diff options
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 Binary files differnew file mode 100644 index 00000000..c99db24a --- /dev/null +++ b/tests/testfile43.bz2 |