summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--backends/ChangeLog11
-rw-r--r--backends/i386_corenote.c4
-rw-r--r--backends/linux-core-note.c33
-rw-r--r--backends/ppc_corenote.c13
-rw-r--r--backends/ppc_regs.c10
-rw-r--r--libdw/ChangeLog19
-rw-r--r--libdw/dwarf_child.c11
-rw-r--r--libdw/dwarf_formref.c22
-rw-r--r--libdw/dwarf_formref_die.c36
-rw-r--r--libdw/dwarf_siblingof.c4
-rw-r--r--libdw/libdw.h8
-rw-r--r--libdw/libdwP.h7
-rw-r--r--libdw/libdw_findcu.c13
-rw-r--r--libdw/libdw_form.c7
-rw-r--r--libdwfl/ChangeLog92
-rw-r--r--libdwfl/derelocate.c73
-rw-r--r--libdwfl/dwfl_module.c10
-rw-r--r--libdwfl/dwfl_module_build_id.c6
-rw-r--r--libdwfl/dwfl_module_getdwarf.c32
-rw-r--r--libdwfl/dwfl_module_getsym.c7
-rw-r--r--libdwfl/dwfl_report_elf.c88
-rw-r--r--libdwfl/libdwflP.h16
-rw-r--r--libdwfl/linux-kernel-modules.c23
-rw-r--r--libdwfl/offline.c77
-rw-r--r--libdwfl/relocate.c647
-rw-r--r--libebl/ChangeLog4
-rw-r--r--libebl/eblcorenotetypename.c18
-rw-r--r--libelf/ChangeLog4
-rw-r--r--libelf/elf.h23
-rw-r--r--src/ChangeLog28
-rw-r--r--src/readelf.c112
-rw-r--r--src/unstrip.c80
-rw-r--r--tests/ChangeLog21
-rw-r--r--tests/Makefile.am5
-rw-r--r--tests/dwfl-addr-sect.c13
-rwxr-xr-xtests/run-allregs.sh6
-rwxr-xr-xtests/run-dwfl-addr-sect.sh37
-rw-r--r--tests/test-subr.sh4
-rw-r--r--tests/testfile43.bz2bin0 -> 739 bytes
39 files changed, 1231 insertions, 393 deletions
diff --git a/backends/ChangeLog b/backends/ChangeLog
index 082f4f39..2bb61f2b 100644
--- a/backends/ChangeLog
+++ b/backends/ChangeLog
@@ -1,3 +1,14 @@
+2007-10-18 Roland McGrath <roland@redhat.com>
+
+ * ppc_regs.c (ppc_register_info): Assign 67 to "vscr".
+ Return "vector" and 32 bits for vscr and vrsave.
+ * ppc_corenote.c (altivec_regs): New variable.
+ (EXTRA_NOTES): New macro, handle NT_PPC_VMX.
+
+ * linux-core-note.c (EXTRA_REGSET): New macro.
+ Remove NT_PRXFPREG case. Instead, use EXTRA_NOTES if defined.
+ * i386_corenote.c (EXTRA_NOTES): Define it.
+
2007-10-09 Roland McGrath <roland@redhat.com>
* sparc_auxv.c: New file.
diff --git a/backends/i386_corenote.c b/backends/i386_corenote.c
index cc72a45f..f6c4c1de 100644
--- a/backends/i386_corenote.c
+++ b/backends/i386_corenote.c
@@ -99,6 +99,8 @@ static const Ebl_Register_Location prxfpreg_regs[] =
{ .offset = 32, .regno = 11, .count = 8, .bits = 80, .pad = 6 }, /* stN */
{ .offset = 32 + 128, .regno = 21, .count = 8, .bits = 128 }, /* xmm */
};
-#define PRXFPREG_SIZE 512
+
+#define EXTRA_NOTES \
+ EXTRA_REGSET (NT_PRFPXREG, 512, prxfpreg_regs)
#include "linux-core-note.c"
diff --git a/backends/linux-core-note.c b/backends/linux-core-note.c
index c4a90b70..3dc41373 100644
--- a/backends/linux-core-note.c
+++ b/backends/linux-core-note.c
@@ -198,28 +198,23 @@ EBLHOOK(core_note) (n_type, descsz,
*items = prpsinfo_items;
return 1;
-#ifdef FPREGSET_SIZE
- case NT_FPREGSET:
- if (descsz != FPREGSET_SIZE)
- return 0;
- *regs_offset = 0;
- *nregloc = sizeof fpregset_regs / sizeof fpregset_regs[0];
- *reglocs = fpregset_regs;
- *nitems = 0;
- *items = NULL;
+#define EXTRA_REGSET(type, size, table) \
+ case type: \
+ if (descsz != size) \
+ return 0; \
+ *regs_offset = 0; \
+ *nregloc = sizeof table / sizeof table[0]; \
+ *reglocs = table; \
+ *nitems = 0; \
+ *items = NULL; \
return 1;
+
+#ifdef FPREGSET_SIZE
+ EXTRA_REGSET (NT_FPREGSET, FPREGSET_SIZE, fpregset_regs)
#endif
-#ifdef PRXFPREG_SIZE
- case NT_PRXFPREG:
- if (descsz != PRXFPREG_SIZE)
- return 0;
- *regs_offset = 0;
- *nregloc = sizeof prxfpreg_regs / sizeof prxfpreg_regs[0];
- *reglocs = prxfpreg_regs;
- *nitems = 0;
- *items = NULL;
- return 1;
+#ifdef EXTRA_NOTES
+ EXTRA_NOTES
#endif
}
diff --git a/backends/ppc_corenote.c b/backends/ppc_corenote.c
index e9ff124c..daadbb48 100644
--- a/backends/ppc_corenote.c
+++ b/backends/ppc_corenote.c
@@ -71,6 +71,19 @@ static const Ebl_Register_Location fpregset_regs[] =
};
#define FPREGSET_SIZE (33 * 8)
+static const Ebl_Register_Location altivec_regs[] =
+ {
+ /* vr0-vr31 */
+ { .offset = 0, .regno = 1124, .count = 32, .bits = 128 },
+ /* vscr XXX 67 is an unofficial assignment */
+ { .offset = 32 * 16, .regno = 67, .count = 1, .bits = 32, .pad = 12 },
+ /* vrsave */
+ { .offset = 33 * 16, .regno = 356, .count = 1, .bits = 32, .pad = 12 }
+ };
+
+#define EXTRA_NOTES \
+ EXTRA_REGSET (NT_PPC_VMX, 34 * 16, altivec_regs)
+
#if BITS == 32
# define ULONG uint32_t
# define ALIGN_ULONG 4
diff --git a/backends/ppc_regs.c b/backends/ppc_regs.c
index 4cf5abc6..cc7d84fa 100644
--- a/backends/ppc_regs.c
+++ b/backends/ppc_regs.c
@@ -58,13 +58,13 @@ ppc_register_info (Ebl *ebl __attribute__ ((unused)),
if (ebl->machine != EM_PPC64 && regno < 64)
*bits = 64;
}
- else if (regno < 1124)
- *setname = "privileged";
- else
+ else if (regno == 67 || regno == 356 || regno >= 1124)
{
*setname = "vector";
- *bits = 128;
+ *bits = regno >= 1124 ? 128 : 32;
}
+ else
+ *setname = "privileged";
switch (regno)
{
@@ -100,6 +100,8 @@ ppc_register_info (Ebl *ebl __attribute__ ((unused)),
return stpcpy (name, "fpscr") + 1 - name;
case 66:
return stpcpy (name, "msr") + 1 - name;
+ case 67: /* XXX unofficial assignment */
+ return stpcpy (name, "vscr") + 1 - name;
case 70 + 0 ... 70 + 9:
name[0] = 's';
diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index d21f5d64..b7cd6285 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,22 @@
+2007-10-17 Roland McGrath <roland@redhat.com>
+
+ * libdw.h (__deprecated_attribute__): New macro.
+ (dwarf_formref): Mark it deprecated.
+ * dwarf_formref.c (__libdw_formref): New function, broken out of ...
+ (dwarf_formref): ... here. Call it. Remove INTDEF.
+ * libdwP.h: Remove INTDECL.
+ Declare __libdw_formref.
+ * dwarf_siblingof.c (dwarf_siblingof): Call __libdw_formref instead.
+ * dwarf_formref_die.c: Likewise. Handle DW_FORM_ref_addr here.
+
+ * libdw_form.c (__libdw_form_val_len): Fix DW_FORM_ref_addr result,
+ needs to check CU->version.
+
+ * libdwP.h (struct Dwarf_CU): New member `version'.
+ * libdw_findcu.c (__libdw_findcu): Initialize it.
+
+ * dwarf_child.c: Return 1 for null entry as first child.
+
2007-10-05 Roland McGrath <roland@redhat.com>
* dwarf_begin_elf.c (check_section): Punt on SHT_NOBITS sections.
diff --git a/libdw/dwarf_child.c b/libdw/dwarf_child.c
index 42b38137..b22b010e 100644
--- a/libdw/dwarf_child.c
+++ b/libdw/dwarf_child.c
@@ -1,5 +1,5 @@
/* Return vhild of current DIE.
- Copyright (C) 2003, 2004, 2005, 2006 Red Hat, Inc.
+ Copyright (C) 2003, 2004, 2005, 2006, 2007 Red Hat, Inc.
This file is part of Red Hat elfutils.
Written by Ulrich Drepper <drepper@redhat.com>, 2003.
@@ -177,6 +177,15 @@ dwarf_child (die, result)
if (addr == NULL)
return -1;
+ /* It's kosher (just suboptimal) to have a null entry first thing (7.5.3).
+ So if this starts with ULEB128 of 0 (even with silly encoding of 0),
+ it is a kosher null entry and we do not really have any children. */
+ const unsigned char *code = addr;
+ while (unlikely (*code == 0x80))
+ ++code;
+ if (unlikely (*code == '\0'))
+ return 1;
+
/* RESULT can be the same as DIE. So preserve what we need. */
struct Dwarf_CU *cu = die->cu;
diff --git a/libdw/dwarf_formref.c b/libdw/dwarf_formref.c
index ac905c82..7c4fb71a 100644
--- a/libdw/dwarf_formref.c
+++ b/libdw/dwarf_formref.c
@@ -1,5 +1,5 @@
/* Return reference offset represented by attribute.
- Copyright (C) 2003, 2005 Red Hat, Inc.
+ Copyright (C) 2003, 2005, 2007 Red Hat, Inc.
This file is part of Red Hat elfutils.
Written by Ulrich Drepper <drepper@redhat.com>, 2003.
@@ -55,15 +55,11 @@
#include <dwarf.h>
#include "libdwP.h"
-
int
-dwarf_formref (attr, return_offset)
+__libdw_formref (attr, return_offset)
Dwarf_Attribute *attr;
Dwarf_Off *return_offset;
{
- if (attr == NULL)
- return -1;
-
const unsigned char *datap;
switch (attr->form)
@@ -100,4 +96,16 @@ dwarf_formref (attr, return_offset)
return 0;
}
-INTDEF(dwarf_formref)
+
+/* This is the old public entry point.
+ It is now deprecated in favor of dwarf_formref_die. */
+int
+dwarf_formref (attr, return_offset)
+ Dwarf_Attribute *attr;
+ Dwarf_Off *return_offset;
+{
+ if (attr == NULL)
+ return -1;
+
+ return __libdw_formref (attr, return_offset);
+}
diff --git a/libdw/dwarf_formref_die.c b/libdw/dwarf_formref_die.c
index 18ffe2fb..90a4b2d3 100644
--- a/libdw/dwarf_formref_die.c
+++ b/libdw/dwarf_formref_die.c
@@ -1,5 +1,5 @@
/* Look up the DIE in a reference-form attribute.
- 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
@@ -52,13 +52,39 @@
#endif
#include "libdwP.h"
+#include <dwarf.h>
+
Dwarf_Die *
-dwarf_formref_die (Dwarf_Attribute *attr, Dwarf_Die *die_mem)
+dwarf_formref_die (attr, die_mem)
+ Dwarf_Attribute *attr;
+ Dwarf_Die *die_mem;
{
+ if (attr == NULL)
+ return NULL;
+
Dwarf_Off offset;
- return (unlikely (INTUSE(dwarf_formref) (attr, &offset) != 0) ? NULL
- : INTUSE(dwarf_offdie) (attr->cu->dbg, attr->cu->start + offset,
- die_mem));
+ if (attr->form == DW_FORM_ref_addr)
+ {
+ /* This has an absolute offset. */
+
+ uint8_t ref_size = (attr->cu->version == 2
+ ? attr->cu->address_size
+ : attr->cu->offset_size);
+
+ if (ref_size == 8)
+ offset = read_8ubyte_unaligned (attr->cu->dbg, attr->valp);
+ else
+ offset = read_4ubyte_unaligned (attr->cu->dbg, attr->valp);
+ }
+ else
+ {
+ /* Other forms produce an offset from the CU. */
+ if (unlikely (__libdw_formref (attr, &offset) != 0))
+ return NULL;
+ offset += attr->cu->start;
+ }
+
+ return INTUSE(dwarf_offdie) (attr->cu->dbg, offset, die_mem);
}
INTDEF (dwarf_formref_die)
diff --git a/libdw/dwarf_siblingof.c b/libdw/dwarf_siblingof.c
index 00e5a1c7..a6cca394 100644
--- a/libdw/dwarf_siblingof.c
+++ b/libdw/dwarf_siblingof.c
@@ -1,5 +1,5 @@
/* Return sibling of given DIE.
- Copyright (C) 2003, 2004, 2005 Red Hat, Inc.
+ Copyright (C) 2003, 2004, 2005, 2007 Red Hat, Inc.
This file is part of Red Hat elfutils.
Written by Ulrich Drepper <drepper@redhat.com>, 2003.
@@ -92,7 +92,7 @@ dwarf_siblingof (die, result)
{
Dwarf_Off offset;
sibattr.valp = addr;
- if (INTUSE(dwarf_formref) (&sibattr, &offset) != 0)
+ if (__libdw_formref (&sibattr, &offset) != 0)
/* Something went wrong. */
return -1;
diff --git a/libdw/libdw.h b/libdw/libdw.h
index 70a35b04..6242d04f 100644
--- a/libdw/libdw.h
+++ b/libdw/libdw.h
@@ -57,10 +57,13 @@
#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)
# define __nonnull_attribute__(...) __attribute__ ((__nonnull__ (__VA_ARGS__)))
+# define __deprecated_attribute__ __attribute__ ((__deprecated__))
#else
# define __nonnull_attribute__(args...)
+# define __deprecated_attribute__
#endif
+
#ifdef __GNUC_STDC_INLINE__
# define __libdw_extern_inline extern __inline __attribute__ ((__gnu_inline__))
#else
@@ -310,9 +313,10 @@ extern int dwarf_formsdata (Dwarf_Attribute *attr, Dwarf_Sword *return_uval)
extern int dwarf_formaddr (Dwarf_Attribute *attr, Dwarf_Addr *return_addr)
__nonnull_attribute__ (2);
-/* Return reference offset represented by attribute. */
+/* This function is deprecated. Always use dwarf_formref_die instead.
+ Return reference offset represented by attribute. */
extern int dwarf_formref (Dwarf_Attribute *attr, Dwarf_Off *return_offset)
- __nonnull_attribute__ (2);
+ __nonnull_attribute__ (2) __deprecated_attribute__;
/* Look up the DIE in a reference-form attribute. */
extern Dwarf_Die *dwarf_formref_die (Dwarf_Attribute *attr, Dwarf_Die *die_mem)
diff --git a/libdw/libdwP.h b/libdw/libdwP.h
index f069075b..78fd5ce7 100644
--- a/libdw/libdwP.h
+++ b/libdw/libdwP.h
@@ -267,6 +267,7 @@ struct Dwarf_CU
Dwarf_Off end;
uint8_t address_size;
uint8_t offset_size;
+ uint16_t version;
/* Hash table for the abbreviations. */
Dwarf_Abbrev_Hash abbrev_hash;
@@ -365,6 +366,11 @@ extern size_t __libdw_form_val_len (Dwarf *dbg, struct Dwarf_CU *cu,
const unsigned char *valp)
__nonnull_attribute__ (1, 2, 4) internal_function;
+/* Helper function for DW_FORM_ref* handling. */
+extern int __libdw_formref (Dwarf_Attribute *attr, Dwarf_Off *return_offset)
+ __nonnull_attribute__ (1, 2) internal_function;
+
+
/* Helper function to locate attribute. */
extern unsigned char *__libdw_find_attr (Dwarf_Die *die,
unsigned int search_name,
@@ -411,7 +417,6 @@ INTDECL (dwarf_entrypc)
INTDECL (dwarf_errmsg)
INTDECL (dwarf_formaddr)
INTDECL (dwarf_formblock)
-INTDECL (dwarf_formref)
INTDECL (dwarf_formref_die)
INTDECL (dwarf_formsdata)
INTDECL (dwarf_formstring)
diff --git a/libdw/libdw_findcu.c b/libdw/libdw_findcu.c
index e6259d49..afff6d3a 100644
--- a/libdw/libdw_findcu.c
+++ b/libdw/libdw_findcu.c
@@ -1,5 +1,5 @@
/* Find CU for given offset.
- Copyright (C) 2003, 2004, 2005 Red Hat, Inc.
+ Copyright (C) 2003, 2004, 2005, 2007 Red Hat, Inc.
This file is part of Red Hat elfutils.
Written by Ulrich Drepper <drepper@redhat.com>, 2003.
@@ -97,6 +97,7 @@ __libdw_findcu (dbg, start)
if (start < dbg->next_cu_offset)
{
+ invalid:
__libdw_seterrno (DWARF_E_INVALID_DWARF);
return NULL;
}
@@ -115,6 +116,15 @@ __libdw_findcu (dbg, start)
/* No more entries. */
return NULL;
+ /* XXX We need the version number but dwarf_nextcu swallows it. */
+ const char *bytes = (dbg->sectiondata[IDX_debug_info]->d_buf + oldoff
+ + (2 * offset_size - 4));
+ uint16_t version = read_2ubyte_unaligned (dbg, bytes);
+
+ /* We only know how to handle the DWARF version 2 and 3 formats. */
+ if (unlikely (version != 2) && unlikely (version != 3))
+ goto invalid;
+
/* Create an entry for this CU. */
struct Dwarf_CU *newp = libdw_typed_alloc (dbg, struct Dwarf_CU);
@@ -123,6 +133,7 @@ __libdw_findcu (dbg, start)
newp->end = dbg->next_cu_offset;
newp->address_size = address_size;
newp->offset_size = offset_size;
+ newp->version = version;
Dwarf_Abbrev_Hash_init (&newp->abbrev_hash, 41);
newp->orig_abbrev_offset = newp->last_abbrev_offset = abbrev_offset;
newp->lines = NULL;
diff --git a/libdw/libdw_form.c b/libdw/libdw_form.c
index 779b6c0e..ad78f4b4 100644
--- a/libdw/libdw_form.c
+++ b/libdw/libdw_form.c
@@ -1,5 +1,5 @@
/* Helper functions for form handling.
- Copyright (C) 2003, 2004, 2006 Red Hat, Inc.
+ Copyright (C) 2003, 2004, 2006, 2007 Red Hat, Inc.
This file is part of Red Hat elfutils.
Written by Ulrich Drepper <drepper@redhat.com>, 2003.
@@ -73,8 +73,11 @@ __libdw_form_val_len (Dwarf *dbg, struct Dwarf_CU *cu, unsigned int form,
result = cu->address_size;
break;
- case DW_FORM_strp:
case DW_FORM_ref_addr:
+ result = cu->version == 2 ? cu->address_size : cu->offset_size;
+ break;
+
+ case DW_FORM_strp:
result = cu->offset_size;
break;
diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog
index 3c56f177..ea6e4e01 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -1,3 +1,95 @@
+2007-10-23 Roland McGrath <roland@redhat.com>
+
+ * linux-kernel-modules.c (report_kernel_archive): Reorder the kernel
+ module to appear first.
+
+2007-10-20 Roland McGrath <roland@redhat.com>
+
+ * offline.c (process_archive_member): Take FD argument, pass it down
+ to process_file. Return Elf_Cmd, not bool.
+ Call elf_next here, always before elf_end.
+ (process_archive): Update caller. Don't close FD here unless there
+ are no member refs.
+
+ * dwfl_module.c (free_file): Close fd only when elf_end returns zero.
+
+ * libdwflP.h (struct dwfl_file): New bool member `relocated'.
+ * dwfl_module_getdwarf.c (dwfl_module_getelf): For ET_REL, apply
+ partial relocation to one or both files.
+ (dwfl_module_getdwarf): For ET_REL, make sure extra sections'
+ relocations have been applied to the debug file if dwfl_module_getelf
+ has been used before.
+
+ * relocate.c (resolve_symbol): New function.
+ (relocate_section): Call it.
+
+ * relocate.c (relocate_getsym): Handle null MOD->symfile.
+ (relocate_section): Take new bool arg, PARTIAL. If true,
+ no error for BADRELTYPE/RELUNDEF, instead just skip them
+ and leave only those skipped relocs behind the reloc section.
+ (__libdwfl_relocate_section): Take new arg, pass it down.
+ (__libdwfl_relocate): Take new bool arg, DEBUG. If false,
+ do partial relocation on all sections.
+ * dwfl_module_getdwarf.c (load_dw): Update caller.
+ * libdwflP.h: Update decls.
+ * derelocate.c (dwfl_module_address_section): Pass new argument
+ to __libdwfl_relocate_section, true.
+
+ * derelocate.c (cache_sections): Don't cache reloc sections when
+ section_address callback is null.
+
+2007-10-19 Roland McGrath <roland@redhat.com>
+
+ * relocate.c (relocate_section): Fix fencepost error in r_offset check.
+
+ * derelocate.c (struct dwfl_relocation): Add member `relocs'.
+ (struct secref): Likewise.
+ (cache_sections): Cache the relocation section referring to each
+ section we cache, if any.
+ (dwfl_module_address_section): Use __libdwfl_relocate_section as
+ necessary.
+
+ * relocate.c (struct reloc_symtab_cache): New type.
+ (relocate_getsym): Use it instead of four arguments.
+ (__libdwfl_relocate): Update caller.
+ (relocate_section): New function, broken out of ...
+ (__libdwfl_relocate): ... here.
+ (__libdwfl_relocate_section): New function.
+ * libdwflP.h: Declare it.
+
+2007-10-17 Roland McGrath <roland@redhat.com>
+
+ * dwfl_module_getsym.c (dwfl_module_getsym): Apply MOD->symfile->bias
+ to relocated st_value.
+
+ * dwfl_report_elf.c (__libdwfl_report_elf): Align initial BASE for
+ ET_REL to 0x100.
+
+2007-10-16 Roland McGrath <roland@redhat.com>
+
+ * dwfl_report_elf.c (__libdwfl_report_elf): Readjust BASE when a later
+ section has larger alignment requirements not met by the original BASE,
+ rather than padding more between sections.
+
+ * dwfl_report_elf.c (__libdwfl_report_elf): Fix bias calculation.
+
+ * dwfl_module_build_id.c (__libdwfl_find_build_id): Apply module bias
+ to sh_addr value.
+
+ * dwfl_report_elf.c (__libdwfl_report_elf): Don't be confused by BASE
+ at zero in ET_REL case. Adjust BASE to necessary alignment.
+
+ * dwfl_module_build_id.c (check_notes): Take -1, not 0, as stub value
+ for DATA_VADDR.
+ (__libdwfl_find_build_id): Update caller.
+
+ * relocate.c (__libdwfl_relocate_value): Don't use sh_offset.
+ * dwfl_report_elf.c (__libdwfl_report_elf): Likewise.
+ * offline.c (dwfl_offline_section_address): Bail early if there is
+ separate debug file.
+
+ * relocate.c (__libdwfl_relocate): Don't return DWFL_E_NO_DWARF.
+
2007-10-09 Roland McGrath <roland@redhat.com>
* dwfl_report_elf.c (__libdwfl_report_elf): Clear SHDR->sh_offset when
diff --git a/libdwfl/derelocate.c b/libdwfl/derelocate.c
index 6da999d3..0877276d 100644
--- a/libdwfl/derelocate.c
+++ b/libdwfl/derelocate.c
@@ -55,6 +55,7 @@ struct dwfl_relocation
struct
{
Elf_Scn *scn;
+ Elf_Scn *relocs;
const char *name;
GElf_Addr start, end;
} refs[0];
@@ -65,6 +66,7 @@ struct secref
{
struct secref *next;
Elf_Scn *scn;
+ Elf_Scn *relocs;
const char *name;
GElf_Addr start, end;
};
@@ -99,6 +101,7 @@ cache_sections (Dwfl_Module *mod)
return -1;
}
+ bool check_reloc_sections = false;
Elf_Scn *scn = NULL;
while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL)
{
@@ -128,6 +131,7 @@ cache_sections (Dwfl_Module *mod)
struct secref *newref = alloca (sizeof *newref);
newref->scn = scn;
+ newref->relocs = NULL;
newref->name = name;
newref->start = shdr->sh_addr + mod->main.bias;
newref->end = newref->start + shdr->sh_size;
@@ -135,6 +139,28 @@ cache_sections (Dwfl_Module *mod)
refs = newref;
++nrefs;
}
+
+ if (mod->e_type == ET_REL
+ && shdr->sh_size != 0
+ && (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA)
+ && mod->dwfl->callbacks->section_address != NULL)
+ {
+ if (shdr->sh_info < elf_ndxscn (scn))
+ {
+ /* We've already looked at the section these relocs apply to. */
+ Elf_Scn *tscn = elf_getscn (mod->main.elf, shdr->sh_info);
+ if (likely (tscn != NULL))
+ for (struct secref *sec = refs; sec != NULL; sec = sec->next)
+ if (sec->scn == tscn)
+ {
+ sec->relocs = scn;
+ break;
+ }
+ }
+ else
+ /* We'll have to do a second pass. */
+ check_reloc_sections = true;
+ }
}
mod->reloc_info = malloc (offsetof (struct dwfl_relocation, refs[nrefs]));
@@ -156,10 +182,40 @@ cache_sections (Dwfl_Module *mod)
{
mod->reloc_info->refs[i].name = sortrefs[i]->name;
mod->reloc_info->refs[i].scn = sortrefs[i]->scn;
+ mod->reloc_info->refs[i].relocs = sortrefs[i]->relocs;
mod->reloc_info->refs[i].start = sortrefs[i]->start;
mod->reloc_info->refs[i].end = sortrefs[i]->end;
}
+ if (unlikely (check_reloc_sections))
+ {
+ /* There was a reloc section that preceded its target section.
+ So we have to scan again now that we have cached all the
+ possible target sections we care about. */
+
+ scn = NULL;
+ while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL)
+ {
+ GElf_Shdr shdr_mem;
+ GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
+ if (shdr == NULL)
+ goto elf_error;
+
+ if (shdr->sh_size != 0
+ && (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA))
+ {
+ Elf_Scn *tscn = elf_getscn (mod->main.elf, shdr->sh_info);
+ if (likely (tscn != NULL))
+ for (size_t i = 0; i < nrefs; ++i)
+ if (mod->reloc_info->refs[i].scn == tscn)
+ {
+ mod->reloc_info->refs[i].relocs = scn;
+ break;
+ }
+ }
+ }
+ }
+
return nrefs;
}
@@ -321,6 +377,23 @@ dwfl_module_address_section (Dwfl_Module *mod, Dwarf_Addr *address,
if (idx < 0)
return NULL;
+ if (mod->reloc_info->refs[idx].relocs != NULL)
+ {
+ assert (mod->e_type == ET_REL);
+
+ Elf_Scn *tscn = mod->reloc_info->refs[idx].scn;
+ Elf_Scn *relocscn = mod->reloc_info->refs[idx].relocs;
+ Dwfl_Error result = __libdwfl_relocate_section (mod, mod->main.elf,
+ relocscn, tscn, true);
+ if (likely (result == DWFL_E_NOERROR))
+ mod->reloc_info->refs[idx].relocs = NULL;
+ else
+ {
+ __libdwfl_seterrno (result);
+ return NULL;
+ }
+ }
+
*bias = mod->main.bias;
return mod->reloc_info->refs[idx].scn;
}
diff --git a/libdwfl/dwfl_module.c b/libdwfl/dwfl_module.c
index 4cee37c2..434f3ff9 100644
--- a/libdwfl/dwfl_module.c
+++ b/libdwfl/dwfl_module.c
@@ -68,12 +68,10 @@ static void
free_file (struct dwfl_file *file)
{
free (file->name);
- if (file->elf != NULL)
- {
- elf_end (file->elf);
- if (file->fd != -1)
- close (file->fd);
- }
+
+ /* Close the fd only on the last reference. */
+ if (file->elf != NULL && elf_end (file->elf) == 0 && file->fd != -1)
+ close (file->fd);
}
void
diff --git a/libdwfl/dwfl_module_build_id.c b/libdwfl/dwfl_module_build_id.c
index f9a6357f..903b79c5 100644
--- a/libdwfl/dwfl_module_build_id.c
+++ b/libdwfl/dwfl_module_build_id.c
@@ -73,6 +73,8 @@ found_build_id (Dwfl_Module *mod, bool set,
return len;
}
+#define NO_VADDR ((GElf_Addr) -1l)
+
static int
check_notes (Dwfl_Module *mod, bool set, Elf_Data *data, GElf_Addr data_vaddr)
{
@@ -86,7 +88,7 @@ check_notes (Dwfl_Module *mod, bool set, Elf_Data *data, GElf_Addr data_vaddr)
"GNU", sizeof "GNU"))
return found_build_id (mod, set,
data->d_buf + desc_pos, nhdr.n_descsz,
- data_vaddr == 0 ? 0 : data_vaddr + pos);
+ data_vaddr == NO_VADDR ? 0 : data_vaddr + pos);
return 0;
}
@@ -129,7 +131,7 @@ __libdwfl_find_build_id (Dwfl_Module *mod, bool set, Elf *elf)
if (likely (shdr != NULL) && shdr->sh_type == SHT_NOTE)
result = check_notes (mod, set, elf_getdata (scn, NULL),
(shdr->sh_flags & SHF_ALLOC)
- ? shdr->sh_addr : 0);
+ ? shdr->sh_addr + mod->main.bias : NO_VADDR);
}
while (result == 0 && (scn = elf_nextscn (elf, scn)) != NULL);
diff --git a/libdwfl/dwfl_module_getdwarf.c b/libdwfl/dwfl_module_getdwarf.c
index 0f26e5dc..775df731 100644
--- a/libdwfl/dwfl_module_getdwarf.c
+++ b/libdwfl/dwfl_module_getdwarf.c
@@ -600,7 +600,7 @@ load_dw (Dwfl_Module *mod, struct dwfl_file *debugfile)
find_symtab (mod);
Dwfl_Error result = mod->symerr;
if (result == DWFL_E_NOERROR)
- result = __libdwfl_relocate (mod, debugfile->elf);
+ result = __libdwfl_relocate (mod, debugfile->elf, true);
if (result != DWFL_E_NOERROR)
return result;
@@ -689,6 +689,26 @@ dwfl_module_getelf (Dwfl_Module *mod, GElf_Addr *loadbase)
find_file (mod);
if (mod->elferr == DWFL_E_NOERROR)
{
+ if (mod->e_type == ET_REL && ! mod->main.relocated)
+ {
+ /* Before letting them get at the Elf handle,
+ apply all the relocations we know how to. */
+
+ mod->main.relocated = true;
+ if (likely (__libdwfl_module_getebl (mod) == DWFL_E_NOERROR))
+ {
+ (void) __libdwfl_relocate (mod, mod->main.elf, false);
+
+ if (mod->debug.elf == mod->main.elf)
+ mod->debug.relocated = true;
+ else if (mod->debug.elf != NULL && ! mod->debug.relocated)
+ {
+ mod->debug.relocated = true;
+ (void) __libdwfl_relocate (mod, mod->debug.elf, false);
+ }
+ }
+ }
+
*loadbase = mod->main.bias;
return mod->main.elf;
}
@@ -708,6 +728,16 @@ dwfl_module_getdwarf (Dwfl_Module *mod, Dwarf_Addr *bias)
find_dw (mod);
if (mod->dwerr == DWFL_E_NOERROR)
{
+ /* If dwfl_module_getelf was used previously, then partial apply
+ relocation to miscellaneous sections in the debug file too. */
+ if (mod->e_type == ET_REL
+ && mod->main.relocated && ! mod->debug.relocated)
+ {
+ mod->debug.relocated = true;
+ if (mod->debug.elf != mod->main.elf)
+ (void) __libdwfl_relocate (mod, mod->debug.elf, false);
+ }
+
*bias = mod->debug.bias;
return mod->dw;
}
diff --git a/libdwfl/dwfl_module_getsym.c b/libdwfl/dwfl_module_getsym.c
index 04432a43..5f289ccb 100644
--- a/libdwfl/dwfl_module_getsym.c
+++ b/libdwfl/dwfl_module_getsym.c
@@ -85,10 +85,7 @@ dwfl_module_getsym (Dwfl_Module *mod, int ndx,
break;
default:
- if (mod->e_type != ET_REL)
- /* Apply the bias to the symbol value. */
- sym->st_value += mod->symfile->bias;
- else
+ if (mod->e_type == ET_REL)
{
/* In an ET_REL file, the symbol table values are relative
to the section, not to the module's load base. */
@@ -102,6 +99,8 @@ dwfl_module_getsym (Dwfl_Module *mod, int ndx,
return NULL;
}
}
+ /* Apply the bias to the symbol value. */
+ sym->st_value += mod->symfile->bias;
break;
}
diff --git a/libdwfl/dwfl_report_elf.c b/libdwfl/dwfl_report_elf.c
index 905ddd12..0e5d09bc 100644
--- a/libdwfl/dwfl_report_elf.c
+++ b/libdwfl/dwfl_report_elf.c
@@ -51,6 +51,14 @@
#include <fcntl.h>
#include <unistd.h>
+
+/* We start every ET_REL module at a moderately aligned boundary.
+ This keeps the low addresses easy to read compared to a layout
+ starting at 0 (as when using -e). It also makes it unlikely
+ that a middle section will have a larger alignment and require
+ rejiggering (see below). */
+#define REL_MIN_ALIGN ((GElf_Xword) 0x100)
+
Dwfl_Module *
internal_function
__libdwfl_report_elf (Dwfl *dwfl, const char *name, const char *file_name,
@@ -72,41 +80,91 @@ __libdwfl_report_elf (Dwfl *dwfl, const char *name, const char *file_name,
By updating the section header in place, we leave the layout
information to be found by relocation. */
- start = end = base;
+ start = end = base = (base + REL_MIN_ALIGN - 1) & -REL_MIN_ALIGN;
+ bool first = true;
Elf_Scn *scn = NULL;
while ((scn = elf_nextscn (elf, scn)) != NULL)
{
GElf_Shdr shdr_mem;
GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
- if (shdr == NULL)
+ if (unlikely (shdr == NULL))
goto elf_error;
if (shdr->sh_flags & SHF_ALLOC)
{
const GElf_Xword align = shdr->sh_addralign ?: 1;
- if (shdr->sh_addr == 0 || (bias == 0 && end > start))
+ const GElf_Addr next = (end + align - 1) & -align;
+ if (shdr->sh_addr == 0
+ /* Once we've started doing layout we have to do it all,
+ unless we just layed out the first section at 0 when
+ it already was at 0. */
+ || (bias == 0 && end > start && end != next))
{
- shdr->sh_addr = (end + align - 1) & -align;
+ shdr->sh_addr = next;
if (end == base)
/* This is the first section assigned a location.
Use its aligned address as the module's base. */
- start = shdr->sh_addr;
+ start = base = shdr->sh_addr;
+ else if (unlikely (base & (align - 1)))
+ {
+ /* If BASE has less than the maximum alignment of
+ any section, we eat more than the optimal amount
+ of padding and so make the module's apparent
+ size come out larger than it would when placed
+ at zero. So reset the layout with a better base. */
+
+ start = end = base = (base + align - 1) & -align;
+ Elf_Scn *prev_scn = NULL;
+ do
+ {
+ prev_scn = elf_nextscn (elf, prev_scn);
+ GElf_Shdr prev_shdr_mem;
+ GElf_Shdr *prev_shdr = gelf_getshdr (prev_scn,
+ &prev_shdr_mem);
+ if (unlikely (prev_shdr == NULL))
+ goto elf_error;
+ if (prev_shdr->sh_flags & SHF_ALLOC)
+ {
+ const GElf_Xword prev_align
+ = prev_shdr->sh_addralign ?: 1;
+
+ prev_shdr->sh_addr
+ = (end + prev_align - 1) & -prev_align;
+ end = prev_shdr->sh_addr + prev_shdr->sh_size;
+
+ if (unlikely (! gelf_update_shdr (prev_scn,
+ prev_shdr)))
+ goto elf_error;
+ }
+ }
+ while (prev_scn != scn);
+ continue;
+ }
+
end = shdr->sh_addr + shdr->sh_size;
- if (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))
+ if (likely (shdr->sh_addr != 0)
+ && unlikely (! gelf_update_shdr (scn, shdr)))
goto elf_error;
}
else
{
- if (bias == 0 || end < shdr->sh_addr + shdr->sh_size)
+ /* The address is already assigned. Just track it. */
+ if (first || end < shdr->sh_addr + shdr->sh_size)
end = shdr->sh_addr + shdr->sh_size;
- if (bias == 0 || bias > shdr->sh_addr)
+ if (first || bias > shdr->sh_addr)
+ /* This is the lowest address in the module. */
bias = shdr->sh_addr;
+
+ if ((shdr->sh_addr - bias + base) & (align - 1))
+ /* This section winds up misaligned using BASE.
+ Adjust BASE upwards to make it congruent to
+ the lowest section address in the file modulo ALIGN. */
+ base = (((base + align - 1) & -align)
+ + (bias & (align - 1)));
}
+
+ first = false;
}
}
@@ -117,7 +175,7 @@ __libdwfl_report_elf (Dwfl *dwfl, const char *name, const char *file_name,
Now just compute the bias from the requested base. */
start = base;
end = end - bias + start;
- bias -= start;
+ bias = start - bias;
}
break;
@@ -133,7 +191,7 @@ __libdwfl_report_elf (Dwfl *dwfl, const char *name, const char *file_name,
for (uint_fast16_t i = 0; i < ehdr->e_phnum; ++i)
{
GElf_Phdr phdr_mem, *ph = gelf_getphdr (elf, i, &phdr_mem);
- if (ph == NULL)
+ if (unlikely (ph == NULL))
goto elf_error;
if (ph->p_type == PT_LOAD)
{
@@ -148,7 +206,7 @@ __libdwfl_report_elf (Dwfl *dwfl, const char *name, const char *file_name,
for (uint_fast16_t i = ehdr->e_phnum; i-- > 0;)
{
GElf_Phdr phdr_mem, *ph = gelf_getphdr (elf, i, &phdr_mem);
- if (ph == NULL)
+ if (unlikely (ph == NULL))
goto elf_error;
if (ph->p_type == PT_LOAD)
{
diff --git a/libdwfl/libdwflP.h b/libdwfl/libdwflP.h
index e75a3ab6..bbb56aac 100644
--- a/libdwfl/libdwflP.h
+++ b/libdwfl/libdwflP.h
@@ -121,6 +121,7 @@ struct dwfl_file
char *name;
int fd;
bool valid; /* The build ID note has been matched. */
+ bool relocated; /* Partial relocation of all sections done. */
Elf *elf;
GElf_Addr bias; /* Actual load address - p_vaddr. */
@@ -227,11 +228,20 @@ extern void __libdwfl_module_free (Dwfl_Module *mod) internal_function;
/* Process relocations in debugging sections in an ET_REL file.
- DEBUGFILE must be opened with ELF_C_READ_MMAP_PRIVATE or ELF_C_READ,
+ FILE must be opened with ELF_C_READ_MMAP_PRIVATE or ELF_C_READ,
to make it possible to relocate the data in place (or ELF_C_RDWR or
ELF_C_RDWR_MMAP if you intend to modify the Elf file on disk). After
- this, dwarf_begin_elf on DEBUGFILE will read the relocated data. */
-extern Dwfl_Error __libdwfl_relocate (Dwfl_Module *mod, Elf *debugfile)
+ this, dwarf_begin_elf on FILE will read the relocated data.
+
+ When DEBUG is false, apply partial relocation to all sections. */
+extern Dwfl_Error __libdwfl_relocate (Dwfl_Module *mod, Elf *file, bool debug)
+ internal_function;
+
+/* Process (simple) relocations in arbitrary section TSCN of an ET_REL file.
+ RELOCSCN is SHT_REL or SHT_RELA and TSCN is its sh_info target section. */
+extern Dwfl_Error __libdwfl_relocate_section (Dwfl_Module *mod, Elf *relocated,
+ Elf_Scn *relocscn, Elf_Scn *tscn,
+ bool partial)
internal_function;
/* Adjust *VALUE from section-relative to absolute.
diff --git a/libdwfl/linux-kernel-modules.c b/libdwfl/linux-kernel-modules.c
index c15e0896..b113806e 100644
--- a/libdwfl/linux-kernel-modules.c
+++ b/libdwfl/linux-kernel-modules.c
@@ -226,9 +226,26 @@ report_kernel_archive (Dwfl *dwfl, const char **release,
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;
+ {
+ /* We have the archive file open! */
+ Dwfl_Module *last = __libdwfl_report_offline (dwfl, NULL, archive, fd,
+ true, predicate);
+ if (unlikely (last == NULL))
+ result = -1;
+ else
+ {
+ /* Find the kernel and move it to the head of the list. */
+ Dwfl_Module **tailp = &dwfl->modulelist, **prevp = tailp;
+ for (Dwfl_Module *m = *prevp; m != NULL; m = *(prevp = &m->next))
+ if (!m->gc && m->e_type != ET_REL && !strcmp (m->name, "kernel"))
+ {
+ *prevp = m->next;
+ m->next = *tailp;
+ *tailp = m;
+ break;
+ }
+ }
+ }
free (archive);
return result;
diff --git a/libdwfl/offline.c b/libdwfl/offline.c
index 916d263e..ff7b793a 100644
--- a/libdwfl/offline.c
+++ b/libdwfl/offline.c
@@ -53,8 +53,9 @@
/* Since dwfl_report_elf lays out the sections already, this will only be
called when the section headers of the debuginfo file are being
- consulted instead. With binutils strip-to-debug, the symbol table is in
- the debuginfo file and relocation looks there. */
+ consulted instead, or for the section placed at 0. With binutils
+ strip-to-debug, the symbol table is in the debuginfo file and relocation
+ looks there. */
int
dwfl_offline_section_address (Dwfl_Module *mod,
void **userdata __attribute__ ((unused)),
@@ -69,6 +70,11 @@ dwfl_offline_section_address (Dwfl_Module *mod,
assert (shdr->sh_addr == 0);
assert (shdr->sh_flags & SHF_ALLOC);
+ if (mod->debug.elf == NULL)
+ /* We are only here because sh_addr is zero even though layout is complete.
+ The first section in the first file under -e is placed at 0. */
+ return 0;
+
/* The section numbers might not match between the two files.
The best we can rely on is the order of SHF_ALLOC sections. */
@@ -114,7 +120,8 @@ static Dwfl_Module *process_archive (Dwfl *dwfl, const char *name,
int (*predicate) (const char *module,
const char *file));
-/* Report one module for an ELF file, or many for an archive. */
+/* Report one module for an ELF file, or many for an archive.
+ Always consumes ELF and FD. */
static Dwfl_Module *
process_file (Dwfl *dwfl, const char *name, const char *file_name, int fd,
Elf *elf, int (*predicate) (const char *module,
@@ -135,7 +142,7 @@ process_file (Dwfl *dwfl, const char *name, const char *file_name, int fd,
}
}
-/* Report the open ELF file as a module. */
+/* Report the open ELF file as a module. Always consumes ELF and FD. */
static Dwfl_Module *
process_elf (Dwfl *dwfl, const char *name, const char *file_name, int fd,
Elf *elf)
@@ -166,24 +173,30 @@ process_elf (Dwfl *dwfl, const char *name, const char *file_name, int fd,
return mod;
}
-static bool
+/* Always consumes MEMBER. Returns elf_next result on success.
+ For errors returns ELF_C_NULL with *MOD set to null. */
+static Elf_Cmd
process_archive_member (Dwfl *dwfl, const char *name, const char *file_name,
int (*predicate) (const char *module, const char *file),
- Elf *member, Dwfl_Module **mod)
+ int fd, Elf *member, Dwfl_Module **mod)
{
const Elf_Arhdr *h = elf_getarhdr (member);
if (unlikely (h == NULL))
{
__libdwfl_seterrno (DWFL_E_LIBELF);
+ fail:
elf_end (member);
*mod = NULL;
- return false;
+ return ELF_C_NULL;
}
if (!strcmp (h->ar_name, "/") || !strcmp (h->ar_name, "//"))
{
+ skip:;
+ /* Skip this and go to the next. */
+ Elf_Cmd result = elf_next (member);
elf_end (member);
- return true;
+ return result;
}
char *member_name;
@@ -193,7 +206,7 @@ process_archive_member (Dwfl *dwfl, const char *name, const char *file_name,
__libdwfl_seterrno (DWFL_E_NOMEM);
elf_end (member);
*mod = NULL;
- return false;
+ return ELF_C_NULL;
}
char *module_name = NULL;
@@ -218,18 +231,24 @@ process_archive_member (Dwfl *dwfl, const char *name, const char *file_name,
if (unlikely (want < 0))
{
__libdwfl_seterrno (DWFL_E_CB);
- elf_end (member);
- *mod = NULL;
- return false;
+ goto fail;
}
- return true;
+ goto skip;
}
}
- *mod = process_file (dwfl, name, member_name, -1, member, predicate);
+ /* We let __libdwfl_report_elf cache the fd in mod->main.fd,
+ though it's the same fd for all the members.
+ On module teardown we will close it only on the last Elf reference. */
+ *mod = process_file (dwfl, name, member_name, fd, member, predicate);
free (member_name);
free (module_name);
- return *mod != NULL;
+
+ if (*mod == NULL) /* process_file called elf_end. */
+ return ELF_C_NULL;
+
+ /* Advance the archive-reading offset for the next iteration. */
+ return elf_next (member);
}
/* Report each member of the archive as its own module. */
@@ -240,24 +259,18 @@ process_archive (Dwfl *dwfl, const char *name, const char *file_name, int fd,
{
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))
+ while (process_archive_member (dwfl, name, file_name, predicate,
+ fd, elf_begin (fd, ELF_C_READ_MMAP_PRIVATE,
+ archive), &mod) != ELF_C_NULL)
+ ;
+
+ /* We can drop the archive Elf handle even if we're still using members
+ in live modules. When the last module's elf_end on a member returns
+ zero, that module will close FD. If no modules survived the predicate,
+ we are all done with the file right here. */
+ if (elf_end (archive) == 0)
close (fd);
+
return mod;
}
diff --git a/libdwfl/relocate.c b/libdwfl/relocate.c
index e355af0c..6265f1bf 100644
--- a/libdwfl/relocate.c
+++ b/libdwfl/relocate.c
@@ -64,9 +64,7 @@ __libdwfl_relocate_value (Dwfl_Module *mod, Elf *elf, size_t *shstrndx,
if (refshdr == NULL)
return DWFL_E_LIBELF;
- if (refshdr->sh_addr == 0
- && (refshdr->sh_flags & SHF_ALLOC)
- && refshdr->sh_offset != 0)
+ if (refshdr->sh_addr == 0 && (refshdr->sh_flags & SHF_ALLOC))
{
/* This is a loaded section. Find its actual
address and update the section header. */
@@ -89,13 +87,11 @@ __libdwfl_relocate_value (Dwfl_Module *mod, Elf *elf, size_t *shstrndx,
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 (unlikely (! gelf_update_shdr (refscn, refshdr)))
+ if (likely (refshdr->sh_addr != 0)
+ && unlikely (! gelf_update_shdr (refscn, refshdr)))
return DWFL_E_LIBELF;
}
@@ -104,17 +100,31 @@ __libdwfl_relocate_value (Dwfl_Module *mod, Elf *elf, size_t *shstrndx,
return DWFL_E_NOERROR;
}
+
+/* Cache used by relocate_getsym. */
+struct reloc_symtab_cache
+{
+ Elf *symelf;
+ Elf_Data *symdata;
+ Elf_Data *symxndxdata;
+ Elf_Data *symstrdata;
+ size_t symshstrndx;
+ size_t strtabndx;
+};
+#define RELOC_SYMTAB_CACHE(cache) \
+ struct reloc_symtab_cache cache = \
+ { NULL, NULL, NULL, NULL, SHN_UNDEF, SHN_UNDEF }
+
/* This is just doing dwfl_module_getsym, except that we must always use
the symbol table in RELOCATED itself when it has one, not MOD->symfile. */
static Dwfl_Error
-relocate_getsym (Elf **symelf, Elf_Data **symdata, Elf_Data **symxndxdata,
- size_t *symshstrndx,
- Dwfl_Module *mod, Elf *relocated,
+relocate_getsym (Dwfl_Module *mod,
+ Elf *relocated, struct reloc_symtab_cache *cache,
int symndx, GElf_Sym *sym, GElf_Word *shndx)
{
- if (*symdata == NULL)
+ if (cache->symdata == NULL)
{
- if (mod->symfile->elf != relocated)
+ if (mod->symfile == NULL || mod->symfile->elf != relocated)
{
/* We have to look up the symbol table in the file we are
relocating, if it has its own. These reloc sections refer to
@@ -131,34 +141,42 @@ relocate_getsym (Elf **symelf, Elf_Data **symdata, Elf_Data **symxndxdata,
default:
continue;
case SHT_SYMTAB:
- *symelf = relocated;
- *symdata = elf_getdata (scn, NULL);
- if (unlikely (*symdata == NULL))
+ cache->symelf = relocated;
+ cache->symdata = elf_getdata (scn, NULL);
+ cache->strtabndx = shdr->sh_link;
+ if (unlikely (cache->symdata == NULL))
return DWFL_E_LIBELF;
break;
case SHT_SYMTAB_SHNDX:
- *symxndxdata = elf_getdata (scn, NULL);
- if (unlikely (*symxndxdata == NULL))
+ cache->symxndxdata = elf_getdata (scn, NULL);
+ if (unlikely (cache->symxndxdata == NULL))
return DWFL_E_LIBELF;
break;
}
- if (*symdata != NULL && *symxndxdata != NULL)
+ if (cache->symdata != NULL && cache->symxndxdata != NULL)
break;
}
}
- if (*symdata == NULL)
+ if (cache->symdata == NULL)
{
+ /* We might not have looked for a symbol table file yet,
+ when coming from __libdwfl_relocate_section. */
+ if (unlikely (mod->symfile == NULL)
+ && unlikely (INTUSE(dwfl_module_getsymtab) (mod) < 0))
+ return dwfl_errno ();
+
/* The symbol table we have already cached is the one from
the file being relocated, so it's what we need. Or else
this is an ET_REL .debug file with no .symtab of its own;
the symbols refer to the section indices in the main file. */
- *symelf = mod->symfile->elf;
- *symdata = mod->symdata;
- *symxndxdata = mod->symxndxdata;
+ cache->symelf = mod->symfile->elf;
+ cache->symdata = mod->symdata;
+ cache->symxndxdata = mod->symxndxdata;
+ cache->symstrdata = mod->symstrdata;
}
}
- if (unlikely (gelf_getsymshndx (*symdata, *symxndxdata,
+ if (unlikely (gelf_getsymshndx (cache->symdata, cache->symxndxdata,
symndx, sym, shndx) == NULL))
return DWFL_E_LIBELF;
@@ -173,13 +191,362 @@ relocate_getsym (Elf **symelf, Elf_Data **symdata, Elf_Data **symxndxdata,
return DWFL_E_NOERROR;
}
- return __libdwfl_relocate_value (mod, *symelf, symshstrndx,
+ return __libdwfl_relocate_value (mod, cache->symelf, &cache->symshstrndx,
*shndx, &sym->st_value);
}
+/* Handle an undefined symbol. We really only support ET_REL for Linux
+ kernel modules, and offline archives. The behavior of the Linux module
+ loader is very simple and easy to mimic. It only matches magically
+ exported symbols, and we match any defined symbols. But we get the same
+ answer except when the module's symbols are undefined and would prevent
+ it from being loaded. */
+static Dwfl_Error
+resolve_symbol (Dwfl_Module *referer, struct reloc_symtab_cache *symtab,
+ GElf_Sym *sym, GElf_Word shndx)
+{
+ /* First we need its name. */
+ if (sym->st_name != 0)
+ {
+ if (symtab->symstrdata == NULL)
+ {
+ /* Cache the strtab for this symtab. */
+ assert (referer->symfile == NULL
+ || referer->symfile->elf != symtab->symelf);
+ symtab->symstrdata = elf_getdata (elf_getscn (symtab->symelf,
+ symtab->strtabndx),
+ NULL);
+ if (unlikely (symtab->symstrdata == NULL))
+ return DWFL_E_LIBELF;
+ }
+ if (unlikely (sym->st_name >= symtab->symstrdata->d_size))
+ return DWFL_E_BADSTROFF;
+
+ const char *name = symtab->symstrdata->d_buf;
+ name += sym->st_name;
+
+ for (Dwfl_Module *m = referer->dwfl->modulelist; m != NULL; m = m->next)
+ if (m != referer)
+ {
+ /* Get this module's symtab.
+ If we got a fresh error reading the table, report it.
+ If we just have no symbols in this module, no harm done. */
+ if (m->symdata == NULL
+ && m->symerr == DWFL_E_NOERROR
+ && INTUSE(dwfl_module_getsymtab) (m) < 0
+ && m->symerr != DWFL_E_NO_SYMTAB)
+ return m->symerr;
+
+ for (size_t ndx = 1; ndx < m->syments; ++ndx)
+ {
+ sym = gelf_getsymshndx (m->symdata, m->symxndxdata,
+ ndx, sym, &shndx);
+ if (unlikely (sym == NULL))
+ return DWFL_E_LIBELF;
+ if (sym->st_shndx != SHN_XINDEX)
+ shndx = sym->st_shndx;
+
+ /* We are looking for a defined global symbol with a name. */
+ if (shndx == SHN_UNDEF || shndx == SHN_COMMON
+ || GELF_ST_BIND (sym->st_info) == STB_LOCAL
+ || sym->st_name == 0)
+ continue;
+
+ /* Get this candidate symbol's name. */
+ if (unlikely (sym->st_name >= m->symstrdata->d_size))
+ return DWFL_E_BADSTROFF;
+ const char *n = m->symstrdata->d_buf;
+ n += sym->st_name;
+
+ /* Does the name match? */
+ if (strcmp (name, n))
+ continue;
+
+ /* We found it! */
+ if (shndx == SHN_ABS)
+ return DWFL_E_NOERROR;
+
+ /* In an ET_REL file, the symbol table values are relative
+ to the section, not to the module's load base. */
+ size_t symshstrndx = SHN_UNDEF;
+ return __libdwfl_relocate_value (m, m->symfile->elf,
+ &symshstrndx,
+ shndx, &sym->st_value);
+ }
+ }
+ }
+
+ return DWFL_E_RELUNDEF;
+}
+
+static Dwfl_Error
+relocate_section (Dwfl_Module *mod, Elf *relocated, const GElf_Ehdr *ehdr,
+ size_t shstrndx, struct reloc_symtab_cache *reloc_symtab,
+ Elf_Scn *scn, GElf_Shdr *shdr,
+ Elf_Scn *tscn, bool debugscn, bool partial)
+{
+ /* First, fetch the name of the section these relocations apply to. */
+ GElf_Shdr tshdr_mem;
+ GElf_Shdr *tshdr = gelf_getshdr (tscn, &tshdr_mem);
+ const char *tname = elf_strptr (relocated, shstrndx, tshdr->sh_name);
+ if (tname == NULL)
+ return DWFL_E_LIBELF;
+
+ if (debugscn && ! ebl_debugscn_p (mod->ebl, tname))
+ /* This relocation section is not for a debugging section.
+ Nothing to do here. */
+ return DWFL_E_NOERROR;
+
+ /* Fetch the section data that needs the relocations applied. */
+ Elf_Data *tdata = elf_rawdata (tscn, NULL);
+ if (tdata == NULL)
+ return DWFL_E_LIBELF;
+
+ /* Apply one relocation. Returns true for any invalid data. */
+ Dwfl_Error relocate (GElf_Addr offset, const GElf_Sxword *addend,
+ int rtype, int symndx)
+ {
+ /* First, resolve the symbol to an absolute value. */
+ GElf_Addr value;
+
+ if (symndx == STN_UNDEF)
+ /* When strip removes a section symbol referring to a
+ section moved into the debuginfo file, it replaces
+ that symbol index in relocs with STN_UNDEF. We
+ don't actually need the symbol, because those relocs
+ are always references relative to the nonallocated
+ debugging sections, which start at zero. */
+ value = 0;
+ else
+ {
+ GElf_Sym sym;
+ GElf_Word shndx;
+ Dwfl_Error error = relocate_getsym (mod, relocated, reloc_symtab,
+ symndx, &sym, &shndx);
+ if (unlikely (error != DWFL_E_NOERROR))
+ return error;
+
+ if (shndx == SHN_UNDEF || shndx == SHN_COMMON)
+ {
+ /* Maybe we can figure it out anyway. */
+ error = resolve_symbol (mod, reloc_symtab, &sym, shndx);
+ if (error != DWFL_E_NOERROR)
+ return error;
+ }
+
+ value = sym.st_value;
+ }
+
+ /* These are the types we can relocate. */
+#define TYPES DO_TYPE (BYTE, Byte); DO_TYPE (HALF, Half); \
+ DO_TYPE (WORD, Word); DO_TYPE (SWORD, Sword); \
+ DO_TYPE (XWORD, Xword); DO_TYPE (SXWORD, Sxword)
+ size_t size;
+ Elf_Type type = ebl_reloc_simple_type (mod->ebl, rtype);
+ switch (type)
+ {
+#define DO_TYPE(NAME, Name) \
+ case ELF_T_##NAME: \
+ size = sizeof (GElf_##Name); \
+ break
+ TYPES;
+#undef DO_TYPE
+ default:
+ /* This might be because ebl_openbackend failed to find
+ any libebl_CPU.so library. Diagnose that clearly. */
+ if (ebl_get_elfmachine (mod->ebl) == EM_NONE)
+ return DWFL_E_UNKNOWN_MACHINE;
+ return DWFL_E_BADRELTYPE;
+ }
+
+ if (offset + size > tdata->d_size)
+ return DWFL_E_BADRELOFF;
+
+#define DO_TYPE(NAME, Name) GElf_##Name Name;
+ union { TYPES; } tmpbuf;
+#undef DO_TYPE
+ Elf_Data tmpdata =
+ {
+ .d_type = type,
+ .d_buf = &tmpbuf,
+ .d_size = size,
+ .d_version = EV_CURRENT,
+ };
+ Elf_Data rdata =
+ {
+ .d_type = type,
+ .d_buf = tdata->d_buf + offset,
+ .d_size = size,
+ .d_version = EV_CURRENT,
+ };
+
+ /* XXX check for overflow? */
+ if (addend)
+ {
+ /* For the addend form, we have the value already. */
+ value += *addend;
+ switch (type)
+ {
+#define DO_TYPE(NAME, Name) \
+ case ELF_T_##NAME: \
+ tmpbuf.Name = value; \
+ break
+ TYPES;
+#undef DO_TYPE
+ default:
+ abort ();
+ }
+ }
+ else
+ {
+ /* Extract the original value and apply the reloc. */
+ Elf_Data *d = gelf_xlatetom (relocated, &tmpdata, &rdata,
+ ehdr->e_ident[EI_DATA]);
+ if (d == NULL)
+ return DWFL_E_LIBELF;
+ assert (d == &tmpdata);
+ switch (type)
+ {
+#define DO_TYPE(NAME, Name) \
+ case ELF_T_##NAME: \
+ tmpbuf.Name += (GElf_##Name) value; \
+ break
+ TYPES;
+#undef DO_TYPE
+ default:
+ abort ();
+ }
+ }
+
+ /* Now convert the relocated datum back to the target
+ format. This will write into rdata.d_buf, which
+ points into the raw section data being relocated. */
+ Elf_Data *s = gelf_xlatetof (relocated, &rdata, &tmpdata,
+ ehdr->e_ident[EI_DATA]);
+ if (s == NULL)
+ return DWFL_E_LIBELF;
+ assert (s == &rdata);
+
+ /* We have applied this relocation! */
+ return DWFL_E_NOERROR;
+ }
+
+ /* Fetch the relocation section and apply each reloc in it. */
+ Elf_Data *reldata = elf_getdata (scn, NULL);
+ if (reldata == NULL)
+ return DWFL_E_LIBELF;
+
+ Dwfl_Error result = DWFL_E_NOERROR;
+ size_t nrels = shdr->sh_size / shdr->sh_entsize;
+ size_t complete = 0;
+ if (shdr->sh_type == SHT_REL)
+ for (size_t relidx = 0; !result && relidx < nrels; ++relidx)
+ {
+ GElf_Rel rel_mem, *r = gelf_getrel (reldata, relidx, &rel_mem);
+ if (r == NULL)
+ return DWFL_E_LIBELF;
+ result = relocate (r->r_offset, NULL,
+ GELF_R_TYPE (r->r_info),
+ GELF_R_SYM (r->r_info));
+ if (partial)
+ switch (result)
+ {
+ case DWFL_E_NOERROR:
+ /* We applied the relocation. Elide it. */
+ memset (&rel_mem, 0, sizeof rel_mem);
+ gelf_update_rel (reldata, relidx, &rel_mem);
+ ++complete;
+ break;
+ case DWFL_E_BADRELTYPE:
+ case DWFL_E_RELUNDEF:
+ /* We couldn't handle this relocation. Skip it. */
+ result = DWFL_E_NOERROR;
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ for (size_t relidx = 0; !result && relidx < nrels; ++relidx)
+ {
+ GElf_Rela rela_mem, *r = gelf_getrela (reldata, relidx,
+ &rela_mem);
+ if (r == NULL)
+ return DWFL_E_LIBELF;
+ result = relocate (r->r_offset, &r->r_addend,
+ GELF_R_TYPE (r->r_info),
+ GELF_R_SYM (r->r_info));
+ if (partial)
+ switch (result)
+ {
+ case DWFL_E_NOERROR:
+ /* We applied the relocation. Elide it. */
+ memset (&rela_mem, 0, sizeof rela_mem);
+ gelf_update_rela (reldata, relidx, &rela_mem);
+ ++complete;
+ break;
+ case DWFL_E_BADRELTYPE:
+ case DWFL_E_RELUNDEF:
+ /* We couldn't handle this relocation. Skip it. */
+ result = DWFL_E_NOERROR;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (likely (result == DWFL_E_NOERROR))
+ {
+ if (!partial || complete == nrels)
+ /* Mark this relocation section as being empty now that we have
+ done its work. This affects unstrip -R, so e.g. it emits an
+ empty .rela.debug_info along with a .debug_info that has
+ already been fully relocated. */
+ nrels = 0;
+ else if (complete != 0)
+ {
+ /* We handled some of the relocations but not all.
+ We've zeroed out the ones we processed.
+ Now remove them from the section. */
+
+ size_t next = 0;
+ if (shdr->sh_type == SHT_REL)
+ for (size_t relidx = 0; relidx < nrels; ++relidx)
+ {
+ GElf_Rel rel_mem;
+ GElf_Rel *r = gelf_getrel (reldata, relidx, &rel_mem);
+ if (r->r_info != 0 || r->r_offset != 0)
+ {
+ if (next != relidx)
+ gelf_update_rel (reldata, next, r);
+ ++next;
+ }
+ }
+ else
+ for (size_t relidx = 0; relidx < nrels; ++relidx)
+ {
+ GElf_Rela rela_mem;
+ GElf_Rela *r = gelf_getrela (reldata, relidx, &rela_mem);
+ if (r->r_info != 0 || r->r_offset != 0 || r->r_addend != 0)
+ {
+ if (next != relidx)
+ gelf_update_rela (reldata, next, r);
+ ++next;
+ }
+ }
+ nrels = next;
+ }
+
+ shdr->sh_size = reldata->d_size = nrels * shdr->sh_entsize;
+ gelf_update_shdr (scn, shdr);
+ }
+
+ return result;
+}
+
Dwfl_Error
internal_function
-__libdwfl_relocate (Dwfl_Module *mod, Elf *debugfile)
+__libdwfl_relocate (Dwfl_Module *mod, Elf *debugfile, bool debug)
{
assert (mod->e_type == ET_REL);
@@ -188,23 +555,18 @@ __libdwfl_relocate (Dwfl_Module *mod, Elf *debugfile)
if (ehdr == NULL)
return DWFL_E_LIBELF;
- /* 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)
- reloc_symshstrndx = d_shstrndx;
+
+ RELOC_SYMTAB_CACHE (reloc_symtab);
/* Look at each section in the debuginfo file, and process the
relocation sections for debugging sections. */
- Dwfl_Error result = DWFL_E_NO_DWARF;
+ Dwfl_Error result = DWFL_E_NOERROR;
Elf_Scn *scn = NULL;
- while ((scn = elf_nextscn (debugfile, scn)) != NULL)
+ while (result == DWFL_E_NOERROR
+ && (scn = elf_nextscn (debugfile, scn)) != NULL)
{
GElf_Shdr shdr_mem;
GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
@@ -212,198 +574,39 @@ __libdwfl_relocate (Dwfl_Module *mod, Elf *debugfile)
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. */
+ /* It's a relocation section. */
Elf_Scn *tscn = elf_getscn (debugfile, shdr->sh_info);
- if (tscn == NULL)
- return DWFL_E_LIBELF;
-
- GElf_Shdr tshdr_mem;
- GElf_Shdr *tshdr = gelf_getshdr (tscn, &tshdr_mem);
- const char *tname = elf_strptr (debugfile, d_shstrndx,
- tshdr->sh_name);
- if (tname == NULL)
- return DWFL_E_LIBELF;
-
- if (! ebl_debugscn_p (mod->ebl, tname))
- /* This relocation section is not for a debugging section.
- Nothing to do here. */
- continue;
-
- /* Fetch the section data that needs the relocations applied. */
- Elf_Data *tdata = elf_rawdata (tscn, NULL);
- if (tdata == NULL)
- return DWFL_E_LIBELF;
-
- /* Apply one relocation. Returns true for any invalid data. */
- Dwfl_Error relocate (GElf_Addr offset, const GElf_Sxword *addend,
- int rtype, int symndx)
- {
- /* First, resolve the symbol to an absolute value. */
- GElf_Addr value;
-
- if (symndx == STN_UNDEF)
- /* When strip removes a section symbol referring to a
- section moved into the debuginfo file, it replaces
- that symbol index in relocs with STN_UNDEF. We
- don't actually need the symbol, because those relocs
- are always references relative to the nonallocated
- debugging sections, which start at zero. */
- value = 0;
- else
- {
- GElf_Sym sym;
- GElf_Word shndx;
- Dwfl_Error error = relocate_getsym (&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;
-
- value = sym.st_value;
- }
-
- /* These are the types we can relocate. */
-#define TYPES DO_TYPE (BYTE, Byte); DO_TYPE (HALF, Half); \
- DO_TYPE (WORD, Word); DO_TYPE (SWORD, Sword); \
- DO_TYPE (XWORD, Xword); DO_TYPE (SXWORD, Sxword)
- size_t size;
- Elf_Type type = ebl_reloc_simple_type (mod->ebl, rtype);
- switch (type)
- {
-#define DO_TYPE(NAME, Name) \
- case ELF_T_##NAME: \
- size = sizeof (GElf_##Name); \
- break
- TYPES;
-#undef DO_TYPE
- default:
- /* This might be because ebl_openbackend failed to find
- any libebl_CPU.so library. Diagnose that clearly. */
- if (ebl_get_elfmachine (mod->ebl) == EM_NONE)
- return DWFL_E_UNKNOWN_MACHINE;
- return DWFL_E_BADRELTYPE;
- }
-
- if (offset + size >= tdata->d_size)
- return DWFL_E_BADRELOFF;
-
-#define DO_TYPE(NAME, Name) GElf_##Name Name;
- union { TYPES; } tmpbuf;
-#undef DO_TYPE
- Elf_Data tmpdata =
- {
- .d_type = type,
- .d_buf = &tmpbuf,
- .d_size = size,
- .d_version = EV_CURRENT,
- };
- Elf_Data rdata =
- {
- .d_type = type,
- .d_buf = tdata->d_buf + offset,
- .d_size = size,
- .d_version = EV_CURRENT,
- };
-
- /* XXX check for overflow? */
- if (addend)
- {
- /* For the addend form, we have the value already. */
- value += *addend;
- switch (type)
- {
-#define DO_TYPE(NAME, Name) \
- case ELF_T_##NAME: \
- tmpbuf.Name = value; \
- break
- TYPES;
-#undef DO_TYPE
- default:
- abort ();
- }
- }
- else
- {
- /* Extract the original value and apply the reloc. */
- Elf_Data *d = gelf_xlatetom (debugfile, &tmpdata, &rdata,
- ehdr->e_ident[EI_DATA]);
- if (d == NULL)
- return DWFL_E_LIBELF;
- assert (d == &tmpdata);
- switch (type)
- {
-#define DO_TYPE(NAME, Name) \
- case ELF_T_##NAME: \
- tmpbuf.Name += (GElf_##Name) value; \
- break
- TYPES;
-#undef DO_TYPE
- default:
- abort ();
- }
- }
-
- /* Now convert the relocated datum back to the target
- format. This will write into rdata.d_buf, which
- points into the raw section data being relocated. */
- Elf_Data *s = gelf_xlatetof (debugfile, &rdata, &tmpdata,
- ehdr->e_ident[EI_DATA]);
- if (s == NULL)
- return DWFL_E_LIBELF;
- assert (s == &rdata);
-
- /* We have applied this relocation! */
- return DWFL_E_NOERROR;
- }
-
- /* Fetch the relocation section and apply each reloc in it. */
- Elf_Data *reldata = elf_getdata (scn, NULL);
- if (reldata == NULL)
- return DWFL_E_LIBELF;
-
- result = DWFL_E_NOERROR;
- size_t nrels = shdr->sh_size / shdr->sh_entsize;
- if (shdr->sh_type == SHT_REL)
- for (size_t relidx = 0; !result && relidx < nrels; ++relidx)
- {
- GElf_Rel rel_mem, *r = gelf_getrel (reldata, relidx, &rel_mem);
- if (r == NULL)
- return DWFL_E_LIBELF;
- result = relocate (r->r_offset, NULL,
- GELF_R_TYPE (r->r_info),
- GELF_R_SYM (r->r_info));
- }
+ if (unlikely (tscn == NULL))
+ result = DWFL_E_LIBELF;
else
- for (size_t relidx = 0; !result && relidx < nrels; ++relidx)
- {
- GElf_Rela rela_mem, *r = gelf_getrela (reldata, relidx,
- &rela_mem);
- if (r == NULL)
- return DWFL_E_LIBELF;
- result = relocate (r->r_offset, &r->r_addend,
- GELF_R_TYPE (r->r_info),
- GELF_R_SYM (r->r_info));
- }
- 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);
+ result = relocate_section (mod, debugfile, ehdr, d_shstrndx,
+ &reloc_symtab, scn, shdr, tscn,
+ debug, !debug);
}
}
return result;
}
+
+Dwfl_Error
+internal_function
+__libdwfl_relocate_section (Dwfl_Module *mod, Elf *relocated,
+ Elf_Scn *relocscn, Elf_Scn *tscn, bool partial)
+{
+ GElf_Ehdr ehdr_mem;
+ GElf_Shdr shdr_mem;
+
+ RELOC_SYMTAB_CACHE (reloc_symtab);
+
+ size_t shstrndx;
+ if (elf_getshstrndx (relocated, &shstrndx) < 0)
+ return DWFL_E_LIBELF;
+
+ return (__libdwfl_module_getebl (mod)
+ ?: relocate_section (mod, relocated,
+ gelf_getehdr (relocated, &ehdr_mem), shstrndx,
+ &reloc_symtab,
+ relocscn, gelf_getshdr (relocscn, &shdr_mem),
+ tscn, false, partial));
+}
diff --git a/libebl/ChangeLog b/libebl/ChangeLog
index ae31b8f2..86c91781 100644
--- a/libebl/ChangeLog
+++ b/libebl/ChangeLog
@@ -1,3 +1,7 @@
+2007-10-18 Roland McGrath <roland@redhat.com>
+
+ * eblcorenotetypename.c (ebl_core_note_type_name): Handle NT_PPC_VMX.
+
2007-10-11 Roland McGrath <roland@redhat.com>
* eblobjnote.c (ebl_object_note): Translate target format (byte-swap)
diff --git a/libebl/eblcorenotetypename.c b/libebl/eblcorenotetypename.c
index c2b57f9e..44b02376 100644
--- a/libebl/eblcorenotetypename.c
+++ b/libebl/eblcorenotetypename.c
@@ -86,20 +86,26 @@ ebl_core_note_type_name (ebl, type, buf, len)
KNOWNSTYPE (LWPSTATUS),
KNOWNSTYPE (LWPSINFO),
KNOWNSTYPE (PRFPXREG)
+#undef KNOWNSTYPE
};
/* Handle standard names. */
if (type < sizeof (knowntypes) / sizeof (knowntypes[0])
&& knowntypes[type] != NULL)
res = knowntypes[type];
- else if (type == NT_PRXFPREG)
- res = "PRXFPREG";
else
- {
- snprintf (buf, len, "%s: %" PRIu32, gettext ("<unknown>"), type);
+ switch (type)
+ {
+#define KNOWNSTYPE(name) case NT_##name: res = #name; break
+ KNOWNSTYPE (PRXFPREG);
+ KNOWNSTYPE (PPC_VMX);
+#undef KNOWNSTYPE
+
+ default:
+ snprintf (buf, len, "%s: %" PRIu32, gettext ("<unknown>"), type);
- res = buf;
- }
+ res = buf;
+ }
}
return res;
diff --git a/libelf/ChangeLog b/libelf/ChangeLog
index 247598c7..3488c2e5 100644
--- a/libelf/ChangeLog
+++ b/libelf/ChangeLog
@@ -1,3 +1,7 @@
+2007-10-18 Roland McGrath <roland@redhat.com>
+
+ * elf.h: Update from glibc.
+
2007-10-07 Roland McGrath <roland@redhat.com>
* elf_begin.c (__libelf_next_arhdr): Fix fencepost error and wrong
diff --git a/libelf/elf.h b/libelf/elf.h
index 6cc547ef..acd3d3e1 100644
--- a/libelf/elf.h
+++ b/libelf/elf.h
@@ -604,6 +604,7 @@ typedef struct
#define NT_LWPSINFO 17 /* Contains copy of lwpinfo struct */
#define NT_PRFPXREG 20 /* Contains copy of fprxregset struct */
#define NT_PRXFPREG 0x46e62b7f /* Contains copy of user_fxsr_struct */
+#define NT_PPC_VMX 0x100 /* PowerPC Altivec/VMX registers */
/* Legal values for the note segment descriptor types for object files. */
@@ -1723,6 +1724,8 @@ typedef Elf32_Addr Elf32_Conflict;
#define R_PARISC_LTOFF_FPTR14R 62 /* LT-rel. fct ptr, right 14 bits. */
#define R_PARISC_FPTR64 64 /* 64 bits function address. */
#define R_PARISC_PLABEL32 65 /* 32 bits function address. */
+#define R_PARISC_PLABEL21L 66 /* Left 21 bits of fdesc address. */
+#define R_PARISC_PLABEL14R 70 /* Right 14 bits of fdesc address. */
#define R_PARISC_PCREL64 72 /* 64 bits PC-rel. address. */
#define R_PARISC_PCREL22F 74 /* 22 bits PC-rel. address. */
#define R_PARISC_PCREL14WR 75 /* PC-rel. address, right 14 bits. */
@@ -1783,6 +1786,26 @@ typedef Elf32_Addr Elf32_Conflict;
#define R_PARISC_LTOFF_TP16F 229 /* 16 bits LT-TP-rel. address. */
#define R_PARISC_LTOFF_TP16WF 230 /* 16 bits LT-TP-rel. address. */
#define R_PARISC_LTOFF_TP16DF 231 /* 16 bits LT-TP-rel. address. */
+#define R_PARISC_GNU_VTENTRY 232
+#define R_PARISC_GNU_VTINHERIT 233
+#define R_PARISC_TLS_GD21L 234 /* GD 21-bit left. */
+#define R_PARISC_TLS_GD14R 235 /* GD 14-bit right. */
+#define R_PARISC_TLS_GDCALL 236 /* GD call to __t_g_a. */
+#define R_PARISC_TLS_LDM21L 237 /* LD module 21-bit left. */
+#define R_PARISC_TLS_LDM14R 238 /* LD module 14-bit right. */
+#define R_PARISC_TLS_LDMCALL 239 /* LD module call to __t_g_a. */
+#define R_PARISC_TLS_LDO21L 240 /* LD offset 21-bit left. */
+#define R_PARISC_TLS_LDO14R 241 /* LD offset 14-bit right. */
+#define R_PARISC_TLS_DTPMOD32 242 /* DTP module 32-bit. */
+#define R_PARISC_TLS_DTPMOD64 243 /* DTP module 64-bit. */
+#define R_PARISC_TLS_DTPOFF32 244 /* DTP offset 32-bit. */
+#define R_PARISC_TLS_DTPOFF64 245 /* DTP offset 32-bit. */
+#define R_PARISC_TLS_LE21L R_PARISC_TPREL21L
+#define R_PARISC_TLS_LE14R R_PARISC_TPREL14R
+#define R_PARISC_TLS_IE21L R_PARISC_LTOFF_TP21L
+#define R_PARISC_TLS_IE14R R_PARISC_LTOFF_TP14R
+#define R_PARISC_TLS_TPREL32 R_PARISC_TPREL32
+#define R_PARISC_TLS_TPREL64 R_PARISC_TPREL64
#define R_PARISC_HIRESERVE 255
/* Legal values for p_type field of Elf32_Phdr/Elf64_Phdr. */
diff --git a/src/ChangeLog b/src/ChangeLog
index ebd729fe..df4305c2 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,31 @@
+2007-10-20 Roland McGrath <roland@redhat.com>
+
+ * unstrip.c (options): Update -R description.
+ (struct symbol): Put symbol details a union with a size_t pointer
+ `duplicate'.
+ (compare_symbols_output): Use null ->name as marker for discard
+ symbols, not zero *->map.
+ (copy_elided_sections): Record forwarding pointers for discarded
+ duplicates and fill SYMNDX_MAP elements through them.
+
+ * readelf.c (process_file): Set offline_next_address to 0 at start.
+ (struct process_dwflmod_args): New type.
+ (process_dwflmod): Take args in it, pass fd to process_elf_file.
+ (process_file): Update caller; dup FD for passing to libdwfl.
+ (process_elf_file): Take new arg FD. For ET_REL file when
+ displaying data affected by libdwfl relocation, open a new Elf handle.
+
+2007-10-17 Roland McGrath <roland@redhat.com>
+
+ * readelf.c (print_debug_line_section): For invalid data inside a
+ unit with plausible length, keep printing at the next unit boundary.
+
+ * readelf.c (attr_callback): Use dwarf_formref_die, not dwarf_formref.
+
+2007-10-16 Roland McGrath <roland@redhat.com>
+
+ * readelf.c (hex_dump): Fix rounding error in whitespace calculation.
+
2007-10-15 Roland McGrath <roland@redhat.com>
* make-debug-archive.in: New file.
diff --git a/src/readelf.c b/src/readelf.c
index c591b322..2197d840 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -54,6 +54,7 @@
#include "../libelf/libelfP.h"
#include "../libebl/libeblP.h"
#include "../libdw/libdwP.h"
+#include "../libdwfl/libdwflP.h"
#include "../libdw/memory-access.h"
@@ -200,7 +201,7 @@ static size_t shnum;
/* Declarations of local functions. */
static void process_file (int fd, const char *fname, bool only_one);
-static void process_elf_file (Dwfl_Module *dwflmod);
+static void process_elf_file (Dwfl_Module *dwflmod, int fd);
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);
@@ -460,6 +461,12 @@ count_dwflmod (Dwfl_Module *dwflmod __attribute__ ((unused)),
return DWARF_CB_ABORT;
}
+struct process_dwflmod_args
+{
+ int fd;
+ bool only_one;
+};
+
static int
process_dwflmod (Dwfl_Module *dwflmod,
void **userdata __attribute__ ((unused)),
@@ -467,10 +474,10 @@ process_dwflmod (Dwfl_Module *dwflmod,
Dwarf_Addr base __attribute__ ((unused)),
void *arg)
{
- bool only_one = *(bool *) arg;
+ const struct process_dwflmod_args *a = arg;
/* Print the file name. */
- if (!only_one)
+ if (!a->only_one)
{
const char *fname;
dwfl_module_info (dwflmod, NULL, NULL, NULL, NULL, NULL, &fname, NULL);
@@ -478,7 +485,7 @@ process_dwflmod (Dwfl_Module *dwflmod,
printf ("\n%s:\n\n", fname);
}
- process_elf_file (dwflmod);
+ process_elf_file (dwflmod, a->fd);
return DWARF_CB_OK;
}
@@ -507,6 +514,11 @@ process_file (int fd, const char *fname, bool only_one)
if (!any_control_option)
return;
+ /* Duplicate an fd for dwfl_report_offline to swallow. */
+ int dwfl_fd = dup (fd);
+ if (unlikely (dwfl_fd < 0))
+ error (EXIT_FAILURE, errno, "dup");
+
/* 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 =
@@ -515,7 +527,10 @@ process_file (int fd, const char *fname, bool only_one)
.find_debuginfo = find_no_debuginfo
};
Dwfl *dwfl = dwfl_begin (&callbacks);
- if (dwfl_report_offline (dwfl, fname, fname, fd) == NULL)
+ if (likely (dwfl != NULL))
+ /* Let 0 be the logical address of the file (or first in archive). */
+ dwfl->offline_next_address = 0;
+ if (dwfl_report_offline (dwfl, fname, fname, dwfl_fd) == NULL)
{
struct stat64 st;
if (fstat64 (fd, &st) != 0)
@@ -535,7 +550,8 @@ process_file (int fd, const char *fname, bool only_one)
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);
+ struct process_dwflmod_args a = { .fd = fd, .only_one = only_one };
+ dwfl_getmodules (dwfl, &process_dwflmod, &a, 0);
}
dwfl_end (dwfl);
}
@@ -543,7 +559,7 @@ process_file (int fd, const char *fname, bool only_one)
/* Process one ELF file. */
static void
-process_elf_file (Dwfl_Module *dwflmod)
+process_elf_file (Dwfl_Module *dwflmod, int fd)
{
GElf_Addr dwflbias;
Elf *elf = dwfl_module_getelf (dwflmod, &dwflbias);
@@ -553,6 +569,7 @@ process_elf_file (Dwfl_Module *dwflmod)
if (ehdr == NULL)
{
+ elf_error:
error (0, 0, gettext ("cannot read ELF header: %s"), elf_errmsg (-1));
return;
}
@@ -560,6 +577,7 @@ process_elf_file (Dwfl_Module *dwflmod)
Ebl *ebl = ebl_openbackend (elf);
if (ebl == NULL)
{
+ ebl_error:
error (0, errno, gettext ("cannot create EBL handle"));
return;
}
@@ -570,10 +588,40 @@ process_elf_file (Dwfl_Module *dwflmod)
gettext ("cannot determine number of sections: %s"),
elf_errmsg (-1));
+ /* For an ET_REL file, libdwfl has adjusted the in-core shdrs
+ and may have applied relocation to some sections.
+ So we need to get a fresh Elf handle on the file to display those. */
+ bool print_unrelocated = (print_section_header
+ || print_relocations
+ || dump_data_sections != NULL
+ || print_notes);
+
+ Elf *pure_elf = NULL;
+ Ebl *pure_ebl = ebl;
+ if (ehdr->e_type == ET_REL && print_unrelocated)
+ {
+ /* Read the file afresh. */
+ pure_elf = elf_begin (fd, ELF_C_READ_MMAP, NULL);
+ off64_t aroff = elf_getaroff (elf);
+ if (aroff > 0)
+ {
+ /* Archive member. */
+ (void) elf_rand (pure_elf, aroff);
+ Elf *armem = elf_begin (-1, ELF_C_READ_MMAP, pure_elf);
+ elf_end (pure_elf);
+ pure_elf = armem;
+ }
+ if (pure_elf == NULL)
+ goto elf_error;
+ pure_ebl = ebl_openbackend (pure_elf);
+ if (pure_ebl == NULL)
+ goto ebl_error;
+ }
+
if (print_file_header)
print_ehdr (ebl, ehdr);
if (print_section_header)
- print_shdr (ebl, ehdr);
+ print_shdr (pure_ebl, ehdr);
if (print_program_header)
print_phdr (ebl, ehdr);
if (print_section_groups)
@@ -581,7 +629,7 @@ process_elf_file (Dwfl_Module *dwflmod)
if (print_dynamic_table)
print_dynamic (ebl, ehdr);
if (print_relocations)
- print_relocs (ebl);
+ print_relocs (pure_ebl);
if (print_histogram)
handle_hash (ebl);
if (print_symbol_table)
@@ -593,17 +641,23 @@ process_elf_file (Dwfl_Module *dwflmod)
if (print_arch)
print_liblist (ebl);
if (dump_data_sections != NULL)
- dump_data (ebl);
+ dump_data (pure_ebl);
if (string_sections != NULL)
dump_strings (ebl);
if (print_debug_sections != 0)
print_debug (dwflmod, ebl, ehdr);
if (print_notes)
- handle_notes (ebl, ehdr);
+ handle_notes (pure_ebl, ehdr);
if (print_string_sections)
print_strings (ebl);
ebl_closebackend (ebl);
+
+ if (pure_ebl != ebl)
+ {
+ ebl_closebackend (pure_ebl);
+ elf_end (pure_elf);
+ }
}
@@ -4027,13 +4081,13 @@ attr_callback (Dwarf_Attribute *attrp, void *arg)
case DW_FORM_ref4:
case DW_FORM_ref2:
case DW_FORM_ref1:;
- Dwarf_Off ref;
- if (unlikely (dwarf_formref (attrp, &ref) != 0))
+ Dwarf_Die ref;
+ if (unlikely (dwarf_formref_die (attrp, &ref) == NULL))
goto attrval_out;
printf (" %*s%-20s [%6" PRIxMAX "]\n",
(int) (level * 2), "", dwarf_attr_string (attr),
- (uintmax_t) (ref + cbargs->cu_offset));
+ (uintmax_t) dwarf_dieoffset (&ref));
break;
case DW_FORM_udata:
@@ -4384,7 +4438,15 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl,
line_range, opcode_base);
if (unlikely (linep + opcode_base - 1 >= lineendp))
- goto invalid_data;
+ {
+ invalid_unit:
+ error (0, 0,
+ gettext ("invalid data at offset %tu in section [%zu] '%s'"),
+ linep - (const unsigned char *) data->d_buf,
+ elf_ndxscn (scn), ".debug_line");
+ linep = lineendp;
+ continue;
+ }
int opcode_base_l10 = 1;
unsigned int tmp = opcode_base;
while (tmp > 10)
@@ -4400,14 +4462,14 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl,
opcode_base_l10, cnt, linep[cnt - 1]);
linep += opcode_base - 1;
if (unlikely (linep >= lineendp))
- goto invalid_data;
+ goto invalid_unit;
puts (gettext ("\nDirectory table:"));
while (*linep != 0)
{
unsigned char *endp = memchr (linep, '\0', lineendp - linep);
if (endp == NULL)
- goto invalid_data;
+ goto invalid_unit;
printf (" %s\n", (char *) linep);
@@ -4417,7 +4479,7 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl,
++linep;
if (unlikely (linep >= lineendp))
- goto invalid_data;
+ goto invalid_unit;
puts (gettext ("\nFile name table:\n"
" Entry Dir Time Size Name"));
for (unsigned int cnt = 1; *linep != 0; ++cnt)
@@ -4426,7 +4488,7 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl,
char *fname = (char *) linep;
unsigned char *endp = memchr (fname, '\0', lineendp - linep);
if (endp == NULL)
- goto invalid_data;
+ goto invalid_unit;
linep = endp + 1;
/* Then the index. */
@@ -4517,13 +4579,13 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl,
{
/* This an extended opcode. */
if (unlikely (linep + 2 > lineendp))
- goto invalid_data;
+ goto invalid_unit;
/* The length. */
unsigned int len = *linep++;
if (unlikely (linep + len > lineendp))
- goto invalid_data;
+ goto invalid_unit;
/* The sub-opcode. */
opcode = *linep++;
@@ -4559,7 +4621,7 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl,
unsigned char *endp = memchr (linep, '\0',
lineendp - linep);
if (endp == NULL)
- goto invalid_data;
+ goto invalid_unit;
linep = endp + 1;
unsigned int diridx;
@@ -4626,7 +4688,7 @@ define new file: dir=%u, mtime=%" PRIu64 ", length=%" PRIu64 ", name=%s\n"),
case DW_LNS_set_column:
/* Takes one uleb128 parameter which is stored in column. */
if (unlikely (standard_opcode_lengths[opcode] != 1))
- goto invalid_data;
+ goto invalid_unit;
get_uleb128 (u128, linep);
printf (gettext (" set column to %" PRIu64 "\n"),
@@ -4662,7 +4724,7 @@ define new file: dir=%u, mtime=%" PRIu64 ", length=%" PRIu64 ", name=%s\n"),
/* Takes one 16 bit parameter which is added to the
address. */
if (unlikely (standard_opcode_lengths[opcode] != 1))
- goto invalid_data;
+ goto invalid_unit;
u128 = read_2ubyte_unaligned_inc (dbg, linep);
address += u128;
@@ -5888,7 +5950,7 @@ hex_dump (const uint8_t *data, size_t len)
printf ("%02x", data[pos + i]);
if (chunk < 16)
- printf ("%*s", (int) ((16 - chunk) * 2 + (16 - chunk) / 4), "");
+ printf ("%*s", (int) ((16 - chunk) * 2 + (16 - chunk + 3) / 4), "");
for (size_t i = 0; i < chunk; ++i)
{
diff --git a/src/unstrip.c b/src/unstrip.c
index d19ad27e..2670835a 100644
--- a/src/unstrip.c
+++ b/src/unstrip.c
@@ -87,7 +87,7 @@ static const struct argp_option options[] =
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 },
+ N_("Apply relocations to section contents 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 }
@@ -719,17 +719,27 @@ struct symbol
const char *name;
struct Ebl_Strent *strent;
};
- GElf_Addr value;
- GElf_Xword size;
- GElf_Word shndx;
union
{
struct
{
- uint8_t info;
- uint8_t other;
- } info;
- int16_t compare;
+ GElf_Addr value;
+ GElf_Xword size;
+ GElf_Word shndx;
+ union
+ {
+ struct
+ {
+ uint8_t info;
+ uint8_t other;
+ } info;
+ int16_t compare;
+ };
+ };
+
+ /* For a symbol discarded after first sort, this matches its better's
+ map pointer. */
+ size_t *duplicate;
};
};
@@ -819,7 +829,7 @@ compare_symbols_output (const void *a, const void *b)
int cmp;
/* Sort discarded symbols last. */
- cmp = (*s1->map == 0) - (*s2->map == 0);
+ cmp = (s1->name == NULL) - (s2->name == NULL);
if (cmp == 0)
/* Local symbols must come first. */
@@ -1605,31 +1615,65 @@ copy_elided_sections (Elf *unstripped, Elf *stripped,
new slots, collecting a map from old indices to new. */
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);
+ {
+ /* Skip a section symbol for a removed section. */
+ if (s->shndx == SHN_UNDEF
+ && GELF_ST_TYPE (s->info.info) == STT_SECTION)
+ {
+ s->name = NULL; /* Mark as discarded. */
+ *s->map = STN_UNDEF;
+ s->duplicate = NULL;
+ continue;
+ }
+
+ struct symbol *n = s;
+ while (n + 1 < &symbols[total_syms] && !compare_symbols (s, n + 1))
+ ++n;
+
+ while (s < n)
+ {
+ /* This is a duplicate. Its twin will get the next slot. */
+ s->name = NULL; /* Mark as discarded. */
+ s->duplicate = n->map;
+ ++s;
+ }
+
+ /* Allocate the next slot. */
+ *s->map = ++nsym;
+ }
/* Now we sort again, to determine the order in the output. */
qsort (symbols, total_syms, sizeof symbols[0], compare_symbols_output);
if (nsym < total_syms)
/* The discarded symbols are now at the end of the table. */
- assert (*symbols[nsym].map == 0);
+ assert (symbols[nsym].name == NULL);
/* Now a final pass updates the map with the final order,
and builds up the new string table. */
symstrtab = ebl_strtabinit (true);
for (size_t i = 0; i < nsym; ++i)
{
+ assert (symbols[i].name != NULL);
assert (*symbols[i].map != 0);
- *symbols[i].map = i;
+ *symbols[i].map = 1 + i;
symbols[i].strent = ebl_strtabadd (symstrtab, symbols[i].name, 0);
}
+ /* Scan the discarded symbols too, just to update their slots
+ in SYMNDX_MAP to refer to their live duplicates. */
+ for (size_t i = nsym; i < total_syms; ++i)
+ {
+ assert (symbols[i].name == NULL);
+ if (symbols[i].duplicate == NULL)
+ assert (*symbols[i].map == STN_UNDEF);
+ else
+ {
+ assert (*symbols[i].duplicate != STN_UNDEF);
+ *symbols[i].map = *symbols[i].duplicate;
+ }
+ }
+
/* Now we are ready to write the new symbol table. */
symdata = elf_getdata (unstripped_symtab, NULL);
symstrdata = elf_getdata (unstripped_strtab, NULL);
diff --git a/tests/ChangeLog b/tests/ChangeLog
index 1284b134..f029f156 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,3 +1,24 @@
+2007-10-20 Roland McGrath <roland@redhat.com>
+
+ * run-dwfl-addr-sect.sh: Change expected output, no errors.
+
+2007-10-19 Roland McGrath <roland@redhat.com>
+
+ * dwfl-addr-sect.c (handle_address): Return int.
+ Don't exit on error, just return nonzero.
+ (main): Collect results.
+ * run-dwfl-addr-sect.sh: New file.
+ * testfile43.bz2: New data file.
+ * Makefile.am (EXTRA_DIST, TESTS): Add them.
+
+2007-10-18 Roland McGrath <roland@redhat.com>
+
+ * run-allregs.sh: Update expected ppc output for vrsave/vscr.
+
+2007-10-16 Roland McGrath <roland@redhat.com>
+
+ * test-subr.sh (remove_files): Don't pass -Bb to diff.
+
2007-10-09 Roland McGrath <roland@redhat.com>
* dwflmodtest.c (print_module): Don't use %p in output.
diff --git a/tests/Makefile.am b/tests/Makefile.am
index ab325c7a..45560788 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -83,7 +83,7 @@ TESTS = run-arextract.sh run-arsymtest.sh newfile test-nlist \
run-native-test.sh run-bug1-test.sh \
dwfl-bug-addr-overflow run-addrname-test.sh \
dwfl-bug-fd-leak dwfl-bug-report \
- run-dwfl-bug-offline-rel.sh
+ run-dwfl-bug-offline-rel.sh run-dwfl-addr-sect.sh
# run-show-ciefde.sh
if !STANDALONE
@@ -114,6 +114,7 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh \
run-addrscopes.sh run-strings-test.sh run-funcscopes.sh \
run-find-prologues.sh run-allregs.sh run-native-test.sh \
run-addrname-test.sh run-dwfl-bug-offline-rel.sh \
+ run-dwfl-addr-sect.sh \
testfile15.bz2 testfile15.debug.bz2 \
testfile16.bz2 testfile16.debug.bz2 \
testfile17.bz2 testfile17.debug.bz2 \
@@ -132,7 +133,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 testfile42.bz2
+ testfile41.bz2 testfile42.bz2 testfile43.bz2
installed_TESTS_ENVIRONMENT = libdir=$(DESTDIR)$(libdir) \
bindir=$(DESTDIR)$(bindir) \
diff --git a/tests/dwfl-addr-sect.c b/tests/dwfl-addr-sect.c
index b1f29f7c..62d11541 100644
--- a/tests/dwfl-addr-sect.c
+++ b/tests/dwfl-addr-sect.c
@@ -37,8 +37,7 @@
#include ELFUTILS_HEADER(dwfl)
#include <dwarf.h>
-
-static void
+static int
handle_address (Dwfl *dwfl, Dwarf_Addr address)
{
Dwfl_Module *mod = dwfl_addrmodule (dwfl, address);
@@ -46,12 +45,16 @@ handle_address (Dwfl *dwfl, Dwarf_Addr address)
Dwarf_Addr bias;
Elf_Scn *scn = dwfl_module_address_section (mod, &adjusted, &bias);
if (scn == NULL)
- error (EXIT_FAILURE, 0, "%#" PRIx64 ": dwfl_module_address_section: %s",
- address, dwfl_errmsg (-1));
+ {
+ error (0, 0, "%#" PRIx64 ": dwfl_module_address_section: %s",
+ address, dwfl_errmsg (-1));
+ return 1;
+ }
printf ("address %#" PRIx64 " => module \"%s\" section %zu + %#" PRIx64 "\n",
address,
dwfl_module_info (mod, NULL, NULL, NULL, NULL, NULL, NULL, NULL),
elf_ndxscn (scn), adjusted);
+ return 0;
}
int
@@ -74,7 +77,7 @@ main (int argc, char **argv)
char *endp;
uintmax_t addr = strtoumax (argv[remaining], &endp, 0);
if (endp != argv[remaining])
- handle_address (dwfl, addr);
+ result |= handle_address (dwfl, addr);
else
result = 1;
}
diff --git a/tests/run-allregs.sh b/tests/run-allregs.sh
index c7f46b0b..82d57409 100755
--- a/tests/run-allregs.sh
+++ b/tests/run-allregs.sh
@@ -502,7 +502,6 @@ privileged registers:
353: spr253 (spr253), unsigned 32 bits
354: spr254 (spr254), unsigned 32 bits
355: spr255 (spr255), unsigned 32 bits
- 356: vrsave (vrsave), unsigned 32 bits
357: spr257 (spr257), unsigned 32 bits
358: spr258 (spr258), unsigned 32 bits
359: spr259 (spr259), unsigned 32 bits
@@ -1147,6 +1146,8 @@ privileged registers:
998: spr898 (spr898), unsigned 32 bits
999: spr899 (spr899), unsigned 32 bits
vector registers:
+ 67: vscr (vscr), unsigned 32 bits
+ 356: vrsave (vrsave), unsigned 32 bits
1124: vr0 (vr0), unsigned 128 bits
1125: vr1 (vr1), unsigned 128 bits
1126: vr2 (vr2), unsigned 128 bits
@@ -1524,7 +1525,6 @@ privileged registers:
353: spr253 (spr253), unsigned 64 bits
354: spr254 (spr254), unsigned 64 bits
355: spr255 (spr255), unsigned 64 bits
- 356: vrsave (vrsave), unsigned 64 bits
357: spr257 (spr257), unsigned 64 bits
358: spr258 (spr258), unsigned 64 bits
359: spr259 (spr259), unsigned 64 bits
@@ -2169,6 +2169,8 @@ privileged registers:
998: spr898 (spr898), unsigned 64 bits
999: spr899 (spr899), unsigned 64 bits
vector registers:
+ 67: vscr (vscr), unsigned 32 bits
+ 356: vrsave (vrsave), unsigned 32 bits
1124: vr0 (vr0), unsigned 128 bits
1125: vr1 (vr1), unsigned 128 bits
1126: vr2 (vr2), unsigned 128 bits
diff --git a/tests/run-dwfl-addr-sect.sh b/tests/run-dwfl-addr-sect.sh
new file mode 100755
index 00000000..69280f58
--- /dev/null
+++ b/tests/run-dwfl-addr-sect.sh
@@ -0,0 +1,37 @@
+#! /bin/sh
+# 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>.
+
+. $srcdir/test-subr.sh
+
+testfiles testfile43
+
+export LC_ALL=C
+testrun_compare ./dwfl-addr-sect -e testfile43 0x64 0x8 0x98 <<\EOF
+address 0x64 => module "" section 4 + 0
+address 0x8 => module "" section 1 + 0x8
+address 0x98 => module "" section 7 + 0
+EOF
+
+exit 0
diff --git a/tests/test-subr.sh b/tests/test-subr.sh
index d92c602e..7fda05a0 100644
--- a/tests/test-subr.sh
+++ b/tests/test-subr.sh
@@ -1,5 +1,5 @@
#! /bin/sh
-# 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
@@ -58,7 +58,7 @@ testrun_compare()
{
outfile="${1##*/}.out"
testrun_out $outfile "$@"
- diff -Bbu $outfile -
+ diff -u $outfile -
# diff's exit status will kill the script.
}
diff --git a/tests/testfile43.bz2 b/tests/testfile43.bz2
new file mode 100644
index 00000000..c99db24a
--- /dev/null
+++ b/tests/testfile43.bz2
Binary files differ