]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
merge of '92c36bfdbc6468d1711c043b530e0dfe5abb6dec'
authorUlrich Drepper <drepper@redhat.com>
Tue, 16 Oct 2007 05:21:27 +0000 (05:21 +0000)
committerUlrich Drepper <drepper@redhat.com>
Tue, 16 Oct 2007 05:21:27 +0000 (05:21 +0000)
     and 'c22c8c43f8f68b0bffd4d5ccdb2282c958268742'

41 files changed:
NEWS
backends/ChangeLog
backends/Makefile.am
backends/linux-core-note.c
backends/sparc64_corenote.c [new file with mode: 0644]
backends/sparc_auxv.c [new file with mode: 0644]
backends/sparc_corenote.c [new file with mode: 0644]
backends/sparc_init.c
backends/sparc_symbol.c
libdw/ChangeLog
libdw/dwarf_begin_elf.c
libdw/libdw.h
libdwfl/ChangeLog
libdwfl/derelocate.c
libdwfl/dwfl_module_getdwarf.c
libdwfl/dwfl_module_getsym.c
libdwfl/dwfl_report_elf.c
libdwfl/libdwflP.h
libdwfl/linux-kernel-modules.c
libdwfl/offline.c
libdwfl/relocate.c
libebl/ChangeLog
libebl/eblobjnote.c
libelf/ChangeLog
libelf/elf_begin.c
src/ChangeLog
src/Makefile.am
src/ar.c
src/arlib.c
src/arlib.h
src/arlib2.c
src/elflint.c
src/make-debug-archive.in [new file with mode: 0644]
src/readelf.c
src/unstrip.c
tests/ChangeLog
tests/Makefile.am
tests/dwflmodtest.c
tests/run-dwfl-bug-offline-rel.sh
tests/run-elflint-test.sh
tests/testfile42.bz2 [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index 3120ce504350a25cfb227c6300928194cae2f3de..eb52105a6933a7e4e529663829ff020dc10f1a14 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -2,13 +2,16 @@ Version 0.130:
 
 readelf: -p option can take an argument like -x for one section,
         or no argument (as before) for all SHF_STRINGS sections;
-        new option --archive-index (or -c)
+        new option --archive-index (or -c);
+        improved -n output for core files, on many machines
 
 libelf: new function elf_getdata_rawchunk, replaces gelf_rawchunk;
        new functions gelf_getnote, gelf_getauxv, gelf_update_auxv
 
 readelf, elflint: handle SHT_NOTE sections without requiring phdrs
 
+elflint: stricter checks on debug sections
+
 libdwfl: new functions dwfl_build_id_find_elf, dwfl_build_id_find_debuginfo,
         dwfl_module_build_id, dwfl_module_report_build_id;
         support dynamic symbol tables found via phdrs;
@@ -16,6 +19,8 @@ libdwfl: new functions dwfl_build_id_find_elf, dwfl_build_id_find_debuginfo,
 
 unstrip: new option --list (or -n)
 
+libebl: backend improvements for sparc, alpha, powerpc
+
 Version 0.129:
 
 readelf: new options --hex-dump (or -x), --strings (or -p)
index 9c51f98649d661d0cce31c8f5eeb19cea7055e52..082f4f3907c6cc74d7369b7b4cebf4b94fe65e3f 100644 (file)
@@ -1,3 +1,21 @@
+2007-10-09  Roland McGrath  <roland@redhat.com>
+
+       * sparc_auxv.c: New file.
+       * Makefile.am (sparc_SRCS): Add it.
+       * sparc_init.c (sparc_init): Initialize auxv_info hook.
+
+2007-10-08  Roland McGrath  <roland@redhat.com>
+
+       * linux-core-note.c (TIMEVAL_FIELD): New macro.
+       (prstatus_items): Use it.
+       * sparc_corenote.c: New file.
+       * sparc64_corenote.c: New file.
+       * Makefile.am (sparc_SRCS): Add them.
+       * sparc_init.c (sparc_init): Initialize core_note hook.
+
+       * sparc_symbol.c (sparc_machine_flag_check): New function.
+       * sparc_init.c (sparc_init): Use it.
+
 2007-09-27  Roland McGrath  <roland@redhat.com>
 
        * alpha_retval.c: Use dwarf_attr_integrate and dwarf_hasattr_integrate.
index 84aa47852f1649df2a9c7be215a99f11ac42a559..4174f8e372d6909b6bea0352686d6d9da4090578 100644 (file)
@@ -96,7 +96,8 @@ arm_SRCS = arm_init.c arm_symbol.c
 libebl_arm_pic_a_SOURCES = $(arm_SRCS)
 am_libebl_arm_pic_a_OBJECTS = $(arm_SRCS:.c=.os)
 
-sparc_SRCS = sparc_init.c sparc_symbol.c sparc_regs.c sparc_retval.c
+sparc_SRCS = sparc_init.c sparc_symbol.c sparc_regs.c sparc_retval.c \
+            sparc_corenote.c sparc64_corenote.c sparc_auxv.c
 libebl_sparc_pic_a_SOURCES = $(sparc_SRCS)
 am_libebl_sparc_pic_a_OBJECTS = $(sparc_SRCS:.c=.os)
 
index 0913cc97ba498a0e9635fc18d0a1d4a57784d36c..c4a90b7062d89f49541cc3b3f9a324fe8c2bb0dc 100644 (file)
@@ -53,6 +53,15 @@ struct EBLHOOK(timeval)
   FIELD (ULONG, tv_usec);
 };
 
+/* On sparc64, tv_usec (suseconds_t) is actually 32 bits with 32 bits padding.
+   The 'T'|0x80 value for .format indicates this as a special kludge.  */
+#if SUSECONDS_HALF
+# define TIMEVAL_FIELD(name)   FIELD (time, ULONG, name, 'T'|0x80, .count = 2)
+#else
+# define TIMEVAL_FIELD(name)   FIELD (time, ULONG, name, 'T', .count = 2)
+#endif
+
+
 struct EBLHOOK(prstatus)
 {
   struct EBLHOOK(siginfo) pr_info;
@@ -115,10 +124,10 @@ static const Ebl_Core_Item prstatus_items[] =
     FIELD (identity, PID_T, ppid, 'd'),
     FIELD (identity, PID_T, pgrp, 'd'),
     FIELD (identity, PID_T, sid, 'd'),
-    FIELD (time, ULONG, utime, 'T', .count = 2),
-    FIELD (time, ULONG, stime, 'T', .count = 2),
-    FIELD (time, ULONG, cutime, 'T', .count = 2),
-    FIELD (time, ULONG, cstime, 'T', .count = 2),
+    TIMEVAL_FIELD (utime),
+    TIMEVAL_FIELD (stime),
+    TIMEVAL_FIELD (cutime),
+    TIMEVAL_FIELD (cstime),
 #ifdef PRSTATUS_REGSET_ITEMS
     PRSTATUS_REGSET_ITEMS,
 #endif
diff --git a/backends/sparc64_corenote.c b/backends/sparc64_corenote.c
new file mode 100644 (file)
index 0000000..cef6431
--- /dev/null
@@ -0,0 +1,2 @@
+#define BITS 64
+#include "sparc_corenote.c"
diff --git a/backends/sparc_auxv.c b/backends/sparc_auxv.c
new file mode 100644 (file)
index 0000000..a22b3ce
--- /dev/null
@@ -0,0 +1,43 @@
+/* SPARC-specific auxv handling.
+   Copyright (C) 2007 Red Hat, Inc.
+   This file is part of Red Hat elfutils.
+
+   Red Hat elfutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by the
+   Free Software Foundation; version 2 of the License.
+
+   Red Hat elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along
+   with Red Hat elfutils; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+   Red Hat elfutils is an included package of the Open Invention Network.
+   An included package of the Open Invention Network is a package for which
+   Open Invention Network licensees cross-license their patents.  No patent
+   license is granted, either expressly or impliedly, by designation as an
+   included package.  Should you wish to participate in the Open Invention
+   Network licensing program, please visit www.openinventionnetwork.com
+   <http://www.openinventionnetwork.com>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#define BACKEND sparc_
+#include "libebl_CPU.h"
+
+int
+EBLHOOK(auxv_info) (GElf_Xword a_type, const char **name, const char **format)
+{
+  if (a_type != AT_HWCAP)
+    return 0;
+
+  *name = "HWCAP";
+  *format = "b"
+    "flush\0" "stbar\0" "swap\0" "muldiv\0" "v9\0" "ultra3\0" "v9v\0" "\0";
+  return 1;
+}
diff --git a/backends/sparc_corenote.c b/backends/sparc_corenote.c
new file mode 100644 (file)
index 0000000..55aed8f
--- /dev/null
@@ -0,0 +1,109 @@
+/* PowerPC specific core note handling.
+   Copyright (C) 2007 Red Hat, Inc.
+   This file is part of Red Hat elfutils.
+
+   Red Hat elfutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by the
+   Free Software Foundation; version 2 of the License.
+
+   Red Hat elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along
+   with Red Hat elfutils; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+   Red Hat elfutils is an included package of the Open Invention Network.
+   An included package of the Open Invention Network is a package for which
+   Open Invention Network licensees cross-license their patents.  No patent
+   license is granted, either expressly or impliedly, by designation as an
+   included package.  Should you wish to participate in the Open Invention
+   Network licensing program, please visit www.openinventionnetwork.com
+   <http://www.openinventionnetwork.com>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <elf.h>
+#include <inttypes.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <sys/time.h>
+
+#ifndef BITS
+# define BITS          32
+# define BACKEND       sparc_
+#else
+# define BITS          64
+# define BACKEND       sparc64_
+#endif
+#include "libebl_CPU.h"
+
+#define GR(at, n, dwreg)                                               \
+    { .offset = at * BITS/8, .regno = dwreg, .count = n, .bits = BITS }
+
+static const Ebl_Register_Location prstatus_regs[] =
+  {
+    GR (0, 32, 0),             /* %g0-%g7, %o0-%o7, %i0-%i7 */
+#if BITS == 32
+    GR (32, 1, 65),            /* %psr */
+    GR (33, 2, 68),            /* %pc, %npc */
+    GR (35, 1, 64),            /* %y */
+    GR (36, 1, 66),            /* %wim, %tbr */
+#else
+    GR (32, 1, 82),            /* %state */
+    GR (33, 2, 80),            /* %pc, %npc */
+    GR (35, 1, 85),            /* %y */
+#endif
+  };
+#define PRSTATUS_REGS_SIZE     (BITS / 8 * (32 + (BITS == 32 ? 6 : 4)))
+
+static const Ebl_Register_Location fpregset_regs[] =
+  {
+#if BITS == 32
+    GR (0, 32, 32),            /* %f0-%f31 */
+    /*                                    padding word */
+    GR (33, 1, 70),            /* %fsr */
+    /*                                    qcnt, q_entrysize, en, q, padding */
+# define FPREGSET_SIZE         (34 * 4 + 4 + 64 * 4 + 4)
+#else
+    GR (0, 32, 32),            /* %f0-%f31 */
+    GR (32, 1, 83),            /* %fsr */
+    /*  33, 1,                            %gsr */
+    GR (34, 1, 84),            /* %fprs */
+# define FPREGSET_SIZE         (35 * 8)
+#endif
+  };
+
+#if BITS == 32
+# define ULONG                 uint32_t
+# define ALIGN_ULONG           4
+# define TYPE_ULONG            ELF_T_WORD
+# define TYPE_LONG             ELF_T_SWORD
+# define UID_T                 uint16_t
+# define GID_T                 uint16_t
+# define ALIGN_UID_T           2
+# define ALIGN_GID_T           2
+# define TYPE_UID_T            ELF_T_HALF
+# define TYPE_GID_T            ELF_T_HALF
+#else
+# define ULONG                 uint64_t
+# define ALIGN_ULONG           8
+# define TYPE_ULONG            ELF_T_XWORD
+# define TYPE_LONG             ELF_T_SXWORD
+# define UID_T                 uint32_t
+# define GID_T                 uint32_t
+# define ALIGN_UID_T           4
+# define ALIGN_GID_T           4
+# define TYPE_UID_T            ELF_T_WORD
+# define TYPE_GID_T            ELF_T_WORD
+# define SUSECONDS_HALF                1
+#endif
+#define PID_T                  int32_t
+#define ALIGN_PID_T            4
+#define TYPE_PID_T             ELF_T_SWORD
+
+#include "linux-core-note.c"
index ba0e08a3fb7473a2515ac127c88fdd26b3399e39..8da845e2953a4bb29777a16600380540943c8afc 100644 (file)
@@ -1,5 +1,5 @@
 /* Initialization of SPARC specific backend library.
-   Copyright (C) 2002, 2005, 2006 Red Hat, Inc.
+   Copyright (C) 2002, 2005, 2006, 2007 Red Hat, Inc.
    This file is part of Red Hat elfutils.
 
    Red Hat elfutils is free software; you can redistribute it and/or modify
@@ -34,6 +34,7 @@
 /* This defines the common reloc hooks based on sparc_reloc.def.  */
 #include "common-reloc.c"
 
+extern __typeof (EBLHOOK (core_note)) sparc64_core_note attribute_hidden;
 
 const char *
 sparc_init (elf, machine, eh, ehlen)
@@ -55,7 +56,12 @@ sparc_init (elf, machine, eh, ehlen)
     eh->name = "SPARC";
   sparc_init_reloc (eh);
   HOOK (eh, reloc_simple_type);
-  //HOOK (eh, core_note);
+  HOOK (eh, machine_flag_check);
+  if (eh->class == ELFCLASS64)
+    eh->core_note = sparc64_core_note;
+  else
+    HOOK (eh, core_note);
+  HOOK (eh, auxv_info);
   HOOK (eh, register_info);
   HOOK (eh, return_value_location);
 
index 3a261a00c1c3200df6095444f28b4a39e1829ab4..237620c9195729dea5496c0a731bc973e47d7e61 100644 (file)
@@ -1,5 +1,5 @@
 /* SPARC specific symbolic name handling.
-   Copyright (C) 2002, 2003, 2005 Red Hat, Inc.
+   Copyright (C) 2002, 2003, 2005, 2007 Red Hat, Inc.
    This file is part of Red Hat elfutils.
    Written by Jakub Jelinek <jakub@redhat.com>, 2002.
 
@@ -55,3 +55,14 @@ sparc_reloc_simple_type (Ebl *ebl __attribute__ ((unused)), int type)
       return ELF_T_NUM;
     }
 }
+
+/* Check whether machine flags are valid.  */
+bool
+sparc_machine_flag_check (GElf_Word flags)
+{
+  return ((flags &~ (EF_SPARCV9_MM
+                    | EF_SPARC_LEDATA
+                    | EF_SPARC_32PLUS
+                    | EF_SPARC_SUN_US1
+                    | EF_SPARC_SUN_US3)) == 0);
+}
index 34c4e5b1f5276d40e00a42a921f4bc6e083f4219..d21f5d6483c7b55102ef358b5fb60147b0464ae3 100644 (file)
@@ -1,3 +1,10 @@
+2007-10-05  Roland McGrath  <roland@redhat.com>
+
+       * dwarf_begin_elf.c (check_section): Punt on SHT_NOBITS sections.
+
+       * libdw.h (__extern_inline): Rename to __libdw_extern_inline.
+       [__OPTIMIZE__] (dwarf_whatattr, dwarf_whatform): Update uses.
+
 2007-10-03  Roland McGrath  <roland@redhat.com>
 
        * libdw.map (ELFUTILS_0.130: Add dwfl_build_id_find_elf
index e6ead61416b6addb465884927b10c570cd7eee77..aaac39992b38c997cb81bd043464c4c25b3fe59a 100644 (file)
@@ -97,6 +97,11 @@ check_section (Dwarf *result, GElf_Ehdr *ehdr, Elf_Scn *scn, bool inscngrp)
        wrong in the libelf library.  */
     abort ();
 
+  /* Ignore any SHT_NOBITS sections.  Debugging sections should not
+     have been stripped, but in case of a corrupt file we won't try
+     to look at the missing data.  */
+  if (unlikely (shdr->sh_type == SHT_NOBITS))
+    return result;
 
   /* Make sure the section is part of a section group only iff we
      really need it.  If we are looking for the global (= non-section
index 5385312752f5c18298fb011032c52a6118112167..70a35b0469526b3e63ff1c5d61bd2e4e148e5693 100644 (file)
@@ -62,9 +62,9 @@
 #endif
 
 #ifdef __GNUC_STDC_INLINE__
-# define __extern_inline extern __inline __attribute__ ((__gnu_inline__))
+# define __libdw_extern_inline extern __inline __attribute__ ((__gnu_inline__))
 #else
-# define __extern_inline extern __inline
+# define __libdw_extern_inline extern __inline
 #endif
 
 
@@ -630,14 +630,14 @@ extern Dwarf_OOM dwarf_new_oom_handler (Dwarf *dbg, Dwarf_OOM handler);
 /* Inline optimizations.  */
 #ifdef __OPTIMIZE__
 /* Return attribute code of given attribute.  */
-__extern_inline unsigned int
+__libdw_extern_inline unsigned int
 dwarf_whatattr (Dwarf_Attribute *attr)
 {
   return attr == NULL ? 0 : attr->code;
 }
 
 /* Return attribute code of given attribute.  */
-__extern_inline unsigned int
+__libdw_extern_inline unsigned int
 dwarf_whatform (Dwarf_Attribute *attr)
 {
   return attr == NULL ? 0 : attr->form;
index d682f8f9f44f3805abe1237b638413404fd719b3..3c56f177a58c3836dba6ae9aa1d165d4a9d04c3e 100644 (file)
@@ -1,3 +1,68 @@
+2007-10-09  Roland McGrath  <roland@redhat.com>
+
+       * dwfl_report_elf.c (__libdwfl_report_elf): Clear SHDR->sh_offset when
+       caching SHDR->sh_addr = 0.
+       * offline.c (dwfl_offline_section_address): Never called for sh_addr
+       really at 0, don't check for it.  Use MOD->debug directly, not symfile.
+
+       * dwfl_module_getdwarf.c (load_symtab): Return success properly when
+       we've found SHT_SYMTAB.
+
+       * relocate.c (relocate_getsym): New function.
+       (__libdwfl_relocate): Use it.
+       (__libdwfl_relocate_value): Take new Elf * argument.  Make SYMSHSTRNDX
+       be a pointer instead of value; cache getshstrndx result there.
+       * libdwflP.h: Update decl.
+       * derelocate.c (cache_sections): Update caller.
+       Always work on the main file, not the symfile.
+       (dwfl_module_address_section): Likewise.
+       * dwfl_module_getsym.c (dwfl_module_getsym): Update caller.
+
+2007-10-07  Roland McGrath  <roland@redhat.com>
+
+       * offline.c (process_archive): Initialize MOD.
+
+       * linux-kernel-modules.c (get_release): New function, broken out of ...
+       (report_kernel): ... here.  Call it.
+       (try_kernel_name): Take new arg TRY_DEBUG, only try ".debug" if set.
+       (find_kernel_elf): Update caller.
+       (report_kernel_archive): New function.
+       (dwfl_linux_kernel_report_offline): Call it.
+
+       * offline.c (process_file): Take new arg PREDICATE, pass it down.
+       (process_archive): Likewise.
+       (process_archive_member): Likewise.  When nonnull, let the predicate
+       decide whether to use this member.
+       (__libdwfl_report_offline): New function, broken out of ...
+       (dwfl_report_offline): ... here.  Call it.
+       * libdwflP.h: Declare it.
+
+       * offline.c (process_archive, process_archive_member): New functions.
+       (process_elf, process_file): New functions, broken out of ...
+       (dwfl_report_offline): ... here.  Call process_file, which recurses on
+       ELF_K_AR files.
+
+       * dwfl_report_elf.c (__libdwfl_report_elf): New, broken out of ...
+       (dwfl_report_elf): ... here.  Call it.
+       * libdwflP.h: Declare it.
+
+2007-10-06  Roland McGrath  <roland@redhat.com>
+
+       * derelocate.c (dwfl_module_relocations): Don't call
+       dwfl_module_getdwarf.
+
+       * derelocate.c (find_section): Use __libdwfl_seterrno, not
+       __libdw_seterrno.
+
+       * relocate.c (__libdwfl_relocate_value): Abuse sh_offset, not
+       SHF_ALLOC, to cache sh_addr resolved to 0.
+
+       * dwfl_report_elf.c (dwfl_report_elf): When an ET_REL file has sh_addr
+       values nonzero already, just use its existing layout.
+
+       * relocate.c (__libdwfl_relocate): Clear size of reloc section in its
+       in-core shdr after applying it.
+
 2007-10-04  Ulrich Drepper  <drepper@redhat.com>
 
        * linux-kernel-modules.c (dwfl_linux_kernel_report_kernel): Fake
index cd01a7e80de9026d8817006e6e4bec87a36ccb5f..6da999d31c8a18ecee471149440fc03a74035b29 100644 (file)
@@ -88,46 +88,48 @@ compare_secrefs (const void *a, const void *b)
 static int
 cache_sections (Dwfl_Module *mod)
 {
-  size_t symshstrndx;
-  if (elf_getshstrndx (mod->symfile->elf, &symshstrndx) < 0)
+  struct secref *refs = NULL;
+  size_t nrefs = 0;
+
+  size_t shstrndx;
+  if (unlikely (elf_getshstrndx (mod->main.elf, &shstrndx) < 0))
     {
+    elf_error:
       __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)
+  while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL)
     {
       GElf_Shdr shdr_mem;
       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
       if (shdr == NULL)
-       return -1;
+       goto elf_error;
 
       if ((shdr->sh_flags & SHF_ALLOC) && shdr->sh_addr == 0)
        {
          /* This section might not yet have been looked at.  */
-         if (__libdwfl_relocate_value (mod, symshstrndx, elf_ndxscn (scn),
+         if (__libdwfl_relocate_value (mod, mod->main.elf, &shstrndx,
+                                       elf_ndxscn (scn),
                                        &shdr->sh_addr) != DWFL_E_NOERROR)
            continue;
          shdr = gelf_getshdr (scn, &shdr_mem);
-         if (shdr == NULL)
-           return -1;
+         if (unlikely (shdr == NULL))
+           goto elf_error;
        }
 
       if (shdr->sh_flags & SHF_ALLOC)
        {
-         const char *name = elf_strptr (mod->symfile->elf, symshstrndx,
+         const char *name = elf_strptr (mod->main.elf, shstrndx,
                                         shdr->sh_name);
-         if (name == NULL)
-           return -1;
+         if (unlikely (name == NULL))
+           goto elf_error;
 
          struct secref *newref = alloca (sizeof *newref);
          newref->scn = scn;
          newref->name = name;
-         newref->start = shdr->sh_addr + mod->symfile->bias;
+         newref->start = shdr->sh_addr + mod->main.bias;
          newref->end = newref->start + shdr->sh_size;
          newref->next = refs;
          refs = newref;
@@ -171,13 +173,6 @@ dwfl_module_relocations (Dwfl_Module *mod)
   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:
@@ -295,7 +290,7 @@ find_section (Dwfl_Module *mod, Dwarf_Addr *addr)
        }
     }
 
-  __libdw_seterrno (DWARF_E_NO_MATCH);
+  __libdwfl_seterrno (DWFL_E (LIBDW, DWARF_E_NO_MATCH));
   return -1;
 }
 
@@ -326,6 +321,6 @@ dwfl_module_address_section (Dwfl_Module *mod, Dwarf_Addr *address,
   if (idx < 0)
     return NULL;
 
-  *bias = mod->symfile->bias;
+  *bias = mod->main.bias;
   return mod->reloc_info->refs[idx].scn;
 }
index 90c77c8695c90377335d56589faa8b7e0432d4f8..0f26e5dcc7ed8e822a9d3581f5c1161b4582a8e2 100644 (file)
@@ -205,7 +205,9 @@ find_debuginfo (Dwfl_Module *mod)
 }
 
 
-/* Try to find a symbol table in FILE.  */
+/* Try to find a symbol table in FILE.
+   Returns DWFL_E_NOERROR if a proper one is found.
+   Returns DWFL_E_NO_SYMTAB if not, but still sets results for SHT_DYNSYM.  */
 static Dwfl_Error
 load_symtab (struct dwfl_file *file, struct dwfl_file **symfile,
             Elf_Scn **symscn, Elf_Scn **xndxscn,
@@ -223,7 +225,7 @@ load_symtab (struct dwfl_file *file, struct dwfl_file **symfile,
            *symfile = file;
            *strshndx = shdr->sh_link;
            *syments = shdr->sh_size / shdr->sh_entsize;
-           if (*symscn != NULL && *xndxscn != NULL)
+           if (*xndxscn != NULL)
              return DWFL_E_NOERROR;
            break;
 
@@ -237,12 +239,22 @@ load_symtab (struct dwfl_file *file, struct dwfl_file **symfile,
 
          case SHT_SYMTAB_SHNDX:
            *xndxscn = scn;
+           if (*symscn != NULL)
+             return DWFL_E_NOERROR;
            break;
 
          default:
            break;
          }
     }
+
+  if (*symscn != NULL)
+    /* We found one, though no SHT_SYMTAB_SHNDX to go with it.  */
+    return DWFL_E_NOERROR;
+
+  /* We found no SHT_SYMTAB, so any SHT_SYMTAB_SHNDX was bogus.
+     We might have found an SHT_DYNSYM and set *SYMSCN et al though.  */
+  *xndxscn = NULL;
   return DWFL_E_NO_SYMTAB;
 }
 
index 0c076e87f3b450dcac2dcb53fdfbb40abd106611..04432a4371c71a4754240c99f89c99c41145ec78 100644 (file)
@@ -1,5 +1,5 @@
 /* Find debugging and symbol information for a module in libdwfl.
-   Copyright (C) 2006 Red Hat, Inc.
+   Copyright (C) 2006,2007 Red Hat, Inc.
    This file is part of Red Hat elfutils.
 
    Red Hat elfutils is free software; you can redistribute it and/or modify
@@ -92,11 +92,10 @@ dwfl_module_getsym (Dwfl_Module *mod, int ndx,
        {
          /* In an ET_REL file, the symbol table values are relative
             to the section, not to the module's load base.  */
-         size_t symshstrndx;
-         Dwfl_Error result = DWFL_E_LIBELF;
-         if (elf_getshstrndx (mod->symfile->elf, &symshstrndx) == 0)
-           result = __libdwfl_relocate_value (mod, symshstrndx,
-                                              shndx, &sym->st_value);
+         size_t symshstrndx = SHN_UNDEF;
+         Dwfl_Error result = __libdwfl_relocate_value (mod, mod->symfile->elf,
+                                                       &symshstrndx,
+                                                       shndx, &sym->st_value);
          if (unlikely (result != DWFL_E_NOERROR))
            {
              __libdwfl_seterrno (result);
index 0383538604c2b69fab3c73537ac45a49b87afc0c..905ddd12e306a72b82af8dc8f720921b59ed8039 100644 (file)
@@ -1,5 +1,5 @@
 /* Report a module to libdwfl based on ELF program headers.
-   Copyright (C) 2005 Red Hat, Inc.
+   Copyright (C) 2005, 2007 Red Hat, Inc.
    This file is part of Red Hat elfutils.
 
    Red Hat elfutils is free software; you can redistribute it and/or modify
 #include <fcntl.h>
 #include <unistd.h>
 
-
 Dwfl_Module *
-dwfl_report_elf (Dwfl *dwfl, const char *name,
-                const char *file_name, int fd, GElf_Addr base)
+internal_function
+__libdwfl_report_elf (Dwfl *dwfl, const char *name, const char *file_name,
+                     int fd, Elf *elf, GElf_Addr base)
 {
-  bool closefd = false;
-
-  if (fd < 0)
-    {
-      fd = open64 (file_name, O_RDONLY);
-      if (fd < 0)
-       {
-         __libdwfl_seterrno (DWFL_E_ERRNO);
-         return NULL;
-       }
-      closefd = true;
-    }
-
-  Elf *elf = elf_begin (fd, ELF_C_READ_MMAP_PRIVATE, NULL);
-
   GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (elf, &ehdr_mem);
   if (ehdr == NULL)
     {
     elf_error:
       __libdwfl_seterrno (DWFL_E_LIBELF);
-      if (closefd)
-       close (fd);
       return NULL;
     }
 
@@ -102,23 +85,39 @@ dwfl_report_elf (Dwfl *dwfl, const char *name,
          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;
+             if (shdr->sh_addr == 0 || (bias == 0 && end > start))
+               {
+                 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 (shdr->sh_addr == 0)
+                   /* This is a marker that this was resolved to zero,
+                      to prevent a callback.  */
+                   shdr->sh_offset = 0;
+                 if (! gelf_update_shdr (scn, shdr))
+                   goto elf_error;
+               }
+             else
+               {
+                 if (bias == 0 || end < shdr->sh_addr + shdr->sh_size)
+                   end = shdr->sh_addr + shdr->sh_size;
+                 if (bias == 0 || bias > shdr->sh_addr)
+                   bias = shdr->sh_addr;
+               }
            }
        }
 
-      if (end == start)
+      if (bias != 0)
        {
-         __libdwfl_seterrno (DWFL_E_BADELF);
-         if (closefd)
-           close (fd);
-         return NULL;
+         /* The section headers had nonzero sh_addr values.  The layout
+            was already done.  We've just collected the total span.
+            Now just compute the bias from the requested base.  */
+         start = base;
+         end = end - bias + start;
+         bias -= start;
        }
       break;
 
@@ -161,8 +160,6 @@ dwfl_report_elf (Dwfl *dwfl, const char *name,
       if (end == 0)
        {
          __libdwfl_seterrno (DWFL_E_NO_PHDR);
-         if (closefd)
-           close (fd);
          return NULL;
        }
       break;
@@ -181,8 +178,6 @@ dwfl_report_elf (Dwfl *dwfl, const char *name,
        {
          elf_end (elf);
        overlap:
-         if (closefd)
-           close (fd);
          m->gc = true;
          __libdwfl_seterrno (DWFL_E_OVERLAP);
          m = NULL;
@@ -204,4 +199,33 @@ dwfl_report_elf (Dwfl *dwfl, const char *name,
     }
   return m;
 }
+
+Dwfl_Module *
+dwfl_report_elf (Dwfl *dwfl, const char *name,
+                const char *file_name, int fd, GElf_Addr base)
+{
+  bool closefd = false;
+  if (fd < 0)
+    {
+      closefd = true;
+      fd = open64 (file_name, O_RDONLY);
+      if (fd < 0)
+       {
+         __libdwfl_seterrno (DWFL_E_ERRNO);
+         return NULL;
+       }
+    }
+
+  Elf *elf = elf_begin (fd, ELF_C_READ_MMAP_PRIVATE, NULL);
+  Dwfl_Module *mod = __libdwfl_report_elf (dwfl, name, file_name,
+                                          fd, elf, base);
+  if (mod == NULL)
+    {
+      elf_end (elf);
+      if (closefd)
+       close (fd);
+    }
+
+  return mod;
+}
 INTDEF (dwfl_report_elf)
index 4b458e1dde5225f5c0547845a1fe77090868e05e..e75a3ab6cbb2469ae1549acc8cf31ff57d291b4d 100644 (file)
@@ -237,8 +237,8 @@ extern Dwfl_Error __libdwfl_relocate (Dwfl_Module *mod, Elf *debugfile)
 /* Adjust *VALUE from section-relative to absolute.
    MOD->dwfl->callbacks->section_address is called to determine the actual
    address of a loaded section.  */
-extern Dwfl_Error __libdwfl_relocate_value (Dwfl_Module *mod,
-                                           size_t m_shstrndx,
+extern Dwfl_Error __libdwfl_relocate_value (Dwfl_Module *mod, Elf *elf,
+                                           size_t *shstrndx_cache,
                                            Elf32_Word shndx,
                                            GElf_Addr *value)
      internal_function;
@@ -277,6 +277,21 @@ extern uint32_t __libdwfl_crc32 (uint32_t crc, unsigned char *buf, size_t len)
 extern int __libdwfl_crc32_file (int fd, uint32_t *resp) attribute_hidden;
 
 
+/* Meat of dwfl_report_elf, given elf_begin just called.
+   Consumes ELF on success, not on failure.  */
+extern Dwfl_Module *__libdwfl_report_elf (Dwfl *dwfl, const char *name,
+                                         const char *file_name, int fd,
+                                         Elf *elf, GElf_Addr base)
+  internal_function;
+
+/* Meat of dwfl_report_offline.  */
+extern Dwfl_Module *__libdwfl_report_offline (Dwfl *dwfl, const char *name,
+                                             const char *file_name,
+                                             int fd, bool closefd,
+                                             int (*predicate) (const char *,
+                                                               const char *))
+  internal_function;
+
 
 /* Avoid PLT entries.  */
 INTDECL (dwfl_begin)
index 8954b2fed7aaf0472eb4914641f07a8a2159f918..c15e0896aaa176d70a0b40db4ead01413890d2bf 100644 (file)
@@ -77,7 +77,7 @@
 
 /* Try to open the given file as it is or under the debuginfo directory.  */
 static int
-try_kernel_name (Dwfl *dwfl, char **fname)
+try_kernel_name (Dwfl *dwfl, char **fname, bool try_debug)
 {
   if (*fname == NULL)
     return -1;
@@ -97,7 +97,7 @@ try_kernel_name (Dwfl *dwfl, char **fname)
       fd = INTUSE(dwfl_standard_find_debuginfo) (&fakemod, NULL, NULL, 0,
                                                 *fname, basename (*fname), 0,
                                                 &debugfname);
-      if (fd < 0)
+      if (fd < 0 && try_debug)
        /* Next, let the call use the default of basename + ".debug",
           to look for "vmlinux.debug" files.  */
        fd = INTUSE(dwfl_standard_find_debuginfo) (&fakemod, NULL, NULL, 0,
@@ -128,21 +128,20 @@ find_kernel_elf (Dwfl *dwfl, const char *release, char **fname)
        : asprintf (fname, "/boot/vmlinux-%s", release)) < 0)
     return -1;
 
-  int fd = try_kernel_name (dwfl, fname);
+  int fd = try_kernel_name (dwfl, fname, true);
   if (fd < 0 && release[0] != '/')
     {
       free (*fname);
       if (asprintf (fname, MODULEDIRFMT "/vmlinux", release) < 0)
        return -1;
-      fd = try_kernel_name (dwfl, fname);
+      fd = try_kernel_name (dwfl, fname, true);
     }
 
   return fd;
 }
 
 static int
-report_kernel (Dwfl *dwfl, const char **release,
-              int (*predicate) (const char *module, const char *file))
+get_release (Dwfl *dwfl, const char **release)
 {
   if (dwfl == NULL)
     return -1;
@@ -157,10 +156,20 @@ report_kernel (Dwfl *dwfl, const char **release,
        *release = release_string;
     }
 
+  return 0;
+}
+
+static int
+report_kernel (Dwfl *dwfl, const char **release,
+              int (*predicate) (const char *module, const char *file))
+{
+  int result = get_release (dwfl, release);
+  if (unlikely (result != 0))
+    return result;
+
   char *fname;
-  int fd = find_kernel_elf (dwfl, release_string, &fname);
+  int fd = find_kernel_elf (dwfl, *release, &fname);
 
-  int result = 0;
   if (fd < 0)
     result = ((predicate != NULL && !(*predicate) (KERNEL_MODNAME, NULL))
              ? 0 : errno ?: ENOENT);
@@ -197,6 +206,34 @@ report_kernel (Dwfl *dwfl, const char **release,
   return result;
 }
 
+/* Look for a kernel debug archive.  If we find one, report all its modules.
+   If not, return ENOENT.  */
+static int
+report_kernel_archive (Dwfl *dwfl, const char **release,
+                      int (*predicate) (const char *module, const char *file))
+{
+  int result = get_release (dwfl, release);
+  if (unlikely (result != 0))
+    return result;
+
+  char *archive;
+  if (unlikely ((*release)[0] == '/'
+               ? asprintf (&archive, "%s/debug.a", *release)
+               : asprintf (&archive, MODULEDIRFMT "/debug.a", *release)) < 0)
+    return ENOMEM;
+
+  int fd = try_kernel_name (dwfl, &archive, false);
+  if (fd < 0)
+    result = errno ?: ENOENT;
+  else
+    /* We have the archive file open!  */
+    result = __libdwfl_report_offline (dwfl, NULL, archive, fd, true,
+                                      predicate) == NULL ? -1 : 0;
+
+  free (archive);
+  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/;
@@ -208,8 +245,12 @@ dwfl_linux_kernel_report_offline (Dwfl *dwfl, const char *release,
                                  int (*predicate) (const char *module,
                                                    const char *file))
 {
+  int result = report_kernel_archive (dwfl, &release, predicate);
+  if (result != ENOENT)
+    return result;
+
   /* First report the kernel.  */
-  int result = report_kernel (dwfl, &release, predicate);
+  result = report_kernel (dwfl, &release, predicate);
   if (result == 0)
     {
       /* Do "find /lib/modules/RELEASE -name *.ko".  */
index 0a0645ef3a8ecf18c5ea5b2df006f7f5e36e8e9e..916d263e7384236c887d754929c8fe4456071678 100644 (file)
    <http://www.openinventionnetwork.com>.  */
 
 #include "libdwflP.h"
+#include <fcntl.h>
 #include <unistd.h>
 
 /* Since dwfl_report_elf lays out the sections already, this will only be
    called when the section headers of the debuginfo file are being
-   consulted instead, or for a section located at zero.  With binutils
-   strip-to-debug, the symbol table is in the debuginfo file and relocation
-   looks there.  */
+   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)),
@@ -69,21 +69,13 @@ dwfl_offline_section_address (Dwfl_Module *mod,
   assert (shdr->sh_addr == 0);
   assert (shdr->sh_flags & SHF_ALLOC);
 
-  if (mod->symfile == &mod->main)
-    {
-      /* Because the actual address is zero, we failed to notice
-        we in fact had the right address cached already.  */
-      *addr = 0;
-      return 0;
-    }
-
   /* The section numbers might not match between the two files.
      The best we can rely on is the order of SHF_ALLOC sections.  */
 
-  Elf_Scn *ourscn = elf_getscn (mod->symfile->elf, shndx);
+  Elf_Scn *ourscn = elf_getscn (mod->debug.elf, shndx);
   Elf_Scn *scn = NULL;
   uint_fast32_t skip_alloc = 0;
-  while ((scn = elf_nextscn (mod->symfile->elf, scn)) != ourscn)
+  while ((scn = elf_nextscn (mod->debug.elf, scn)) != ourscn)
     {
       assert (scn != NULL);
       GElf_Shdr shdr_mem;
@@ -98,8 +90,7 @@ dwfl_offline_section_address (Dwfl_Module *mod,
   while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL)
     {
       GElf_Shdr shdr_mem;
-      GElf_Shdr *main_shdr = gelf_getshdr (elf_getscn (mod->main.elf, shndx),
-                                          &shdr_mem);
+      GElf_Shdr *main_shdr = gelf_getshdr (scn, &shdr_mem);
       if (unlikely (main_shdr == NULL))
        return -1;
       if ((main_shdr->sh_flags & SHF_ALLOC) && skip_alloc-- == 0)
@@ -115,15 +106,42 @@ dwfl_offline_section_address (Dwfl_Module *mod,
 }
 INTDEF (dwfl_offline_section_address)
 
-Dwfl_Module *
-dwfl_report_offline (Dwfl *dwfl, const char *name,
-                    const char *file_name, int fd)
+/* Forward declarations.  */
+static Dwfl_Module *process_elf (Dwfl *dwfl, const char *name,
+                                const char *file_name, int fd, Elf *elf);
+static Dwfl_Module *process_archive (Dwfl *dwfl, const char *name,
+                                    const char *file_name, int fd, Elf *elf,
+                                    int (*predicate) (const char *module,
+                                                      const char *file));
+
+/* Report one module for an ELF file, or many for an archive.  */
+static Dwfl_Module *
+process_file (Dwfl *dwfl, const char *name, const char *file_name, int fd,
+             Elf *elf, int (*predicate) (const char *module,
+                                         const char *file))
 {
-  if (dwfl == NULL)
-    return NULL;
+  switch (elf_kind (elf))
+    {
+    default:
+    case ELF_K_NONE:
+      __libdwfl_seterrno (elf == NULL ? DWFL_E_LIBELF : DWFL_E_BADELF);
+      return NULL;
+
+    case ELF_K_ELF:
+      return process_elf (dwfl, name, file_name, fd, elf);
+
+    case ELF_K_AR:
+      return process_archive (dwfl, name, file_name, fd, elf, predicate);
+    }
+}
 
-  Dwfl_Module *mod = INTUSE(dwfl_report_elf) (dwfl, name, file_name, fd,
-                                             dwfl->offline_next_address);
+/* Report the open ELF file as a module.  */
+static Dwfl_Module *
+process_elf (Dwfl *dwfl, const char *name, const char *file_name, int fd,
+            Elf *elf)
+{
+  Dwfl_Module *mod = __libdwfl_report_elf (dwfl, name, file_name, fd, elf,
+                                          dwfl->offline_next_address);
   if (mod != NULL)
     {
       /* If this is an ET_EXEC file with fixed addresses, the address range
@@ -147,4 +165,139 @@ dwfl_report_offline (Dwfl *dwfl, const char *name,
 
   return mod;
 }
+
+static bool
+process_archive_member (Dwfl *dwfl, const char *name, const char *file_name,
+                       int (*predicate) (const char *module, const char *file),
+                       Elf *member, Dwfl_Module **mod)
+{
+  const Elf_Arhdr *h = elf_getarhdr (member);
+  if (unlikely (h == NULL))
+    {
+      __libdwfl_seterrno (DWFL_E_LIBELF);
+      elf_end (member);
+      *mod = NULL;
+      return false;
+    }
+
+  if (!strcmp (h->ar_name, "/") || !strcmp (h->ar_name, "//"))
+    {
+      elf_end (member);
+      return true;
+    }
+
+  char *member_name;
+  if (unlikely (asprintf (&member_name, "%s(%s)", file_name, h->ar_name) < 0))
+    {
+    nomem:
+      __libdwfl_seterrno (DWFL_E_NOMEM);
+      elf_end (member);
+      *mod = NULL;
+      return false;
+    }
+
+  char *module_name = NULL;
+  if (name == NULL || name[0] == '\0')
+    name = h->ar_name;
+  else if (unlikely (asprintf (&module_name, "%s:%s", name, h->ar_name) < 0))
+    {
+      free (member_name);
+      goto nomem;
+    }
+  else
+    name = module_name;
+
+  if (predicate != NULL)
+    {
+      /* Let the predicate decide whether to use this one.  */
+      int want = (*predicate) (name, member_name);
+      if (want <= 0)
+       {
+         free (member_name);
+         free (module_name);
+         if (unlikely (want < 0))
+           {
+             __libdwfl_seterrno (DWFL_E_CB);
+             elf_end (member);
+             *mod = NULL;
+             return false;
+           }
+         return true;
+       }
+    }
+
+  *mod = process_file (dwfl, name, member_name, -1, member, predicate);
+  free (member_name);
+  free (module_name);
+  return *mod != NULL;
+}
+
+/* Report each member of the archive as its own module.  */
+static Dwfl_Module *
+process_archive (Dwfl *dwfl, const char *name, const char *file_name, int fd,
+                Elf *archive,
+                int (*predicate) (const char *module, const char *file))
+
+{
+  Dwfl_Module *mod = NULL;
+  bool more = true;
+  do
+    {
+      Elf *member = elf_begin (-1, ELF_C_READ_MMAP_PRIVATE, archive);
+      if (process_archive_member (dwfl, name, file_name, predicate,
+                                 member, &mod))
+       /* Advance the archive-reading offset for the next iteration.  */
+       more = elf_next (member) != ELF_C_NULL;
+      else if (mod == NULL)
+       {
+         elf_end (member);
+         break;
+       }
+    }
+  while (more);
+  elf_end (archive);
+  if (likely (mod != NULL))
+    close (fd);
+  return mod;
+}
+
+Dwfl_Module *
+internal_function
+__libdwfl_report_offline (Dwfl *dwfl, const char *name,
+                         const char *file_name, int fd, bool closefd,
+                         int (*predicate) (const char *module,
+                                           const char *file))
+{
+  Elf *elf = elf_begin (fd, ELF_C_READ_MMAP_PRIVATE, NULL);
+  Dwfl_Module *mod = process_file (dwfl, name, file_name, fd, elf, predicate);
+  if (mod == NULL)
+    {
+      elf_end (elf);
+      if (closefd)
+       close (fd);
+    }
+  return mod;
+}
+
+Dwfl_Module *
+dwfl_report_offline (Dwfl *dwfl, const char *name,
+                    const char *file_name, int fd)
+{
+  if (dwfl == NULL)
+    return NULL;
+
+  bool closefd = false;
+  if (fd < 0)
+    {
+      closefd = true;
+      fd = open64 (file_name, O_RDONLY);
+      if (fd < 0)
+       {
+         __libdwfl_seterrno (DWFL_E_ERRNO);
+         return NULL;
+       }
+    }
+
+  return __libdwfl_report_offline (dwfl, name, file_name, fd, closefd, NULL);
+}
 INTDEF (dwfl_report_offline)
index f37f83509e6491282bfd51a5f92580d15032db98..e355af0c1637f9adc12790dc3b92ca5c63f94276 100644 (file)
@@ -56,21 +56,27 @@ typedef uint8_t GElf_Byte;
 
 Dwfl_Error
 internal_function
-__libdwfl_relocate_value (Dwfl_Module *mod, size_t symshstrndx,
+__libdwfl_relocate_value (Dwfl_Module *mod, Elf *elf, size_t *shstrndx,
                          Elf32_Word shndx, GElf_Addr *value)
 {
-  Elf_Scn *refscn = elf_getscn (mod->symfile->elf, shndx);
+  Elf_Scn *refscn = elf_getscn (elf, shndx);
   GElf_Shdr refshdr_mem, *refshdr = gelf_getshdr (refscn, &refshdr_mem);
   if (refshdr == NULL)
     return DWFL_E_LIBELF;
 
-  if ((refshdr->sh_flags & SHF_ALLOC) && refshdr->sh_addr == 0)
+  if (refshdr->sh_addr == 0
+      && (refshdr->sh_flags & SHF_ALLOC)
+      && refshdr->sh_offset != 0)
     {
       /* This is a loaded section.  Find its actual
         address and update the section header.  */
-      const char *name = elf_strptr (mod->symfile->elf, symshstrndx,
-                                    refshdr->sh_name);
-      if (name == NULL)
+
+      if (*shstrndx == SHN_UNDEF
+         && unlikely (elf_getshstrndx (elf, shstrndx) < 0))
+       return DWFL_E_LIBELF;
+
+      const char *name = elf_strptr (elf, *shstrndx, refshdr->sh_name);
+      if (unlikely (name == NULL))
        return DWFL_E_LIBELF;
 
       if ((*mod->dwfl->callbacks->section_address) (MODCB_ARGS (mod),
@@ -79,18 +85,17 @@ __libdwfl_relocate_value (Dwfl_Module *mod, size_t symshstrndx,
        return CBFAIL;
 
       if (refshdr->sh_addr == (Dwarf_Addr) -1l)
-       {
-         /* The callback indicated this section wasn't really loaded but we
-            don't really care.  Mark it so we don't check it again for the
-            next relocation.  */
-         refshdr->sh_flags &= ~SHF_ALLOC;
-         refshdr->sh_addr = 0; /* Make no adjustment below.  */
-       }
+       /* The callback indicated this section wasn't really loaded but we
+          don't really care.  */
+       refshdr->sh_addr = 0;   /* Make no adjustment below.  */
+
+      /* Mark it so we don't check it again for the next relocation.  */
+      refshdr->sh_offset = 0;
 
       /* Update the in-core file's section header to show the final
         load address (or unloadedness).  This serves as a cache,
         so we won't get here again for the same section.  */
-      if (! gelf_update_shdr (refscn, refshdr))
+      if (unlikely (! gelf_update_shdr (refscn, refshdr)))
        return DWFL_E_LIBELF;
     }
 
@@ -99,6 +104,79 @@ __libdwfl_relocate_value (Dwfl_Module *mod, size_t symshstrndx,
   return DWFL_E_NOERROR;
 }
 
+/* This is just doing dwfl_module_getsym, except that we must always use
+   the symbol table in RELOCATED itself when it has one, not MOD->symfile.  */
+static Dwfl_Error
+relocate_getsym (Elf **symelf, Elf_Data **symdata, Elf_Data **symxndxdata,
+                size_t *symshstrndx,
+                Dwfl_Module *mod, Elf *relocated,
+                int symndx, GElf_Sym *sym, GElf_Word *shndx)
+{
+  if (*symdata == NULL)
+    {
+      if (mod->symfile->elf != relocated)
+       {
+         /* We have to look up the symbol table in the file we are
+            relocating, if it has its own.  These reloc sections refer to
+            the symbol table in this file, and a symbol table in the main
+            file might not match.  However, some tools did produce ET_REL
+            .debug files with relocs but no symtab of their own.  */
+         Elf_Scn *scn = NULL;
+         while ((scn = elf_nextscn (relocated, scn)) != NULL)
+           {
+             GElf_Shdr shdr_mem, *shdr = gelf_getshdr (scn, &shdr_mem);
+             if (shdr != NULL)
+               switch (shdr->sh_type)
+                 {
+                 default:
+                   continue;
+                 case SHT_SYMTAB:
+                   *symelf = relocated;
+                   *symdata = elf_getdata (scn, NULL);
+                   if (unlikely (*symdata == NULL))
+                     return DWFL_E_LIBELF;
+                   break;
+                 case SHT_SYMTAB_SHNDX:
+                   *symxndxdata = elf_getdata (scn, NULL);
+                   if (unlikely (*symxndxdata == NULL))
+                     return DWFL_E_LIBELF;
+                   break;
+                 }
+             if (*symdata != NULL && *symxndxdata != NULL)
+               break;
+           }
+       }
+      if (*symdata == NULL)
+       {
+         /* The symbol table we have already cached is the one from
+            the file being relocated, so it's what we need.  Or else
+            this is an ET_REL .debug file with no .symtab of its own;
+            the symbols refer to the section indices in the main file.  */
+         *symelf = mod->symfile->elf;
+         *symdata = mod->symdata;
+         *symxndxdata = mod->symxndxdata;
+       }
+    }
+
+  if (unlikely (gelf_getsymshndx (*symdata, *symxndxdata,
+                                 symndx, sym, shndx) == NULL))
+    return DWFL_E_LIBELF;
+
+  if (sym->st_shndx != SHN_XINDEX)
+    *shndx = sym->st_shndx;
+
+  switch (*shndx)
+    {
+    case SHN_ABS:
+    case SHN_UNDEF:
+    case SHN_COMMON:
+      return DWFL_E_NOERROR;
+    }
+
+  return __libdwfl_relocate_value (mod, *symelf, symshstrndx,
+                                  *shndx, &sym->st_value);
+}
+
 Dwfl_Error
 internal_function
 __libdwfl_relocate (Dwfl_Module *mod, Elf *debugfile)
@@ -110,13 +188,17 @@ __libdwfl_relocate (Dwfl_Module *mod, Elf *debugfile)
   if (ehdr == NULL)
     return DWFL_E_LIBELF;
 
-  size_t symshstrndx, d_shstrndx;
-  if (elf_getshstrndx (mod->symfile->elf, &symshstrndx) < 0)
+  /* Cache used by relocate_getsym.  */
+  Elf *reloc_symelf = NULL;
+  Elf_Data *reloc_symdata = NULL;
+  Elf_Data *reloc_symxndxdata = NULL;
+  size_t reloc_symshstrndx = SHN_UNDEF;
+
+  size_t d_shstrndx;
+  if (elf_getshstrndx (debugfile, &d_shstrndx) < 0)
     return DWFL_E_LIBELF;
   if (mod->symfile->elf == debugfile)
-    d_shstrndx = symshstrndx;
-  else if (elf_getshstrndx (debugfile, &d_shstrndx) < 0)
-    return DWFL_E_LIBELF;
+    reloc_symshstrndx = d_shstrndx;
 
   /* Look at each section in the debuginfo file, and process the
      relocation sections for debugging sections.  */
@@ -127,7 +209,8 @@ __libdwfl_relocate (Dwfl_Module *mod, Elf *debugfile)
       GElf_Shdr shdr_mem;
       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
 
-      if (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA)
+      if ((shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA)
+         && shdr->sh_size != 0)
        {
          /* It's a relocation section.  First, fetch the name of the
             section these relocations apply to.  */
@@ -172,10 +255,14 @@ __libdwfl_relocate (Dwfl_Module *mod, Elf *debugfile)
                {
                  GElf_Sym sym;
                  GElf_Word shndx;
-
-                 if (INTUSE(dwfl_module_getsym) (mod, symndx,
-                                                 &sym, &shndx) == NULL)
-                   return dwfl_errno ();
+                 Dwfl_Error error = relocate_getsym (&reloc_symelf,
+                                                     &reloc_symdata,
+                                                     &reloc_symxndxdata,
+                                                     &reloc_symshstrndx,
+                                                     mod, debugfile,
+                                                     symndx, &sym, &shndx);
+                 if (unlikely (error != DWFL_E_NOERROR))
+                   return error;
 
                  if (shndx == SHN_UNDEF || shndx == SHN_COMMON)
                    return DWFL_E_RELUNDEF;
@@ -307,6 +394,14 @@ __libdwfl_relocate (Dwfl_Module *mod, Elf *debugfile)
              }
          if (result != DWFL_E_NOERROR)
            break;
+
+         /* Mark this relocation section as being empty now that we have
+            done its work.  This affects unstrip -R, so e.g. it emits an
+            empty .rela.debug_info along with a .debug_info that has
+            already been fully relocated.  */
+         shdr->sh_size = 0;
+         reldata->d_size = 0;
+         gelf_update_shdr (scn, shdr);
        }
     }
 
index c93e70474e1c8d3ad6638b274b62c71f75fa6fdb..ae31b8f273c51424b230016d17b83c431b8477f0 100644 (file)
@@ -1,3 +1,8 @@
+2007-10-11  Roland McGrath  <roland@redhat.com>
+
+       * eblobjnote.c (ebl_object_note): Translate target format (byte-swap)
+       for NT_GNU_ABI_TAG contents.
+
 2007-08-22  Roland McGrath  <roland@redhat.com>
 
        * libebl.h (Ebl_Core_Item): New member `group'.
index 747fb8e7bfc705d660c00a51f3421a054896811b..836ac8dce780d15717f5952d9294fb5f824331bf 100644 (file)
@@ -81,48 +81,60 @@ ebl_object_note (ebl, name, type, descsz, desc)
          }
        break;
 
-      case NT_VERSION:
-       if (strcmp (name, "GNU") == 0 && descsz >= 8)
+      case NT_GNU_ABI_TAG:
+       if (strcmp (name, "GNU") == 0 && descsz >= 8 && descsz % 4 == 0)
          {
-           struct
-           {
-             uint32_t os;
-             uint32_t version[descsz / 4 - 1];
-           } *tag = (__typeof (tag)) desc;
-
-           const char *os;
-           switch (tag->os)
+           Elf_Data in =
              {
-             case ELF_NOTE_OS_LINUX:
-               os = "Linux";
-               break;
-
-             case ELF_NOTE_OS_GNU:
-               os = "GNU";
-               break;
-
-             case ELF_NOTE_OS_SOLARIS2:
-               os = "Solaris";
-               break;
-
-             case ELF_NOTE_OS_FREEBSD:
-               os = "FreeBSD";
-               break;
-
-             default:
-               os = "???";
-               break;
-             }
+               .d_version = EV_CURRENT,
+               .d_type = ELF_T_WORD,
+               .d_size = descsz,
+               .d_buf = (void *) desc
+             };
+           uint32_t buf[descsz / 4];
+           Elf_Data out =
+             {
+               .d_version = EV_CURRENT,
+               .d_type = ELF_T_WORD,
+               .d_size = descsz,
+               .d_buf = buf
+             };
 
-           printf (gettext ("    OS: %s, ABI: "), os);
-           size_t cnt;
-           for (cnt = 0; cnt < descsz / 4 - 1; ++cnt)
+           if (elf32_xlatetom (&out, &in, ebl->data) != NULL)
              {
-               if (cnt != 0)
-                 putchar_unlocked ('.');
-               printf ("%" PRIu32, tag->version[cnt]);
+               const char *os;
+               switch (buf[0])
+                 {
+                 case ELF_NOTE_OS_LINUX:
+                   os = "Linux";
+                   break;
+
+                 case ELF_NOTE_OS_GNU:
+                   os = "GNU";
+                   break;
+
+                 case ELF_NOTE_OS_SOLARIS2:
+                   os = "Solaris";
+                   break;
+
+                 case ELF_NOTE_OS_FREEBSD:
+                   os = "FreeBSD";
+                   break;
+
+                 default:
+                   os = "???";
+                   break;
+                 }
+
+               printf (gettext ("    OS: %s, ABI: "), os);
+               for (size_t cnt = 1; cnt < descsz / 4; ++cnt)
+                 {
+                   if (cnt > 1)
+                     putchar_unlocked ('.');
+                   printf ("%" PRIu32, buf[cnt]);
+                 }
+               putchar_unlocked ('\n');
              }
-           putchar_unlocked ('\n');
            break;
          }
        /* FALLTHROUGH */
index 1532a4cf1e9b843f81a71b21882fcdbc03575e00..247598c7b89fa1309ad5446b5fef10c788f88a32 100644 (file)
@@ -1,3 +1,9 @@
+2007-10-07  Roland McGrath  <roland@redhat.com>
+
+       * elf_begin.c (__libelf_next_arhdr): Fix fencepost error and wrong
+       member access in terminating name with no trailing /.  Trim trailing
+       spaces when there is no /.
+
 2007-10-04  Roland McGrath  <roland@redhat.com>
 
        * elf_end.c (elf_end): Don't free ELF->state.ar.ar_sym when it's -1l.
index b68410be2417a469a0499a9ff12532c9db266a6b..13f965f7c978358e790fcf7d5abb1988c8a1c206 100644 (file)
@@ -812,7 +812,14 @@ __libelf_next_arhdr (elf)
       if (endp != NULL)
        endp[-1] = '\0';
       else
-       elf->state.ar.raw_name[16] = '\0';
+       {
+         /* In the old BSD style of archive, there is no / terminator.
+            Instead, there is space padding at the end of the name.  */
+         size_t i = 15;
+         do
+           elf->state.ar.ar_name[i] = '\0';
+         while (i > 0 && elf->state.ar.ar_name[--i] == ' ');
+       }
 
       elf_ar_hdr->ar_name = elf->state.ar.ar_name;
     }
index 4d4fa9aab2226fe19567ff30c7266dcb6c13e708..ebd729fec6acb5d5fcaa41d5156f6daed5267350 100644 (file)
@@ -1,3 +1,114 @@
+2007-10-15  Roland McGrath  <roland@redhat.com>
+
+       * make-debug-archive.in: New file.
+       * Makefile.am (EXTRA_DIST): Add it.
+       (make-debug-archive): New target.
+       (bin_SCRIPTS, CLEANFILES): Add it.
+
+2007-10-10  Roland McGrath  <roland@redhat.com>
+
+       * elflint.c (special_sections): Add new attrflag value exact_or_gnuld.
+       Use it to check MERGE|STRINGS for .debug_str.
+       (check_sections): Handle exact_or_gnuld.
+
+2007-10-08  Roland McGrath  <roland@redhat.com>
+
+       * readelf.c (handle_core_item): Handle 'T'|0x80 to indicate
+       64-bit struct timeval with 32-bit tv_usec.
+
+2007-10-07  Roland McGrath  <roland@redhat.com>
+
+       * readelf.c (check_archive_index): New function.
+       (process_file): Call it.  Change signature to take only fd and name.
+       Use libdwfl to open the file, then iterate on its modules (multiple
+       for an archive) to print file name and call process_elf_file.
+       (main): Update caller.  Let process_file do elf_begin.
+       (count_dwflmod, process_dwflmod, find_no_debuginfo): New functions.
+       (process_elf_file): Take only Dwfl_Module * argument.
+       Don't print the file name here.
+       (print_debug_*_section): Take Dwfl_Module * argument.
+       (print_debug): Likewise.  Update caller.
+       (format_dwarf_addr): New function.
+       (print_debug_ranges_section): Use it.
+       (attr_callback): Likewise.
+       (print_debug_line_section, print_debug_loc_section): Likewise.
+
+       * readelf.c (print_debug_ranges_section): Translate all strings.
+       (print_debug_loc_section): Likewise.
+
+       * unstrip.c (copy_elided_sections): Initialize SEC.
+
+       * ar.c (do_oper_insert): Put trailing / on short names.
+
+       * arlib.h (MAX_AR_NAME_LEN): Decrease by one.
+
+       * arlib2.c (arlib_add_long_name): Adjust for header size.
+
+       * arlib.c (arlib_finalize): Pad long name table to keep size even.
+
+       * ar.c (do_oper_insert): Use write_retry for padding write.
+
+       * ar.c (do_oper_insert): Initialize CUR_OFF in no_old case.
+       Unconditionally set FOUND[CNT]->elf when setting ->mem.
+       (remember_long_name): New function.
+       (do_oper_insert): Call it.  Correctly use length of basename,
+       not original name.  Don't store long name twice for new member.
+
+2007-10-06  Roland McGrath  <roland@redhat.com>
+
+       * elflint.c (check_note): Skip empty segment.
+       (check_note_section): Skip empty section.
+
+       * unstrip.c (options, parse_opt, struct arg_info): Grok -R/--relocate.
+       (handle_output_dir_module, handle_implicit_modules): Pass it down.
+       (handle_dwfl_module): When set, use ET_REL already loaded by Dwfl.
+       (compare_alloc_sections): Take new arg REL, ignore address if true.
+       (compare_sections): Likewise, pass it down.
+       (compare_sections_rel, compare_sections_nonrel): New functions.
+       (find_alloc_sections_prelink, copy_elided_sections): Use them
+       instead of compare_sections.
+       (sections_match): New function, broken out of ...
+       (find_alloc_section): ... here.
+       (copy_elided_sections): Reorganize section match-up logic.
+       Use sections_match for SHF_ALLOC in ET_REL.
+       For ET_REL, let the nonzero sh_addr from the debug file dominate.
+
+       * unstrip.c (add_new_section_symbols): Take new arg REL.
+       When true, do not update section symbol values.
+       (collect_symbols): Likewise.  Update section symbols with address
+       of chosen output section, not original section.
+       (check_symtab_section_symbols, copy_elided_sections): Update callers.
+
+       * unstrip.c (compare_alloc_sections): At the same address, preserve
+       original section order.
+
+       * elflint.c (special_sections): Don't require MERGE|STRINGS for
+       .debug_str, it didn't always have them with older tools.
+
+       * elflint.c (check_symtab, check_one_reloc): Ignore sh_addr in ET_REL.
+
+2007-10-05  Roland McGrath  <roland@redhat.com>
+
+       * elflint.c (check_symtab): Allow SHN_UNDEF _GLOBAL_OFFSET_TABLE_ in
+       ET_REL file.
+
+       * elflint.c (check_symtab): For _GLOBAL_OFFSET_TABLE_, diagnose
+       SHN_UNDEF as "bad section".  Use shndx value in messages.
+
+       * elflint.c (special_sections): Add ".debug_str".  Decrement namelen
+       for ".debug" so it matches as a prefix.
+       (IS_KNOWN_SPECIAL): New macro.
+       (check_sections): Use it for ".plt" match.  Cite wrong SHT_NOBITS
+       type even under -d, for a .debug* or .shstrtab section.
+
+       * readelf.c (print_ops): Use hex for address operand.
+
+2007-10-04  Roland McGrath  <roland@redhat.com>
+
+       * unstrip.c (copy_elided_sections): Initialize NDX_SECTION element for
+       .gnu_debuglink section to SHN_UNDEF.  Drop STT_SECTION symbols for
+       sections mapped to SHN_UNDEF.
+
 2007-10-04  Ulrich Drepper  <drepper@redhat.com>
 
        * readelf.c (dump_archive_index): Avoid warning about uninitialized
index 6444cd131891714d2d9cbc9b4ba65e9dd9b033cf..138be5a321c55ac762a348fdb0694fcbafd6471f 100644 (file)
@@ -84,6 +84,10 @@ noinst_HEADERS = ld.h symbolhash.h sectionhash.h versionhash.h \
 EXTRA_DIST = elf32-i386.script libld_elf_i386.map $(ld_modules) arlib.h
 ld_modules = i386_ld.c
 
+bin_SCRIPTS = make-debug-archive
+EXTRA_DIST += make-debug-archive.in
+CLEANFILES = make-debug-archive
+
 if MUDFLAP
 libmudflap = -lmudflap
 endif
@@ -176,6 +180,17 @@ installcheck-binPROGRAMS: $(bin_PROGRAMS)
          done; \
        done; rm -f c$${pid}_.???; exit $$bad
 
-CLEANFILES = none_ld.os $(ld_modules:.c=.os) *.gcno *.gcda *.gconv
+CLEANFILES += none_ld.os $(ld_modules:.c=.os) *.gcno *.gcda *.gconv
 
 MAINTAINERCLEANFILES = ldlex.c ldscript.c ldscript.h
+
+
+make-debug-archive: $(srcdir)/make-debug-archive.in
+       UNSTRIP=$(bindir)/`echo unstrip | sed '$(transform)'`; \
+       AR=$(bindir)/`echo ar | sed '$(transform)'`; \
+       sed -e "s,@UNSTRIP@,$$UNSTRIP,g" -e "s,@AR@,$$AR,g" \
+           -e "s%[@]PACKAGE_NAME[@]%$(PACKAGE_NAME)%g" \
+           -e "s%[@]PACKAGE_VERSION[@]%$(PACKAGE_VERSION)%g" \
+           $(srcdir)/make-debug-archive.in > $@.new
+       chmod +x $@.new
+       mv -f $@.new $@
index e8ce95511e19c70963c860fdd9549bd971afa551..a9102a55045a74667c6aac388186228403008a40 100644 (file)
--- a/src/ar.c
+++ b/src/ar.c
@@ -884,6 +884,15 @@ write_member (struct armem *memb, off_t *startp, off_t *lenp, Elf *elf,
   return 0;
 }
 
+/* Store the name in the long name table if necessary.
+   Record its offset or -1 if we did not need to use the table.  */
+static void
+remember_long_name (struct armem *mem, const char *name, size_t namelen)
+{
+  mem->long_name_off = (namelen > MAX_AR_NAME_LEN
+                       ? arlib_add_long_name (name, namelen)
+                       : -1l);
+}
 
 static int
 do_oper_delete (const char *arfname, char **argv, int argc,
@@ -963,12 +972,7 @@ do_oper_delete (const char *arfname, char **argv, int argc,
          arlib_add_symbols (subelf, arfname, arhdr->ar_name, newp->off);
 
          /* Remember long file names.  */
-         size_t ar_namelen = strlen (arhdr->ar_name);
-         if (ar_namelen > MAX_AR_NAME_LEN)
-           newp->long_name_off = arlib_add_long_name (arhdr->ar_name,
-                                                      ar_namelen);
-         else
-           newp->long_name_off = -1l;
+         remember_long_name (newp, arhdr->ar_name, strlen (arhdr->ar_name));
        }
 
     next:
@@ -1087,6 +1091,9 @@ do_oper_insert (int oper, const char *arfname, char **argv, int argc,
 
   arlib_init ();
 
+  /* Initialize early for no_old case.  */
+  off_t cur_off = SARMAG;
+
   if (fd == -1)
     {
       if (!suppress_create_msg)
@@ -1118,7 +1125,6 @@ do_oper_insert (int oper, const char *arfname, char **argv, int argc,
   /* While iterating over the current content of the archive we must
      determine a number of things: which archive members to keep,
      which are replaced, and where to insert the new members.  */
-  off_t cur_off = SARMAG;
   Elf_Cmd cmd = ELF_C_READ_MMAP;
   Elf *subelf;
   while ((subelf = elf_begin (fd, cmd, elf)) != NULL)
@@ -1137,11 +1143,7 @@ do_oper_insert (int oper, const char *arfname, char **argv, int argc,
       newp->mem = NULL;
 
       /* Remember long file names.  */
-      size_t ar_namelen = strlen (arhdr->ar_name);
-      if (ar_namelen > MAX_AR_NAME_LEN)
-       newp->long_name_off = arlib_add_long_name (arhdr->ar_name, ar_namelen);
-      else
-       newp->long_name_off = -1l;
+      remember_long_name (newp, arhdr->ar_name, strlen (arhdr->ar_name));
 
       /* Check whether this is a file we are looking for.  */
       if (oper != oper_qappend)
@@ -1223,17 +1225,13 @@ do_oper_insert (int oper, const char *arfname, char **argv, int argc,
       for (int cnt = 0; cnt < argc; ++cnt)
        {
          const char *bname = basename (argv[cnt]);
+         size_t bnamelen = strlen (bname);
          if (found[cnt] == NULL)
            {
              found[cnt] = alloca (sizeof (struct armem));
              found[cnt]->old_off = -1;
 
-             size_t ar_namelen = strlen (argv[cnt]);
-             if (ar_namelen > MAX_AR_NAME_LEN)
-               found[cnt]->long_name_off = arlib_add_long_name (bname,
-                                                                ar_namelen);
-             else
-               found[cnt]->long_name_off = -1l;
+             remember_long_name (found[cnt], bname, bnamelen);
            }
 
          struct stat newst;
@@ -1275,14 +1273,12 @@ do_oper_insert (int oper, const char *arfname, char **argv, int argc,
                printf ("%c - %s\n",
                        found[cnt]->old_off == -1l ? 'a' : 'r', argv[cnt]);
 
-#ifdef DEBUG
              found[cnt]->elf = newelf;
-#endif
              found[cnt]->sec = newst.st_mtime;
              found[cnt]->uid = newst.st_uid;
              found[cnt]->gid = newst.st_gid;
              found[cnt]->mode = newst.st_mode;
-             found[cnt]->name = basename (argv[cnt]);
+             found[cnt]->name = bname;
 
              found[cnt]->mem = elf_rawfile (newelf, &found[cnt]->size);
              if (found[cnt] == NULL || elf_cntl (newelf, ELF_C_FDDONE) != 0)
@@ -1291,13 +1287,9 @@ do_oper_insert (int oper, const char *arfname, char **argv, int argc,
 
              close (newfd);
 
-             /* Remember long file names.  */
-             size_t bnamelen = strlen (bname);
-             if (bnamelen > MAX_AR_NAME_LEN)
-               found[cnt]->long_name_off = arlib_add_long_name (bname,
-                                                                bnamelen);
-             else
-               found[cnt]->long_name_off = -1l;
+             if (found[cnt]->old_off != -1l)
+               /* Remember long file names.  */
+               remember_long_name (found[cnt], bname, bnamelen);
            }
        }
     }
@@ -1449,8 +1441,9 @@ do_oper_insert (int oper, const char *arfname, char **argv, int argc,
              if (all->long_name_off == -1)
                {
                  size_t namelen = strlen (all->name);
-                 memset (mempcpy (arhdr.ar_name, all->name, namelen),
-                         ' ', sizeof (arhdr.ar_name) - namelen);
+                 char *p = mempcpy (arhdr.ar_name, all->name, namelen);
+                 *p++ = '/';
+                 memset (p, ' ', sizeof (arhdr.ar_name) - namelen - 1);
                }
              else
                {
@@ -1480,7 +1473,7 @@ do_oper_insert (int oper, const char *arfname, char **argv, int argc,
 
              /* Pad the file if its size is odd.  */
              if ((all->size & 1) != 0)
-               if (write (newfd, "\n", 1) != 1)
+               if (unlikely (write_retry (newfd, "\n", 1) != 1))
                  goto nonew_unlink;
            }
          else
index 1b8785e469ab0ae615b165a5486c324b37422d56..af98454c685f0bc50a17d89d2ced400c76ed6683 100644 (file)
@@ -118,6 +118,13 @@ arlib_finalize (void)
   symtab.longnameslen = obstack_object_size (&symtab.longnamesob);
   if (symtab.longnameslen != sizeof (struct ar_hdr))
     {
+      if ((symtab.longnameslen & 1) != 0)
+       {
+         /* Add one more byte to make length even.  */
+         obstack_grow (&symtab.longnamesob, "\n", 1);
+         ++symtab.longnameslen;
+       }
+
       symtab.longnames = obstack_finish (&symtab.longnamesob);
 
       memcpy (&((struct ar_hdr *) symtab.longnames)->ar_size, tmpbuf,
index af8e8e428ee9bd7b69c62ab396141bf68cc414ec..fd26d248843c584b5b9610393d4ac8990a96f782 100644 (file)
@@ -35,8 +35,9 @@
 #include <sys/types.h>
 
 
-/* Maximum length of a file name that fits directly into the ar header.  */
-#define MAX_AR_NAME_LEN (sizeof (((struct ar_hdr *) NULL)->ar_name))
+/* Maximum length of a file name that fits directly into the ar header.
+   We cannot use the final byte since a / goes there.  */
+#define MAX_AR_NAME_LEN (sizeof (((struct ar_hdr *) NULL)->ar_name) - 1)
 
 
 /* Words matching in size to archive header.  */
index 47edb3563db7ecc81a601a12ff8f9a32eb3ff8e1..7098fec1e16284769a01e3b327c15c437432afb4 100644 (file)
 long int
 arlib_add_long_name (const char *filename, size_t filenamelen)
 {
-  int retval = obstack_object_size (&symtab.longnamesob);
+  size_t size = obstack_object_size (&symtab.longnamesob);
 
   obstack_grow (&symtab.longnamesob, filename, filenamelen);
   obstack_grow (&symtab.longnamesob, "/\n", 2);
 
-  return retval;
+  return size - sizeof (struct ar_hdr);
 }
index e855d483b81cfe37bd684d8aad8e7f33d370a2de..3ddf670f65143515784eed88fa5ee8b5a37788a0 100644 (file)
@@ -727,13 +727,14 @@ section [%2d] '%s': symbol %zu: function in COMMON section is nonsense\n"),
          destshdr = gelf_getshdr (elf_getscn (ebl->elf, xndx), &destshdr_mem);
          if (destshdr != NULL)
            {
+             GElf_Addr sh_addr = (ehdr->e_type == ET_REL ? 0
+                                  : destshdr->sh_addr);
              if (GELF_ST_TYPE (sym->st_info) != STT_TLS)
                {
                  if (! ebl_check_special_symbol (ebl, ehdr, sym, name,
                                                  destshdr))
                    {
-                     if ((sym->st_value - destshdr->sh_addr)
-                         > destshdr->sh_size)
+                     if (sym->st_value - sh_addr > destshdr->sh_size)
                        {
                          /* GNU ld has severe bugs.  When it decides to remove
                             empty sections it leaves symbols referencing them
@@ -750,7 +751,7 @@ section [%2d] '%s': symbol %zu: function in COMMON section is nonsense\n"),
 section [%2d] '%s': symbol %zu: st_value out of bounds\n"),
                                   idx, section_name (ebl, idx), cnt);
                        }
-                     else if ((sym->st_value - destshdr->sh_addr
+                     else if ((sym->st_value - sh_addr
                                + sym->st_size) > destshdr->sh_size)
                        ERROR (gettext ("\
 section [%2d] '%s': symbol %zu does not fit completely in referenced section [%2d] '%s'\n"),
@@ -890,18 +891,24 @@ section [%2d] '%s': symbol %zu: non-local section symbol\n"),
                    destshdr = gelf_getshdr (gotscn, &destshdr_mem);
                }
 
-             const char *sname = (destshdr == NULL ? NULL
+             const char *sname = ((destshdr == NULL || xndx == SHN_UNDEF)
+                                  ? NULL
                                   : elf_strptr (ebl->elf, ehdr->e_shstrndx,
                                                 destshdr->sh_name));
              if (sname == NULL)
-               ERROR (gettext ("\
-section [%2d] '%s': _GLOBAL_OFFSET_TABLE_ symbol refers to bad section\n"),
-                      idx, section_name (ebl, idx));
+               {
+                 if (xndx != SHN_UNDEF || ehdr->e_type != ET_REL)
+                   ERROR (gettext ("\
+section [%2d] '%s': _GLOBAL_OFFSET_TABLE_ symbol refers to \
+bad section [%2d]\n"),
+                          idx, section_name (ebl, idx), xndx);
+               }
              else if (strcmp (sname, ".got.plt") != 0
                       && strcmp (sname, ".got") != 0)
                ERROR (gettext ("\
-section [%2d] '%s': _GLOBAL_OFFSET_TABLE_ symbol refers to '%s' section\n"),
-                      idx, section_name (ebl, idx), sname);
+section [%2d] '%s': _GLOBAL_OFFSET_TABLE_ symbol refers to \
+section [%2d] '%s'\n"),
+                      idx, section_name (ebl, idx), xndx, sname);
 
              if (destshdr != NULL)
                {
@@ -909,7 +916,8 @@ section [%2d] '%s': _GLOBAL_OFFSET_TABLE_ symbol refers to '%s' section\n"),
                  if (!ebl_check_special_symbol (ebl, ehdr, sym, name,
                                                 destshdr))
                    {
-                     if (sym->st_value != destshdr->sh_addr)
+                     if (ehdr->e_type != ET_REL
+                         && sym->st_value != destshdr->sh_addr)
                        /* This test is more strict than the psABIs which
                           usually allow the symbol to be in the middle of
                           the .got section, allowing negative offsets.  */
@@ -1307,7 +1315,8 @@ section [%2d] '%s': relocation %zu: only symbol '_GLOBAL_OFFSET_TABLE_' can be u
     {
       if (destshdr != NULL
          && GELF_R_TYPE (r_info) != 0
-         && (r_offset - destshdr->sh_addr) >= destshdr->sh_size)
+         && (r_offset - (ehdr->e_type == ET_REL ? 0
+                         : destshdr->sh_addr)) >= destshdr->sh_size)
        ERROR (gettext ("\
 section [%2d] '%s': relocation %zu: offset out of bounds\n"),
               idx, section_name (ebl, idx), cnt);
@@ -3086,7 +3095,7 @@ static const struct
   const char *name;
   size_t namelen;
   GElf_Word type;
-  enum { unused, exact, atleast } attrflag;
+  enum { unused, exact, atleast, exact_or_gnuld } attrflag;
   GElf_Word attr;
   GElf_Word attr2;
 } special_sections[] =
@@ -3096,7 +3105,8 @@ static const struct
     { ".comment", 8, SHT_PROGBITS, exact, 0, 0 },
     { ".data", 6, SHT_PROGBITS, exact, SHF_ALLOC | SHF_WRITE, 0 },
     { ".data1", 7, SHT_PROGBITS, exact, SHF_ALLOC | SHF_WRITE, 0 },
-    { ".debug", 7, SHT_PROGBITS, exact, 0, 0 },
+    { ".debug_str", 11, SHT_PROGBITS, exact_or_gnuld, SHF_MERGE | SHF_STRINGS, 0 },
+    { ".debug", 6, SHT_PROGBITS, exact, 0, 0 },
     { ".dynamic", 9, SHT_DYNAMIC, atleast, SHF_ALLOC, SHF_WRITE },
     { ".dynstr", 8, SHT_STRTAB, exact, SHF_ALLOC, 0 },
     { ".dynsym", 8, SHT_DYNSYM, exact, SHF_ALLOC, 0 },
@@ -3132,6 +3142,10 @@ static const struct
 #define nspecial_sections \
   (sizeof (special_sections) / sizeof (special_sections[0]))
 
+#define IS_KNOWN_SPECIAL(idx, string, prefix)                        \
+  (special_sections[idx].namelen == sizeof string - (prefix ? 1 : 0)  \
+   && !memcmp (special_sections[idx].name, string, \
+              sizeof string - (prefix ? 1 : 0)))
 
 static void
 check_sections (Ebl *ebl, GElf_Ehdr *ehdr)
@@ -3213,13 +3227,18 @@ cannot get section header for section [%2zu] '%s': %s\n"),
                char stbuf3[100];
 
                GElf_Word good_type = special_sections[s].type;
-               if (special_sections[s].namelen == sizeof ".plt" &&
-                   !memcmp (special_sections[s].name, ".plt", sizeof ".plt")
+               if (IS_KNOWN_SPECIAL (s, ".plt", false)
                    && ebl_bss_plt_p (ebl, ehdr))
                  good_type = SHT_NOBITS;
 
+               /* In a debuginfo file, any normal section can be SHT_NOBITS.
+                  This is only invalid for DWARF sections and .shstrtab.  */
                if (shdr->sh_type != good_type
-                   && !(is_debuginfo && shdr->sh_type == SHT_NOBITS))
+                   && (shdr->sh_type != SHT_NOBITS
+                       || !is_debuginfo
+                       || IS_KNOWN_SPECIAL (s, ".debug_str", false)
+                       || IS_KNOWN_SPECIAL (s, ".debug", true)
+                       || IS_KNOWN_SPECIAL (s, ".shstrtab", false)))
                  ERROR (gettext ("\
 section [%2d] '%s' has wrong type: expected %s, is %s\n"),
                         (int) cnt, scnname,
@@ -3228,12 +3247,14 @@ section [%2d] '%s' has wrong type: expected %s, is %s\n"),
                         ebl_section_type_name (ebl, shdr->sh_type,
                                                stbuf2, sizeof (stbuf2)));
 
-               if (special_sections[s].attrflag == exact)
+               if (special_sections[s].attrflag == exact
+                   || special_sections[s].attrflag == exact_or_gnuld)
                  {
                    /* Except for the link order and group bit all the
                       other bits should match exactly.  */
                    if ((shdr->sh_flags & ~(SHF_LINK_ORDER | SHF_GROUP))
-                       != special_sections[s].attr)
+                       != special_sections[s].attr
+                       && (special_sections[s].attrflag == exact || !gnuld))
                      ERROR (gettext ("\
 section [%2zu] '%s' has wrong flags: expected %s, is %s\n"),
                             cnt, scnname,
@@ -3665,6 +3686,9 @@ phdr[%d]: no note entries defined for the type of file\n"),
     /* The p_offset values in a separate debug file are bogus.  */
     return;
 
+  if (phdr->p_filesz == 0)
+    return;
+
   GElf_Off notes_size = 0;
   Elf_Data *data = elf_getdata_rawchunk (ebl->elf,
                                         phdr->p_offset, phdr->p_filesz,
@@ -3683,6 +3707,9 @@ phdr[%d]: no note entries defined for the type of file\n"),
 static void
 check_note_section (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr, int idx)
 {
+  if (shdr->sh_size == 0)
+    return;
+
   Elf_Data *data = elf_getdata (elf_getscn (ebl->elf, idx), NULL);
   if (data == NULL)
     {
diff --git a/src/make-debug-archive.in b/src/make-debug-archive.in
new file mode 100644 (file)
index 0000000..c3fcbce
--- /dev/null
@@ -0,0 +1,132 @@
+#!/bin/sh
+#
+# Script to make an offline archive for debugging with libdwfl-based tools.
+#
+#      make-debug-archive ARCHIVE {options}
+#      make-debug-archive --kernel [--force] [RELEASE]
+#
+# Valid options are those listed under 'Input selection options'
+# by running @UNSTRIP@ --help.
+#
+# The archive installed by --kernel be used automatically by -K.
+# An offline archive can be used via -e in any tool that accepts those options.
+#
+
+UNSTRIP=${UNSTRIP:-@UNSTRIP@}
+AR=${AR:-@AR@}
+SUDO=${SUDO:-/usr/bin/sudo}
+
+LS=/bin/ls
+RM=/bin/rm
+MV=/bin/mv
+MKDIR=/bin/mkdir
+XARGS=/usr/bin/xargs
+
+outdir=${TMPDIR:-/tmp}/debugar$$
+
+usage()
+{
+  echo "Usage: $0 ARCHIVE {options}"
+  echo "   or: $0 --kernel [--sudo] [--force] [RELEASE]"
+  echo
+  echo "Valid options are listed under 'Input selection options'"
+  echo "when running: $UNSTRIP --help"
+  echo
+  echo "The --kernel form updates the file used by -K if the"
+  echo "kernel installation has changed, or always with --force."
+  echo "With --sudo, touches the installed file via $SUDO."
+}
+
+fatal_usage()
+{
+  usage >&2
+  exit 2
+}
+
+script_version()
+{
+  echo "`basename $0` (@PACKAGE_NAME@) @PACKAGE_VERSION@"
+  echo "Copyright (C) 2007 Red Hat, Inc."
+  echo "This is free software; see the source for copying conditions."
+  echo "There is NO warranty; not even for MERCHANTABILITY or"
+  echo "FITNESS FOR A PARTICULAR PURPOSE."
+  echo "Written by Roland McGrath."
+}
+
+sudo=
+kernel=no
+force_kernel=no
+while [ $# -gt 0 ]; do
+  case "x$1" in
+  x--help) usage; exit 0 ;;
+  x--version) script_version; exit 0 ;;
+  x--kernel) kernel=yes ;;
+  x--force) force_kernel=yes ;;
+  x--sudo) sudo=$SUDO ;;
+  *) break ;;
+  esac
+  shift
+done
+
+if [ $kernel = no ] && [ $force_kernel = yes -o -n "$sudo" ]; then
+  usage
+fi
+
+if [ $kernel = yes ]; then
+  if [ $# -eq 0 ]; then
+    release=`uname -r`
+  elif [ $# -eq 1 ]; then
+    release=$1
+  else
+    fatal_usage
+  fi
+
+  dir=/usr/lib/debug/lib/modules/$release
+  archive=$dir/debug.a
+  dep=/lib/modules/$release/modules.dep
+
+  if [ ! -d $dir ]; then
+    echo >&2 "$0: $dir not installed"
+    exit 1
+  fi
+
+  # Without --force, bail if the kernel installation is not newer.
+  # This file is normally touched by installing new kernels or modules.
+  if [ $force_kernel = no -a "$archive" -nt "$dep" ]; then
+    exit 0
+  fi
+
+  # We have to kill the old one first, because our own -K would use it.
+  [ ! -e "$archive" ] || $sudo $RM -f "$archive" || exit
+
+  set "$archive" "-K$release"
+fi
+
+if [ $# -lt 2 ]; then
+  fatal_usage
+fi
+
+archive="$1"
+shift
+
+case "$archive" in
+/*) ;;
+*) archive="`/bin/pwd`/$archive" ;;
+esac
+
+if [ -z "$sudo" ]; then
+  new_archive="$archive.new"
+else
+  new_archive="$outdir.a"
+fi
+
+$RM -f "$new_archive" || exit
+
+trap '$RM -rf "$outdir" "$new_archive"' 0 1 2 15
+
+$MKDIR "$outdir" &&
+$UNSTRIP -d "$outdir" -m -a -R "$@" &&
+(cd "$outdir" && $LS | $XARGS $AR cq "$new_archive") &&
+$sudo $MV -f "$new_archive" "$archive"
+
+exit
index ffcb0a1c8b6f104931bdd271f7c3aba8723f2a96..c591b3227b3f04caf53a71d3dcf023ace69b0357 100644 (file)
@@ -39,6 +39,7 @@
 #include <inttypes.h>
 #include <langinfo.h>
 #include <libdw.h>
+#include <libdwfl.h>
 #include <libintl.h>
 #include <locale.h>
 #include <stdarg.h>
@@ -198,11 +199,8 @@ static size_t shnum;
 
 
 /* Declarations of local functions.  */
-static void process_file (int fd, Elf *elf, const char *prefix,
-                         const char *fname, bool only_one,
-                         bool will_print_archive_index);
-static void process_elf_file (Elf *elf, const char *prefix, const char *fname,
-                             bool only_one);
+static void process_file (int fd, const char *fname, bool only_one);
+static void process_elf_file (Dwfl_Module *dwflmod);
 static void print_ehdr (Ebl *ebl, GElf_Ehdr *ehdr);
 static void print_shdr (Ebl *ebl, GElf_Ehdr *ehdr);
 static void print_phdr (Ebl *ebl, GElf_Ehdr *ehdr);
@@ -218,7 +216,7 @@ static void handle_verneed (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr);
 static void handle_verdef (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr);
 static void handle_versym (Ebl *ebl, Elf_Scn *scn,
                           GElf_Shdr *shdr);
-static void print_debug (Ebl *ebl, GElf_Ehdr *ehdr);
+static void print_debug (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr);
 static void handle_hash (Ebl *ebl);
 static void handle_notes (Ebl *ebl, GElf_Ehdr *ehdr);
 static void print_liblist (Ebl *ebl);
@@ -256,21 +254,7 @@ main (int argc, char *argv[])
          continue;
        }
 
-      /* Create an `Elf' descriptor.  */
-      Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
-      if (elf == NULL)
-       error (0, 0, gettext ("cannot generate Elf descriptor: %s\n"),
-              elf_errmsg (-1));
-      else
-       {
-         process_file (fd, elf, NULL, argv[remaining], only_one,
-                       print_archive_index);
-
-         /* Now we can close the descriptor.  */
-         if (elf_end (elf) != 0)
-           error (0, 0, gettext ("error while closing Elf descriptor: %s"),
-                  elf_errmsg (-1));
-       }
+      process_file (fd, argv[remaining], only_one);
 
       close (fd);
     }
@@ -435,103 +419,138 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
 }
 
 
-/* Process one file.  */
+/* Check if the file is an archive, and if so dump its index.  */
 static void
-process_file (int fd, Elf *elf, const char *prefix, const char *fname,
-             bool only_one, bool will_print_archive_index)
+check_archive_index (int fd, const char *fname, bool only_one)
 {
-  /* We can handle two types of files: ELF files and archives.  */
-  Elf_Kind kind = elf_kind (elf);
-  struct stat64 st;
-
-  switch (kind)
+  /* Create an `Elf' descriptor.  */
+  Elf *elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
+  if (elf == NULL)
+    error (0, 0, gettext ("cannot generate Elf descriptor: %s"),
+          elf_errmsg (-1));
+  else
     {
-    case ELF_K_ELF:
-      if (unlikely (will_print_archive_index))
+      if (elf_kind (elf) == ELF_K_AR)
+       {
+         if (!only_one)
+           printf ("\n%s:\n\n", fname);
+         dump_archive_index (elf, fname);
+       }
+      else
        error (0, 0,
               gettext ("'%s' is not an archive, cannot print archive index"),
               fname);
-      /* Yes!  It's an ELF file.  */
-      if (any_control_option)
-       process_elf_file (elf, prefix, fname, only_one);
-      break;
 
-    case ELF_K_AR:
-      {
-       size_t prefix_len = prefix == NULL ? 0 : strlen (prefix);
-       size_t fname_len = strlen (fname) + 1;
-       char new_prefix[prefix_len + 1 + fname_len];
-       char *cp = new_prefix;
+      /* Now we can close the descriptor.  */
+      if (elf_end (elf) != 0)
+       error (0, 0, gettext ("error while closing Elf descriptor: %s"),
+              elf_errmsg (-1));
+    }
+}
 
-       /* Create the full name of the file.  */
-       if (prefix != NULL)
-         {
-           cp = mempcpy (cp, prefix, prefix_len);
-           *cp++ = ':';
-         }
-       memcpy (cp, fname, fname_len);
+/* Trivial callback used for checking if we opened an archive.  */
+static int
+count_dwflmod (Dwfl_Module *dwflmod __attribute__ ((unused)),
+              void **userdata __attribute__ ((unused)),
+              const char *name __attribute__ ((unused)),
+              Dwarf_Addr base __attribute__ ((unused)),
+              void *arg)
+{
+  *(bool *) arg = false;
+  return DWARF_CB_ABORT;
+}
 
-       if (will_print_archive_index)
-         dump_archive_index (elf, new_prefix);
+static int
+process_dwflmod (Dwfl_Module *dwflmod,
+                void **userdata __attribute__ ((unused)),
+                const char *name __attribute__ ((unused)),
+                Dwarf_Addr base __attribute__ ((unused)),
+                void *arg)
+{
+  bool only_one = *(bool *) arg;
 
-       /* It's an archive.  We process each file in it.  */
-       Elf *subelf;
-       Elf_Cmd cmd = ELF_C_READ_MMAP;
-       while ((subelf = elf_begin (fd, cmd, elf)) != NULL)
-         {
-           kind = elf_kind (subelf);
+  /* Print the file name.  */
+  if (!only_one)
+    {
+      const char *fname;
+      dwfl_module_info (dwflmod, NULL, NULL, NULL, NULL, NULL, &fname, NULL);
 
-           /* Call this function recursively.  */
-           if (kind == ELF_K_ELF || kind == ELF_K_AR)
-             {
-               Elf_Arhdr *arhdr = elf_getarhdr (subelf);
-               assert (arhdr != NULL);
+      printf ("\n%s:\n\n", fname);
+    }
 
-               process_file (fd, subelf, new_prefix, arhdr->ar_name, false,
-                             kind == ELF_K_AR && will_print_archive_index);
-             }
+  process_elf_file (dwflmod);
 
-           /* Get next archive element.  */
-           cmd = elf_next (subelf);
-           if (elf_end (subelf) != 0)
-             error (0, 0,
-                    gettext (" error while freeing sub-ELF descriptor: %s\n"),
-                    elf_errmsg (-1));
-         }
-      }
-      break;
+  return DWARF_CB_OK;
+}
 
-    default:
+/* Stub libdwfl callback, only the ELF handle already open is ever used.  */
+static int
+find_no_debuginfo (Dwfl_Module *mod __attribute__ ((unused)),
+                  void **userdata __attribute__ ((unused)),
+                  const char *modname __attribute__ ((unused)),
+                  Dwarf_Addr base __attribute__ ((unused)),
+                  const char *file_name __attribute__ ((unused)),
+                  const char *debuglink_file __attribute__ ((unused)),
+                  GElf_Word debuglink_crc __attribute__ ((unused)),
+                  char **debuginfo_file_name __attribute__ ((unused)))
+{
+  return -1;
+}
+
+/* Process one input file.  */
+static void
+process_file (int fd, const char *fname, bool only_one)
+{
+  if (print_archive_index)
+    check_archive_index (fd, fname, only_one);
+
+  if (!any_control_option)
+    return;
+
+  /* Use libdwfl in a trivial way to open the libdw handle for us.
+     This takes care of applying relocations to DWARF data in ET_REL files.  */
+  static const Dwfl_Callbacks callbacks =
+    {
+      .section_address = dwfl_offline_section_address,
+      .find_debuginfo = find_no_debuginfo
+    };
+  Dwfl *dwfl = dwfl_begin (&callbacks);
+  if (dwfl_report_offline (dwfl, fname, fname, fd) == NULL)
+    {
+      struct stat64 st;
       if (fstat64 (fd, &st) != 0)
        error (0, errno, gettext ("cannot stat input file"));
       else if (st.st_size == 0)
        error (0, 0, gettext ("input file is empty"));
       else
-       /* We cannot do anything.  */
-       error (0, 0, gettext ("\
-Not an ELF file - it has the wrong magic bytes at the start"));
-      break;
+       error (0, 0, gettext ("failed reading '%s': %s"),
+              fname, dwfl_errmsg (-1));
+    }
+  else
+    {
+      dwfl_report_end (dwfl, NULL, NULL);
+
+      if (only_one)
+       /* Clear ONLY_ONE if we have multiple modules, from an archive.  */
+       dwfl_getmodules (dwfl, &count_dwflmod, &only_one, 1);
+
+      /* Process the one or more modules gleaned from this file.  */
+      dwfl_getmodules (dwfl, &process_dwflmod, &only_one, 0);
     }
+  dwfl_end (dwfl);
 }
 
 
-/* Process one file.  */
+/* Process one ELF file.  */
 static void
-process_elf_file (Elf *elf, const char *prefix, const char *fname,
-                 bool only_one)
+process_elf_file (Dwfl_Module *dwflmod)
 {
+  GElf_Addr dwflbias;
+  Elf *elf = dwfl_module_getelf (dwflmod, &dwflbias);
+
   GElf_Ehdr ehdr_mem;
   GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem);
 
-  /* Print the file name.  */
-  if (!only_one)
-    {
-      if (prefix != NULL)
-       printf ("\n%s(%s):\n\n", prefix, fname);
-      else
-       printf ("\n%s:\n\n", fname);
-    }
-
   if (ehdr == NULL)
     {
       error (0, 0, gettext ("cannot read ELF header: %s"), elf_errmsg (-1));
@@ -578,7 +597,7 @@ process_elf_file (Elf *elf, const char *prefix, const char *fname,
   if (string_sections != NULL)
     dump_strings (ebl);
   if (print_debug_sections != 0)
-    print_debug (ebl, ehdr);
+    print_debug (dwflmod, ebl, ehdr);
   if (print_notes)
     handle_notes (ebl, ehdr);
   if (print_string_sections)
@@ -2721,6 +2740,79 @@ print_liblist (Ebl *ebl)
 }
 
 
+static char *
+format_dwarf_addr (Dwfl_Module *dwflmod,
+                  int address_size, Dwarf_Addr address)
+{
+  /* See if there is a name we can give for this address.  */
+  GElf_Sym sym;
+  const char *name = dwfl_module_addrsym (dwflmod, address, &sym, NULL);
+  if (name != NULL)
+    sym.st_value = address - sym.st_value;
+
+  /* Relativize the address.  */
+  int n = dwfl_module_relocations (dwflmod);
+  int i = n < 1 ? -1 : dwfl_module_relocate_address (dwflmod, &address);
+
+  /* In an ET_REL file there is a section name to refer to.  */
+  const char *scn = (i < 0 ? NULL
+                    : dwfl_module_relocation_info (dwflmod, i, NULL));
+
+  char *result;
+  if ((name != NULL
+       ? (sym.st_value != 0
+         ? (scn != NULL
+            ? (address_size == 0
+               ? asprintf (&result,
+                           gettext ("%s+%#" PRIx64 " <%s+%#" PRIx64 ">"),
+                           scn, address, name, sym.st_value)
+               : asprintf (&result,
+                           gettext ("%s+%#0*" PRIx64 " <%s+%#" PRIx64 ">"),
+                           scn, 2 + address_size * 2, address,
+                           name, sym.st_value))
+            : (address_size == 0
+               ? asprintf (&result,
+                           gettext ("%#" PRIx64 " <%s+%#" PRIx64 ">"),
+                           address, name, sym.st_value)
+               : asprintf (&result,
+                           gettext ("%#0*" PRIx64 " <%s+%#" PRIx64 ">"),
+                           2 + address_size * 2, address,
+                           name, sym.st_value)))
+         : (scn != NULL
+            ? (address_size == 0
+               ? asprintf (&result,
+                           gettext ("%s+%#" PRIx64 " <%s>"),
+                           scn, address, name)
+               : asprintf (&result,
+                           gettext ("%s+%#0*" PRIx64 " <%s>"),
+                           scn, 2 + address_size * 2, address, name))
+            : (address_size == 0
+               ? asprintf (&result,
+                           gettext ("%#" PRIx64 " <%s>"),
+                           address, name)
+               : asprintf (&result,
+                           gettext ("%#0*" PRIx64 " <%s>"),
+                           2 + address_size * 2, address, name))))
+       : (scn != NULL
+         ? (address_size == 0
+            ? asprintf (&result,
+                        gettext ("%s+%#" PRIx64),
+                        scn, address)
+            : asprintf (&result,
+                        gettext ("%s+%#0*" PRIx64),
+                        scn, 2 + address_size * 2, address))
+         : (address_size == 0
+            ? asprintf (&result,
+                        "%#" PRIx64,
+                        address)
+            : asprintf (&result,
+                        "%#0*" PRIx64,
+                        2 + address_size * 2, address)))) < 0)
+    error (EXIT_FAILURE, 0, _("memory exhausted"));
+
+  return result;
+}
+
 static const char *
 dwarf_tag_string (unsigned int tag)
 {
@@ -3307,7 +3399,7 @@ dwarf_discr_list_string (unsigned int code)
 
 
 static void
-print_ops (Dwarf *dbg, int indent, int indentrest,
+print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest,
           unsigned int addrsize, Dwarf_Word len, const unsigned char *data)
 {
   static const char *const known[] =
@@ -3487,9 +3579,18 @@ print_ops (Dwarf *dbg, int indent, int indentrest,
          data += addrsize;
          len -= addrsize;
 
-         printf ("%*s[%4" PRIuMAX "] %s %" PRIuMAX "\n",
-                 indent, "", (uintmax_t) offset,
-                 known[op] ?: "???", (uintmax_t) addr);
+         if (op == DW_OP_addr)
+           {
+             char *a = format_dwarf_addr (dwflmod, 0, addr);
+             printf ("%*s[%4" PRIuMAX "] %s %s\n",
+                     indent, "", (uintmax_t) offset,
+                     known[op] ?: "???", a);
+             free (a);
+           }
+         else
+           printf ("%*s[%4" PRIuMAX "] %s %#" PRIxMAX "\n",
+                   indent, "", (uintmax_t) offset,
+                   known[op] ?: "???", (uintmax_t) addr);
          offset += 1 + addrsize;
          break;
 
@@ -3646,7 +3747,8 @@ print_ops (Dwarf *dbg, int indent, int indentrest,
 
 
 static void
-print_debug_abbrev_section (Ebl *ebl __attribute__ ((unused)),
+print_debug_abbrev_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
+                           Ebl *ebl __attribute__ ((unused)),
                            GElf_Ehdr *ehdr __attribute__ ((unused)),
                            Elf_Scn *scn __attribute__ ((unused)),
                            GElf_Shdr *shdr, Dwarf *dbg)
@@ -3717,7 +3819,8 @@ print_debug_abbrev_section (Ebl *ebl __attribute__ ((unused)),
    not have to know a bit about the structure of the section, libdwarf
    takes care of it.  */
 static void
-print_debug_aranges_section (Ebl *ebl __attribute__ ((unused)),
+print_debug_aranges_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
+                            Ebl *ebl __attribute__ ((unused)),
                             GElf_Ehdr *ehdr __attribute__ ((unused)),
                             Elf_Scn *scn __attribute__ ((unused)),
                             GElf_Shdr *shdr, Dwarf *dbg)
@@ -3773,7 +3876,8 @@ print_debug_aranges_section (Ebl *ebl __attribute__ ((unused)),
 
 /* Print content of DWARF .debug_ranges section.  */
 static void
-print_debug_ranges_section (Ebl *ebl __attribute__ ((unused)),
+print_debug_ranges_section (Dwfl_Module *dwflmod,
+                           Ebl *ebl __attribute__ ((unused)),
                            GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr,
                            Dwarf *dbg)
 {
@@ -3800,7 +3904,7 @@ print_debug_ranges_section (Ebl *ebl __attribute__ ((unused)),
 
       if (data->d_size - offset < address_size * 2)
        {
-         printf (" [%6tx]  <INVALID DATA>\n", offset);
+         printf (gettext (" [%6tx]  <INVALID DATA>\n"), offset);
          break;
        }
 
@@ -3820,21 +3924,24 @@ print_debug_ranges_section (Ebl *ebl __attribute__ ((unused)),
        }
 
       if (begin == (Dwarf_Addr) -1l) /* Base address entry.  */
-       printf (" [%6tx]  base address %#0*" PRIxMAX "\n", offset,
-               2 + (int) (address_size * 2), (uintmax_t) end);
+       {
+         char *b = format_dwarf_addr (dwflmod, address_size, end);
+         printf (gettext (" [%6tx]  base address %s\n"), offset, b);
+         free (b);
+       }
       else if (begin == 0 && end == 0) /* End of list entry.  */
        first = true;
       else
        {
+         char *b = format_dwarf_addr (dwflmod, address_size, begin);
+         char *e = format_dwarf_addr (dwflmod, address_size, end);
          /* We have an address range entry.  */
          if (first)            /* First address range entry in a list.  */
-           printf (" [%6tx]  %#0*" PRIxMAX "..%#0*" PRIxMAX "\n", offset,
-                   2 + (int) (address_size * 2), (uintmax_t) begin,
-                   2 + (int) (address_size * 2), (uintmax_t) end);
+           printf (gettext (" [%6tx]  %s..%s\n"), offset, b, e);
          else
-           printf ("           %#0*" PRIxMAX "..%#0*" PRIxMAX "\n",
-                   2 + (int) (address_size * 2), (uintmax_t) begin,
-                   2 + (int) (address_size * 2), (uintmax_t) end);
+           printf (gettext ("           %s..%s\n"), b, e);
+         free (b);
+         free (e);
 
          first = false;
        }
@@ -3843,7 +3950,8 @@ print_debug_ranges_section (Ebl *ebl __attribute__ ((unused)),
 
 
 static void
-print_debug_frame_section (Ebl *ebl __attribute__ ((unused)),
+print_debug_frame_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
+                          Ebl *ebl __attribute__ ((unused)),
                           GElf_Ehdr *ehdr __attribute__ ((unused)),
                           Elf_Scn *scn __attribute__ ((unused)),
                           GElf_Shdr *shdr __attribute__ ((unused)),
@@ -3854,6 +3962,7 @@ print_debug_frame_section (Ebl *ebl __attribute__ ((unused)),
 
 struct attrcb_args
 {
+  Dwfl_Module *dwflmod;
   Dwarf *dbg;
   int level;
   unsigned int addrsize;
@@ -3885,18 +3994,21 @@ attr_callback (Dwarf_Attribute *attrp, void *arg)
 
   switch (form)
     {
-    case DW_FORM_addr:;
-      Dwarf_Addr addr;
-      if (unlikely (dwarf_formaddr (attrp, &addr) != 0))
-       {
-       attrval_out:
-         error (0, 0, gettext ("cannot get attribute value: %s"),
-                dwarf_errmsg (-1));
-         return DWARF_CB_ABORT;
-       }
-      printf ("           %*s%-20s %#0*" PRIxMAX "\n",
-             (int) (level * 2), "", dwarf_attr_string (attr),
-             2 + (int) (cbargs->addrsize * 2), (uintmax_t) addr);
+    case DW_FORM_addr:
+      {
+       Dwarf_Addr addr;
+       if (unlikely (dwarf_formaddr (attrp, &addr) != 0))
+         {
+         attrval_out:
+           error (0, 0, gettext ("cannot get attribute value: %s"),
+                  dwarf_errmsg (-1));
+           return DWARF_CB_ABORT;
+         }
+       char *a = format_dwarf_addr (cbargs->dwflmod, cbargs->addrsize, addr);
+       printf ("           %*s%-20s %s\n",
+               (int) (level * 2), "", dwarf_attr_string (attr), a);
+       free (a);
+      }
       break;
 
     case DW_FORM_indirect:
@@ -4033,7 +4145,8 @@ attr_callback (Dwarf_Attribute *attrp, void *arg)
        case DW_AT_frame_base:
        case DW_AT_return_addr:
        case DW_AT_static_link:
-         print_ops (cbargs->dbg, 12 + level * 2, 12 + level * 2,
+         print_ops (cbargs->dwflmod, cbargs->dbg,
+                    12 + level * 2, 12 + level * 2,
                     cbargs->addrsize, block.length, block.data);
          break;
        }
@@ -4051,7 +4164,8 @@ attr_callback (Dwarf_Attribute *attrp, void *arg)
 
 
 static void
-print_debug_info_section (Ebl *ebl __attribute__ ((unused)),
+print_debug_info_section (Dwfl_Module *dwflmod,
+                         Ebl *ebl __attribute__ ((unused)),
                          GElf_Ehdr *ehdr __attribute__ ((unused)),
                          Elf_Scn *scn __attribute__ ((unused)),
                          GElf_Shdr *shdr, Dwarf *dbg)
@@ -4088,6 +4202,7 @@ print_debug_info_section (Ebl *ebl __attribute__ ((unused)),
 
 
   struct attrcb_args args;
+  args.dwflmod = dwflmod;
   args.dbg = dbg;
   args.addrsize = addrsize;
   args.cu_offset = offset;
@@ -4172,7 +4287,8 @@ print_debug_info_section (Ebl *ebl __attribute__ ((unused)),
 
 
 static void
-print_debug_line_section (Ebl *ebl, GElf_Ehdr *ehdr __attribute__ ((unused)),
+print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl,
+                         GElf_Ehdr *ehdr __attribute__ ((unused)),
                          Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
 {
   printf (gettext ("\
@@ -4391,10 +4507,11 @@ print_debug_line_section (Ebl *ebl, GElf_Ehdr *ehdr __attribute__ ((unused)),
              line += line_increment;
              address += address_increment;
 
+             char *a = format_dwarf_addr (dwflmod, 0, address);
              printf (gettext ("\
- special opcode %u: address+%u = %#" PRIx64 ", line%+d = %zu\n"),
-                     opcode, address_increment, (uint64_t) address,
-                     line_increment, line);
+ special opcode %u: address+%u = %s, line%+d = %zu\n"),
+                     opcode, address_increment, a, line_increment, line);
+             free (a);
            }
          else if (opcode == 0)
            {
@@ -4429,8 +4546,11 @@ print_debug_line_section (Ebl *ebl, GElf_Ehdr *ehdr __attribute__ ((unused)),
                    address = read_4ubyte_unaligned_inc (dbg, linep);
                  else
                    address = read_8ubyte_unaligned_inc (dbg, linep);
-                 printf (gettext ("set address to %#" PRIx64 "\n"),
-                         (uint64_t) address);
+                 {
+                   char *a = format_dwarf_addr (dwflmod, 0, address);
+                   printf (gettext ("set address to %s\n"), a);
+                   free (a);
+                 }
                  break;
 
                case DW_LNE_define_file:
@@ -4478,9 +4598,12 @@ define new file: dir=%u, mtime=%" PRIu64 ", length=%" PRIu64 ", name=%s\n"),
                     address.  */
                  get_uleb128 (u128, linep);
                  address += minimum_instr_len * u128;
-                 printf (gettext ("\
- advance address by %u to %#" PRIx64 "\n"),
-                         u128, (uint64_t) address);
+                 {
+                   char *a = format_dwarf_addr (dwflmod, 0, address);
+                   printf (gettext ("advance address by %u to %s\n"),
+                           u128, a);
+                   free (a);
+                 }
                  break;
 
                case DW_LNS_advance_line:
@@ -4527,9 +4650,12 @@ define new file: dir=%u, mtime=%" PRIu64 ", length=%" PRIu64 ", name=%s\n"),
                  u128 = (minimum_instr_len
                          * ((255 - opcode_base) / line_range));
                  address += u128;
-                 printf (gettext ("\
- advance address by constant %u to %#" PRIx64 "\n"),
-                         u128, (uint64_t) address);
+                 {
+                   char *a = format_dwarf_addr (dwflmod, 0, address);
+                   printf (gettext ("advance address by constant %u to %s\n"),
+                           u128, a);
+                   free (a);
+                 }
                  break;
 
                case DW_LNS_fixed_advance_pc:
@@ -4540,9 +4666,13 @@ define new file: dir=%u, mtime=%" PRIu64 ", length=%" PRIu64 ", name=%s\n"),
 
                  u128 = read_2ubyte_unaligned_inc (dbg, linep);
                  address += u128;
-                 printf (gettext ("\
- advance address by fixed value %u to %#" PRIx64 "\n"),
-                         u128, (uint64_t) address);
+                 {
+                   char *a = format_dwarf_addr (dwflmod, 0, address);
+                   printf (gettext ("\
+advance address by fixed value %u to %s\n"),
+                           u128, a);
+                   free (a);
+                 }
                  break;
 
                case DW_LNS_set_prologue_end:
@@ -4585,7 +4715,8 @@ define new file: dir=%u, mtime=%" PRIu64 ", length=%" PRIu64 ", name=%s\n"),
 
 
 static void
-print_debug_loc_section (Ebl *ebl __attribute__ ((unused)),
+print_debug_loc_section (Dwfl_Module *dwflmod,
+                        Ebl *ebl __attribute__ ((unused)),
                         GElf_Ehdr *ehdr __attribute__ ((unused)),
                         Elf_Scn *scn __attribute__ ((unused)),
                         GElf_Shdr *shdr,
@@ -4614,7 +4745,7 @@ print_debug_loc_section (Ebl *ebl __attribute__ ((unused)),
 
       if (data->d_size - offset < address_size * 2)
        {
-         printf (" [%6tx]  <INVALID DATA>\n", offset);
+         printf (gettext (" [%6tx]  <INVALID DATA>\n"), offset);
          break;
        }
 
@@ -4634,8 +4765,11 @@ print_debug_loc_section (Ebl *ebl __attribute__ ((unused)),
        }
 
       if (begin == (Dwarf_Addr) -1l) /* Base address entry.  */
-       printf (" [%6tx]  base address %#0*" PRIxMAX "\n", offset,
-               2 + (int) (address_size * 2), (uintmax_t) end);
+       {
+         char *b = format_dwarf_addr (dwflmod, address_size, end);
+         printf (gettext (" [%6tx]  base address %s\n"), offset, b);
+         free (b);
+       }
       else if (begin == 0 && end == 0) /* End of list entry.  */
        first = true;
       else
@@ -4643,17 +4777,18 @@ print_debug_loc_section (Ebl *ebl __attribute__ ((unused)),
          /* We have a location expression entry.  */
          uint_fast16_t len = read_2ubyte_unaligned_inc (dbg, readp);
 
+         char *b = format_dwarf_addr (dwflmod, address_size, begin);
+         char *e = format_dwarf_addr (dwflmod, address_size, end);
+
          if (first)            /* First entry in a list.  */
-           printf (" [%6tx]  %#0*" PRIxMAX "..%#0*" PRIxMAX,
-                   offset,
-                   2 + (int) (address_size * 2), (uintmax_t) begin,
-                   2 + (int) (address_size * 2), (uintmax_t) end);
+           printf (gettext (" [%6tx]  %s..%s"), offset, b, e);
          else
-           printf ("           %#0*" PRIxMAX "..%#0*" PRIxMAX,
-                   2 + (int) (address_size * 2), (uintmax_t) begin,
-                   2 + (int) (address_size * 2), (uintmax_t) end);
+           printf (gettext ("           %s..%s"), b, e);
 
-         print_ops (dbg, 1, 18 + (address_size * 4),
+         free (b);
+         free (e);
+
+         print_ops (dwflmod, dbg, 1, 18 + (address_size * 4),
                     address_size, len, readp);
 
          first = false;
@@ -4686,7 +4821,8 @@ mac_compare (const void *p1, const void *p2)
 
 
 static void
-print_debug_macinfo_section (Ebl *ebl __attribute__ ((unused)),
+print_debug_macinfo_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
+                            Ebl *ebl __attribute__ ((unused)),
                             GElf_Ehdr *ehdr __attribute__ ((unused)),
                             Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
 {
@@ -4857,7 +4993,8 @@ print_pubnames (Dwarf *dbg __attribute__ ((unused)), Dwarf_Global *global,
 
 /* Print the known exported symbols in the DWARF section '.debug_pubnames'.  */
 static void
-print_debug_pubnames_section (Ebl *ebl __attribute__ ((unused)),
+print_debug_pubnames_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
+                             Ebl *ebl __attribute__ ((unused)),
                              GElf_Ehdr *ehdr __attribute__ ((unused)),
                              Elf_Scn *scn __attribute__ ((unused)),
                              GElf_Shdr *shdr, Dwarf *dbg)
@@ -4871,7 +5008,8 @@ print_debug_pubnames_section (Ebl *ebl __attribute__ ((unused)),
 
 /* Print the content of the DWARF string section '.debug_str'.  */
 static void
-print_debug_str_section (Ebl *ebl __attribute__ ((unused)),
+print_debug_str_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
+                        Ebl *ebl __attribute__ ((unused)),
                         GElf_Ehdr *ehdr __attribute__ ((unused)),
                         Elf_Scn *scn __attribute__ ((unused)),
                         GElf_Shdr *shdr, Dwarf *dbg)
@@ -4910,34 +5048,29 @@ print_debug_str_section (Ebl *ebl __attribute__ ((unused)),
     }
 }
 
-
 static void
-print_debug (Ebl *ebl, GElf_Ehdr *ehdr)
+print_debug (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr)
 {
-  /* Find the version information sections.  For this we have to
-     search through the section table.  */
-  Dwarf *dbg;
-  Elf_Scn *scn;
-  size_t shstrndx;
-
   /* Before we start the real work get a debug context descriptor.  */
-  dbg = dwarf_begin_elf (ebl->elf, DWARF_C_READ, NULL);
+  Dwarf_Addr dwbias;
+  Dwarf *dbg = dwfl_module_getdwarf (dwflmod, &dwbias);
   if (dbg == NULL)
     {
       error (0, 0, gettext ("cannot get debug context descriptor: %s"),
-            dwarf_errmsg (-1));
+            dwfl_errmsg (-1));
       return;
     }
 
   /* Get the section header string table index.  */
+  size_t shstrndx;
   if (elf_getshstrndx (ebl->elf, &shstrndx) < 0)
     error (EXIT_FAILURE, 0,
           gettext ("cannot get section header string table index"));
 
-  scn = NULL;
+  /* Look through all the sections for the debugging sections to print.  */
+  Elf_Scn *scn = NULL;
   while ((scn = elf_nextscn (ebl->elf, scn)) != NULL)
     {
-      /* Handle the section if it is part of the versioning handling.  */
       GElf_Shdr shdr_mem;
       GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
 
@@ -4947,7 +5080,8 @@ print_debug (Ebl *ebl, GElf_Ehdr *ehdr)
          {
            const char *name;
            enum section_e bitmask;
-           void (*fp) (Ebl *, GElf_Ehdr *, Elf_Scn *, GElf_Shdr *, Dwarf *);
+           void (*fp) (Dwfl_Module *, Ebl *,
+                       GElf_Ehdr *, Elf_Scn *, GElf_Shdr *, Dwarf *);
          } debug_sections[] =
            {
 #define NEW_SECTION(name) \
@@ -4974,14 +5108,11 @@ print_debug (Ebl *ebl, GElf_Ehdr *ehdr)
            if (strcmp (name, debug_sections[n].name) == 0)
              {
                if (print_debug_sections & debug_sections[n].bitmask)
-                 debug_sections[n].fp (ebl, ehdr, scn, shdr, dbg);
+                 debug_sections[n].fp (dwflmod, ebl, ehdr, scn, shdr, dbg);
                break;
              }
        }
     }
-
-  /* We are done with the DWARF handling.  */
-  dwarf_end (dbg);
 }
 
 
@@ -5144,6 +5275,7 @@ handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
       break;
 
     case 'T':
+    case (char) ('T'|0x80):
       assert (count == 2);
       Dwarf_Word sec;
       Dwarf_Word usec;
@@ -5161,6 +5293,22 @@ handle_core_item (Elf *core, const Ebl_Core_Item *item, const void *desc,
        default:
          abort ();
        }
+      if (unlikely (item->format == (char) ('T'|0x80)))
+       {
+         /* This is a hack for an ill-considered 64-bit ABI where
+            tv_usec is actually a 32-bit field with 32 bits of padding
+            rounding out struct timeval.  We've already converted it as
+            a 64-bit field.  For little-endian, this just means the
+            high half is the padding; it's presumably zero, but should
+            be ignored anyway.  For big-endian, it means the 32-bit
+            field went into the high half of USEC.  */
+         GElf_Ehdr ehdr_mem;
+         GElf_Ehdr *ehdr = gelf_getehdr (core, &ehdr_mem);
+         if (likely (ehdr->e_ident[EI_DATA] == ELFDATA2MSB))
+           usec >>= 32;
+         else
+           usec &= UINT32_MAX;
+       }
       colno = print_core_item (colno, ',', ITEM_WRAP_COLUMN, 0, item->name,
                               maxfmt, "%" PRIu64 ".%.6" PRIu64, sec, usec);
       break;
index ec22aa9193ef392b7c34ae439ddee566a375f174..d19ad27e092d4ffeff9ff5cb4b989ddc0a06b1c3 100644 (file)
 
   * prelink vs .debug_* linked addresses
 
-  * merge many inputs? -> ET_EXEC with union phdrs + new phdrs for ET_REL mods
-  ** with applied relocs to ET_REL mods, use data modified by dwfl
-  *** still must apply relocs to SHF_ALLOC
-  ** useless unless merge all symtabs and dwarf sections
-
  */
 
 #ifdef HAVE_CONFIG_H
@@ -91,6 +86,8 @@ static const struct argp_option options[] =
   { "all", 'a', NULL, 0,
     N_("Create output for modules that have no separate debug information"),
     0 },
+  { "relocate", 'R', NULL, 0,
+    N_("Apply relocations to DWARF sections in ET_REL files"), 0 },
   { "list-only", 'n', NULL, 0,
     N_("Only list module and file names, build IDs"), 0 },
   { NULL, 0, NULL, 0, NULL, 0 }
@@ -107,6 +104,7 @@ struct arg_info
   bool ignore;
   bool modnames;
   bool match_files;
+  bool relocate;
 };
 
 /* Handle program arguments.  */
@@ -154,6 +152,9 @@ parse_opt (int key, char *arg, struct argp_state *state)
     case 'n':
       info->list = true;
       break;
+    case 'R':
+      info->relocate = true;
+      break;
 
     case ARGP_KEY_ARGS:
     case ARGP_KEY_NO_ARGS:
@@ -199,10 +200,10 @@ parse_opt (int key, char *arg, struct argp_state *state)
              return EINVAL;
            }
 
-         if (info->ignore || info->all || info->modnames)
+         if (info->ignore || info->all || info->modnames || info->relocate)
            {
              argp_error (state, _("\
--m, -a, and -i options not allowed with explicit files"));
+-m, -a, -R, and -i options not allowed with explicit files"));
              return EINVAL;
            }
 
@@ -543,7 +544,7 @@ adjust_all_relocs (Elf *elf, Elf_Scn *symtab, const GElf_Shdr *symshdr,
    possible, add in section symbols for the added sections.  */
 static Elf_Data *
 add_new_section_symbols (Elf_Scn *old_symscn, size_t old_shnum,
-                        Elf *elf, Elf_Scn *symscn, size_t shnum)
+                        Elf *elf, bool rel, Elf_Scn *symscn, size_t shnum)
 {
   const size_t added = shnum - old_shnum;
 
@@ -590,7 +591,7 @@ add_new_section_symbols (Elf_Scn *old_symscn, size_t old_shnum,
       ELF_CHECK (i_shdr != NULL, _("cannot get section header: %s"));
       GElf_Sym sym =
        {
-         .st_value = i_shdr->sh_addr,
+         .st_value = rel ? 0 : i_shdr->sh_addr,
          .st_info = GELF_ST_INFO (STB_LOCAL, STT_SECTION),
          .st_shndx = i < SHN_LORESERVE ? i : SHN_XINDEX
        };
@@ -623,7 +624,7 @@ add_new_section_symbols (Elf_Scn *old_symscn, size_t old_shnum,
 /* This has the side effect of updating STT_SECTION symbols' values,
    in case of prelink adjustments.  */
 static Elf_Data *
-check_symtab_section_symbols (Elf *elf, Elf_Scn *scn,
+check_symtab_section_symbols (Elf *elf, bool rel, Elf_Scn *scn,
                              size_t shnum, size_t shstrndx,
                              Elf_Scn *oscn, size_t oshnum, size_t oshstrndx,
                              size_t debuglink)
@@ -632,10 +633,10 @@ check_symtab_section_symbols (Elf *elf, Elf_Scn *scn,
                                                   elf_getdata (scn, NULL));
 
   if (n == oshnum)
-    return add_new_section_symbols (oscn, n, elf, scn, shnum);
+    return add_new_section_symbols (oscn, n, elf, rel, scn, shnum);
 
   if (n == oshstrndx || (n == debuglink && n == oshstrndx - 1))
-    return add_new_section_symbols (oscn, n, elf, scn, shstrndx);
+    return add_new_section_symbols (oscn, n, elf, rel, scn, shstrndx);
 
   return NULL;
 }
@@ -650,15 +651,20 @@ struct section
 };
 
 static int
-compare_alloc_sections (const struct section *s1, const struct section *s2)
+compare_alloc_sections (const struct section *s1, const struct section *s2,
+                       bool rel)
 {
-  /* Sort by address.  */
-  if (s1->shdr.sh_addr < s2->shdr.sh_addr)
-    return -1;
-  if (s1->shdr.sh_addr > s2->shdr.sh_addr)
-    return 1;
+  if (!rel)
+    {
+      /* Sort by address.  */
+      if (s1->shdr.sh_addr < s2->shdr.sh_addr)
+       return -1;
+      if (s1->shdr.sh_addr > s2->shdr.sh_addr)
+       return 1;
+    }
 
-  return 0;
+  /* At the same address, preserve original section order.  */
+  return (ssize_t) elf_ndxscn (s1->scn) - (ssize_t) elf_ndxscn (s2->scn);
 }
 
 static int
@@ -676,7 +682,7 @@ compare_unalloc_sections (const GElf_Shdr *shdr1, const GElf_Shdr *shdr2,
 }
 
 static int
-compare_sections (const void *a, const void *b)
+compare_sections (const void *a, const void *b, bool rel)
 {
   const struct section *s1 = a;
   const struct section *s2 = b;
@@ -686,11 +692,23 @@ compare_sections (const void *a, const void *b)
     return (s1->shdr.sh_flags & SHF_ALLOC) ? -1 : 1;
 
   return ((s1->shdr.sh_flags & SHF_ALLOC)
-         ? compare_alloc_sections (s1, s2)
+         ? compare_alloc_sections (s1, s2, rel)
          : compare_unalloc_sections (&s1->shdr, &s2->shdr,
                                      s1->name, s2->name));
 }
 
+static int
+compare_sections_rel (const void *a, const void *b)
+{
+  return compare_sections (a, b, true);
+}
+
+int
+compare_sections_nonrel (const void *a, const void *b)
+{
+  return compare_sections (a, b, false);
+}
+
 
 struct symbol
 {
@@ -717,7 +735,7 @@ struct symbol
 
 /* Collect input symbols into our internal form.  */
 static void
-collect_symbols (Elf *outelf, Elf_Scn *symscn, Elf_Scn *strscn,
+collect_symbols (Elf *outelf, bool rel, Elf_Scn *symscn, Elf_Scn *strscn,
                 const size_t nent, const GElf_Addr bias,
                 const size_t scnmap[], struct symbol *table, size_t *map,
                 struct section *split_bss)
@@ -752,16 +770,14 @@ collect_symbols (Elf *outelf, Elf_Scn *symscn, Elf_Scn *strscn,
       if (scnmap != NULL && shndx != SHN_UNDEF && shndx < SHN_LORESERVE)
        s->shndx = scnmap[shndx - 1];
 
-      if (GELF_ST_TYPE (s->info.info) == STT_SECTION)
+      if (GELF_ST_TYPE (s->info.info) == STT_SECTION && !rel)
        {
+         /* Update the value to match the output section.  */
          GElf_Shdr shdr_mem;
-         GElf_Shdr *shdr = gelf_getshdr (elf_getscn (outelf, shndx),
+         GElf_Shdr *shdr = gelf_getshdr (elf_getscn (outelf, s->shndx),
                                          &shdr_mem);
          ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
-
-         if (GELF_ST_TYPE (s->info.info) == STT_SECTION)
-           /* Update the value to match the output section.  */
-           s->value = shdr->sh_addr;
+         s->value = shdr->sh_addr;
        }
       else if (split_bss != NULL
               && s->value < split_bss->shdr.sh_addr
@@ -836,6 +852,18 @@ compare_symbols_output (const void *a, const void *b)
 
 #undef CMP
 
+/* Return true iff the flags, size, and name match.  */
+static bool
+sections_match (const struct section *sections, size_t i,
+               const GElf_Shdr *shdr, const char *name)
+{
+  return (sections[i].shdr.sh_flags == shdr->sh_flags
+         && (sections[i].shdr.sh_size == shdr->sh_size
+             || (sections[i].shdr.sh_size < shdr->sh_size
+                 && section_can_shrink (&sections[i].shdr)))
+         && !strcmp (sections[i].name, name));
+}
+
 /* Locate a matching allocated section in SECTIONS.  */
 static struct section *
 find_alloc_section (const GElf_Shdr *shdr, GElf_Addr bias, const char *name,
@@ -858,11 +886,7 @@ find_alloc_section (const GElf_Shdr *shdr, GElf_Addr bias, const char *name,
            --i;
          for (; i < nalloc && sections[i].shdr.sh_addr == addr;
               ++i)
-           if (sections[i].shdr.sh_flags == shdr->sh_flags
-               && (sections[i].shdr.sh_size == shdr->sh_size
-                   || (sections[i].shdr.sh_size < shdr->sh_size
-                       && section_can_shrink (&sections[i].shdr)))
-               && !strcmp (sections[i].name, name))
+           if (sections_match (sections, i, shdr, name))
              return &sections[i];
          break;
        }
@@ -1001,7 +1025,7 @@ find_alloc_sections_prelink (Elf *debug, Elf_Data *debug_shstrtab,
            }
        }
       qsort (undo_sections, undo_nalloc,
-            sizeof undo_sections[0], compare_sections);
+            sizeof undo_sections[0], compare_sections_nonrel);
     }
 
   bool fail = false;
@@ -1221,7 +1245,9 @@ copy_elided_sections (Elf *unstripped, Elf *stripped,
   const struct section *stripped_symtab = NULL;
 
   /* Sort the sections, allocated by address and others after.  */
-  qsort (sections, stripped_shnum - 1, sizeof sections[0], compare_sections);
+  qsort (sections, stripped_shnum - 1, sizeof sections[0],
+        stripped_ehdr->e_type == ET_REL
+        ? compare_sections_rel : compare_sections_nonrel);
   size_t nalloc = stripped_shnum - 1;
   while (nalloc > 0 && !(sections[nalloc - 1].shdr.sh_flags & SHF_ALLOC))
     {
@@ -1260,6 +1286,7 @@ copy_elided_sections (Elf *unstripped, Elf *stripped,
   bool check_prelink = false;
   Elf_Scn *unstripped_symtab = NULL;
   size_t unstripped_strtab_ndx = SHN_UNDEF;
+  size_t alloc_avail = 0;
   scn = NULL;
   while ((scn = elf_nextscn (unstripped, scn)) != NULL)
     {
@@ -1280,36 +1307,59 @@ copy_elided_sections (Elf *unstripped, Elf *stripped,
 
       const char *name = get_section_name (ndx, shdr, shstrtab);
 
-      /* Look for the section that matches.  */
-      struct section *sec = ((shdr->sh_flags & SHF_ALLOC)
-                            ? find_alloc_section (shdr, bias, name,
-                                                  sections, nalloc)
-                            : find_unalloc_section (shdr, name));
-      if (sec == NULL)
+      struct section *sec = NULL;
+      if (shdr->sh_flags & SHF_ALLOC)
        {
-         if ((shdr->sh_flags & SHF_ALLOC) && stripped_ehdr->e_type != ET_REL)
+         if (stripped_ehdr->e_type != ET_REL)
            {
-             /* If we couldn't figure it out, it may be a prelink issue.  */
-             check_prelink = true;
-             continue;
+             /* Look for the section that matches.  */
+             sec = find_alloc_section (shdr, bias, name, sections, nalloc);
+             if (sec == NULL)
+               {
+                 /* We couldn't figure it out.  It may be a prelink issue.  */
+                 check_prelink = true;
+                 continue;
+               }
+           }
+         else
+           {
+             /* The sh_addr of allocated sections does not help us,
+                but the order usually matches.  */
+             if (likely (sections_match (sections, alloc_avail, shdr, name)))
+               sec = &sections[alloc_avail++];
+             else
+               for (size_t i = alloc_avail + 1; i < nalloc; ++i)
+                 if (sections_match (sections, i, shdr, name))
+                   {
+                     sec = &sections[i];
+                     break;
+                   }
+           }
+       }
+      else
+       {
+         /* Look for the section that matches.  */
+         sec = find_unalloc_section (shdr, name);
+         if (sec == NULL)
+           {
+             /* An additional unallocated section is fine if not SHT_NOBITS.
+                We looked it up anyway in case it's an unallocated section
+                copied in both files (e.g. SHT_NOTE), and don't keep both.  */
+             if (shdr->sh_type != SHT_NOBITS)
+               continue;
+
+             /* Somehow some old .debug files wound up with SHT_NOBITS
+                .comment sections, so let those pass.  */
+             if (!strcmp (name, ".comment"))
+               continue;
            }
-
-         /* An additional unallocated section is fine if not SHT_NOBITS.
-            We looked it up anyway in case it's an unallocated section
-            copied in both files (e.g. SHT_NOTE), so we don't keep both.  */
-         if (shdr->sh_type != SHT_NOBITS && !(shdr->sh_flags & SHF_ALLOC))
-           continue;
-
-         /* Somehow some old .debug files wound up with SHT_NOBITS
-            .comment sections, so let those pass.  */
-         if (!(shdr->sh_flags & SHF_ALLOC) && !strcmp (name, ".comment"))
-           continue;
-
-         error (EXIT_FAILURE, 0,
-                _("cannot find matching section for [%Zu] '%s'"),
-                elf_ndxscn (scn), name);
        }
 
+      if (sec == NULL)
+       error (EXIT_FAILURE, 0,
+              _("cannot find matching section for [%Zu] '%s'"),
+              elf_ndxscn (scn), name);
+
       sec->outscn = scn;
     }
 
@@ -1374,6 +1424,7 @@ copy_elided_sections (Elf *unstripped, Elf *stripped,
            {
              /* This was created by stripping.  We don't want it.  */
              debuglink = secndx;
+             ndx_section[secndx - 1] = SHN_UNDEF;
              continue;
            }
 
@@ -1418,7 +1469,16 @@ copy_elided_sections (Elf *unstripped, Elf *stripped,
        GElf_Shdr *shdr = gelf_getshdr (sec->outscn, &shdr_mem);
        ELF_CHECK (shdr != NULL, _("cannot get section header: %s"));
 
-       shdr_mem.sh_addr = sec->shdr.sh_addr;
+       /* In an ET_REL file under --relocate, the sh_addr of SHF_ALLOC
+          sections will have been set nonzero by relocation.  This
+          touched the shdrs of whichever file had the symtab.  sh_addr
+          is still zero in the corresponding shdr.  The relocated
+          address is what we want to use.  */
+       if (stripped_ehdr->e_type != ET_REL
+           || !(shdr_mem.sh_flags & SHF_ALLOC)
+           || shdr_mem.sh_addr == 0)
+         shdr_mem.sh_addr = sec->shdr.sh_addr;
+
        shdr_mem.sh_type = sec->shdr.sh_type;
        shdr_mem.sh_size = sec->shdr.sh_size;
        shdr_mem.sh_info = sec->shdr.sh_info;
@@ -1525,13 +1585,14 @@ copy_elided_sections (Elf *unstripped, Elf *stripped,
       size_t symndx_map[total_syms];
 
       if (stripped_symtab != NULL)
-       collect_symbols (unstripped, stripped_symtab->scn,
+       collect_symbols (unstripped, stripped_ehdr->e_type == ET_REL,
+                        stripped_symtab->scn,
                         elf_getscn (stripped, stripped_symtab->shdr.sh_link),
                         stripped_nsym, 0, ndx_section,
                         symbols, symndx_map, NULL);
 
       Elf_Scn *unstripped_strtab = elf_getscn (unstripped, shdr->sh_link);
-      collect_symbols (unstripped,
+      collect_symbols (unstripped, stripped_ehdr->e_type == ET_REL,
                       unstripped_symtab, unstripped_strtab, unstripped_nsym,
                       stripped_ehdr->e_type == ET_REL ? 0 : bias, NULL,
                       &symbols[stripped_nsym - 1],
@@ -1542,11 +1603,15 @@ copy_elided_sections (Elf *unstripped, Elf *stripped,
 
       /* Now we can weed out the duplicates.  Assign remaining symbols
         new slots, collecting a map from old indices to new.  */
-      size_t nsym = *symbols[0].map = 1;
-      for (size_t i = 1; i < total_syms; ++i)
-       *symbols[i].map = (!compare_symbols (&symbols[i - 1], &symbols[i])
-                          ? 0 /* This is a duplicate.  */
-                          : ++nsym); /* Allocate the next slot.  */
+      size_t nsym = 0;
+      for (struct symbol *s = symbols; s < &symbols[total_syms]; ++s)
+       /* Skip a section symbol for a removed section, or a duplicate.  */
+       *s->map = (((s->shndx == SHN_UNDEF
+                    && GELF_ST_TYPE (s->info.info) == STT_SECTION)
+                   || (s + 1 < &symbols[total_syms]
+                       && !compare_symbols (s, s + 1))) ? 0
+                  /* Allocate the next slot.  */
+                  : ++nsym);
 
       /* Now we sort again, to determine the order in the output.  */
       qsort (symbols, total_syms, sizeof symbols[0], compare_symbols_output);
@@ -1627,14 +1692,18 @@ copy_elided_sections (Elf *unstripped, Elf *stripped,
                         &symndx_map[stripped_nsym - 1]);
     }
   else if (stripped_symtab != NULL && stripped_shnum != unstripped_shnum)
-    check_symtab_section_symbols (unstripped, stripped_symtab->scn,
+    check_symtab_section_symbols (unstripped,
+                                 stripped_ehdr->e_type == ET_REL,
+                                 stripped_symtab->scn,
                                  unstripped_shnum, unstripped_shstrndx,
                                  stripped_symtab->outscn,
                                  stripped_shnum, stripped_shstrndx,
                                  debuglink);
 
   if (stripped_dynsym != NULL)
-    (void) check_symtab_section_symbols (unstripped, stripped_dynsym->outscn,
+    (void) check_symtab_section_symbols (unstripped,
+                                        stripped_ehdr->e_type == ET_REL,
+                                        stripped_dynsym->outscn,
                                         unstripped_shnum,
                                         unstripped_shstrndx,
                                         stripped_dynsym->scn, stripped_shnum,
@@ -1861,7 +1930,7 @@ handle_explicit_files (const char *output_file, bool create_dirs,
 /* Handle a pair of files opened implicitly by libdwfl for one module.  */
 static void
 handle_dwfl_module (const char *output_file, bool create_dirs,
-                   Dwfl_Module *mod, bool all, bool ignore)
+                   Dwfl_Module *mod, bool all, bool ignore, bool relocate)
 {
   GElf_Addr bias;
   Elf *stripped = dwfl_module_getelf (mod, &bias);
@@ -1922,25 +1991,38 @@ handle_dwfl_module (const char *output_file, bool create_dirs,
 
   if (stripped_ehdr.e_type == ET_REL)
     {
-      /* We can't use the Elf handles already open,
-        because the DWARF sections have been relocated.  */
+      if (!relocate)
+       {
+         /* We can't use the Elf handles already open,
+            because the DWARF sections have been relocated.  */
 
-      const char *stripped_file = NULL;
-      const char *unstripped_file = NULL;
-      (void) dwfl_module_info (mod, NULL, NULL, NULL, NULL, NULL,
-                              &stripped_file, &unstripped_file);
+         const char *stripped_file = NULL;
+         const char *unstripped_file = NULL;
+         (void) dwfl_module_info (mod, NULL, NULL, NULL, NULL, NULL,
+                                  &stripped_file, &unstripped_file);
 
-      handle_explicit_files (output_file, create_dirs,
-                            stripped_file, unstripped_file);
+         handle_explicit_files (output_file, create_dirs,
+                                stripped_file, unstripped_file);
+         return;
+       }
+
+      /* Relocation is what we want!  This ensures that all sections that can
+        get sh_addr values assigned have them, even ones not used in DWARF.
+        They might still be used in the symbol table.  */
+      if (dwfl_module_relocations (mod) < 0)
+       error (EXIT_FAILURE, 0,
+              _("cannot cache section addresses for module '%s': %s"),
+              dwfl_module_info (mod, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
+              dwfl_errmsg (-1));
     }
-  else
-    handle_file (output_file, create_dirs, stripped, &stripped_ehdr, debug);
+
+  handle_file (output_file, create_dirs, stripped, &stripped_ehdr, debug);
 }
 
 /* Handle one module being written to the output directory.  */
 static void
 handle_output_dir_module (const char *output_dir, Dwfl_Module *mod,
-                         bool all, bool ignore, bool modnames)
+                         bool all, bool ignore, bool modnames, bool relocate)
 {
   if (! modnames)
     {
@@ -1960,7 +2042,7 @@ handle_output_dir_module (const char *output_dir, Dwfl_Module *mod,
   if (asprintf (&output_file, "%s/%s", output_dir, modnames ? name : file) < 0)
     error (EXIT_FAILURE, 0, _("memory exhausted"));
 
-  handle_dwfl_module (output_file, true, mod, all, ignore);
+  handle_dwfl_module (output_file, true, mod, all, ignore, relocate);
 }
 
 
@@ -2073,12 +2155,13 @@ handle_implicit_modules (const struct arg_info *info)
       if (next (offset) != 0)
        error (EXIT_FAILURE, 0, _("matched more than one module"));
       handle_dwfl_module (info->output_file, false, mmi.found,
-                         info->all, info->ignore);
+                         info->all, info->ignore, info->relocate);
     }
   else
     do
       handle_output_dir_module (info->output_dir, mmi.found,
-                               info->all, info->ignore, info->modnames);
+                               info->all, info->ignore,
+                               info->modnames, info->relocate);
     while ((offset = next (offset)) > 0);
 }
 \f
index 32e4efe92a1914c4b8e62004e278841aa8ea560d..1284b134e7757929ed19e46dc4131bd162b5c180 100644 (file)
@@ -1,3 +1,14 @@
+2007-10-09  Roland McGrath  <roland@redhat.com>
+
+       * dwflmodtest.c (print_module): Don't use %p in output.
+       * run-dwfl-bug-offline-rel.sh: Updated expected output.
+
+2007-10-08  Roland McGrath  <roland@redhat.com>
+
+       * testfile42.bz2: New data file.
+       * Makefile.am (EXTRA_DIST): Add it.
+       * run-elflint-test.sh: New test on that file.
+
 2007-10-04  Roland McGrath  <roland@redhat.com>
 
        * run-readelf-test4.sh: New file.
index 1fce5b72728a29754fdab4564ef660330e44a1de..ab325c7afd0f9f3619ad185a6781ad63294960a4 100644 (file)
@@ -132,7 +132,7 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh \
             testfile36.bz2 testfile36.debug.bz2 \
             testfile37.bz2 testfile37.debug.bz2 \
             testfile38.bz2 testfile39.bz2 testfile40.bz2 testfile40.debug.bz2 \
-            testfile41.bz2
+            testfile41.bz2 testfile42.bz2
 
 installed_TESTS_ENVIRONMENT = libdir=$(DESTDIR)$(libdir) \
                              bindir=$(DESTDIR)$(bindir) \
index c34cac42902b0753bce7896e963aee909ef1e2e9..94f960faffda0b6cb0fa41d9502597de3495f9fb 100644 (file)
@@ -188,8 +188,8 @@ print_module (Dwfl_Module *mod __attribute__ ((unused)),
              Dwarf *dw, Dwarf_Addr bias,
              void *arg)
 {
-  printf ("module: %30s %08" PRIx64 " %12p %" PRIx64 " (%s)\n",
-         name, base, dw, bias, dwfl_errmsg (-1));
+  printf ("module: %30s %08" PRIx64 " %s %" PRIx64 " (%s)\n",
+         name, base, dw == NULL ? "no" : "DWARF", bias, dwfl_errmsg (-1));
 
   if (dw != NULL && *(const bool *) arg)
     {
index 40e90bec609d7f831a4faf670dfae8d29506640a..d1f6149a2407d55f8b61dee2698d4468777d6f64 100755 (executable)
@@ -29,7 +29,7 @@ testfiles testfile36 testfile36.debug
 
 testrun_compare ./dwflmodtest -e testfile36 <<\EOF
 module:                                00000000..00002308 testfile36 (null)
-module:                                00000000        (nil) 0 (Callback returned failure)
+module:                                00000000 DWARF 0 (no error)
 module:                                00000000..00002308 testfile36 testfile36.debug
 EOF
 
index 660f10703788c6aa153417d6bf2c57e2b98712d7..a0b93a25356324cb155700ff197008adb482af3b 100755 (executable)
@@ -38,4 +38,7 @@ testrun ../src/elflint -q testfile32
 testfiles testfile33
 testrun ../src/elflint -q testfile33
 
+testfiles testfile42
+testrun ../src/elflint -q --gnu-ld testfile42
+
 exit 0
diff --git a/tests/testfile42.bz2 b/tests/testfile42.bz2
new file mode 100644 (file)
index 0000000..2530aba
Binary files /dev/null and b/tests/testfile42.bz2 differ