From: Roland McGrath Date: Fri, 18 May 2007 08:59:43 +0000 (+0000) Subject: src/ X-Git-Tag: elfutils-0.128~6 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9aa8ef7fbb5ada14b7c4585d6c1361aa5eab6f88;p=thirdparty%2Felfutils.git src/ 2007-05-18 Roland McGrath * unstrip.c (copy_elided_sections): Match up non-NOBITS sections with stripped file, so as not to duplicate a section copied in both. * strip.c (handle_elf): Keep SHT_NOTE section copies in the debug file. tests/ 2007-05-18 Roland McGrath * run-strip-test4.sh (stripped, debugfile): Use new reference files. * testfile37.bz2: New data file. * testfile37.debug.bz2: New data file. * run-unstrip-test2.sh: New file. * Makefile.am (TESTS, EXTRA_DIST): Add them. --- diff --git a/ChangeLog b/ChangeLog index 760c4d2d8..b9f088a0b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2007-05-16 Roland McGrath + + * configure.ac (AM_INIT_AUTOMAKE): Use -Wno-portability. + 2006-11-02 Roland McGrath * Makefile.am (EXTRA_DIST): Add EXCEPTION file. diff --git a/configure.ac b/configure.ac index 596219e56..b6856ccd8 100644 --- a/configure.ac +++ b/configure.ac @@ -25,7 +25,8 @@ AC_CONFIG_FILES([config/Makefile]) AC_COPYRIGHT([Copyright (C) 1996-2003, 2004, 2005, 2006, 2007 Red Hat, Inc.]) AC_PREREQ(2.59) dnl Minimum Autoconf version required. -AM_INIT_AUTOMAKE([gnits 1.7]) +dnl We use GNU make extensions; automake 1.10 defaults to -Wportability. +AM_INIT_AUTOMAKE([gnits 1.7 -Wno-portability]) AM_MAINTAINER_MODE dnl Unique ID for this build. diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog index 39c7ee29d..6e6407ae2 100644 --- a/libdwfl/ChangeLog +++ b/libdwfl/ChangeLog @@ -1,3 +1,23 @@ +2007-05-17 Roland McGrath + + * linux-kernel-modules.c (dwfl_linux_kernel_report_offline): Look at + whole /lib/modules/VERSION tree, not just /lib/modules/VERSION/kernel. + (dwfl_linux_kernel_find_elf): Likewise. + + * linux-kernel-modules.c (dwfl_linux_kernel_report_modules): Use + getline and sscanf instead of fscanf. + +2007-05-08 Roland McGrath + + * offline.c (dwfl_offline_section_address): Don't assume section + numbers match between stripped and debuginfo files. Instead, assume + only that the ordering among SHF_ALLOC sections matches. + + * linux-kernel-modules.c (report_kernel): Change RELEASE argument to + pointer to string. + (dwfl_linux_kernel_report_offline): Update caller. + (dwfl_linux_kernel_report_kernel): Likewise. + 2007-04-23 Roland McGrath * argp-std.c (options): Fix group title string. diff --git a/libdwfl/linux-kernel-modules.c b/libdwfl/linux-kernel-modules.c index 2aaa25acb..98957521b 100644 --- a/libdwfl/linux-kernel-modules.c +++ b/libdwfl/linux-kernel-modules.c @@ -139,21 +139,24 @@ find_kernel_elf (Dwfl *dwfl, const char *release, char **fname) } static int -report_kernel (Dwfl *dwfl, const char *release, +report_kernel (Dwfl *dwfl, const char **release, int (*predicate) (const char *module, const char *file)) { if (dwfl == NULL) return -1; - if (release == NULL) + const char *release_string = release == NULL ? NULL : *release; + if (release_string == NULL) { - release = kernel_release (); - if (release == NULL) + release_string = kernel_release (); + if (release_string == NULL) return errno; + if (release != NULL) + *release = release_string; } char *fname; - int fd = find_kernel_elf (dwfl, release, &fname); + int fd = find_kernel_elf (dwfl, release_string, &fname); int result = 0; if (fd < 0) @@ -198,17 +201,17 @@ dwfl_linux_kernel_report_offline (Dwfl *dwfl, const char *release, const char *file)) { /* First report the kernel. */ - int result = report_kernel (dwfl, release, predicate); + int result = report_kernel (dwfl, &release, predicate); if (result == 0) { - /* Do "find /lib/modules/RELEASE/kernel -name *.ko". */ + /* Do "find /lib/modules/RELEASE -name *.ko". */ char *modulesdir[] = { NULL, NULL }; if (release[0] == '/') modulesdir[0] = (char *) release; else { - if (asprintf (&modulesdir[0], MODULEDIRFMT "/kernel", release) < 0) + if (asprintf (&modulesdir[0], MODULEDIRFMT, release) < 0) return errno; } @@ -394,10 +397,10 @@ dwfl_linux_kernel_find_elf (Dwfl_Module *mod __attribute__ ((unused)), if (!strcmp (module_name, KERNEL_MODNAME)) return find_kernel_elf (mod->dwfl, release, file_name); - /* Do "find /lib/modules/`uname -r`/kernel -name MODULE_NAME.ko". */ + /* Do "find /lib/modules/`uname -r` -name MODULE_NAME.ko". */ char *modulesdir[] = { NULL, NULL }; - if (asprintf (&modulesdir[0], MODULEDIRFMT "/kernel", release) < 0) + if (asprintf (&modulesdir[0], MODULEDIRFMT, release) < 0) return -1; FTS *fts = fts_open (modulesdir, FTS_LOGICAL | FTS_NOSTAT, NULL); @@ -609,14 +612,21 @@ dwfl_linux_kernel_report_modules (Dwfl *dwfl) Dwarf_Addr modaddr; unsigned long int modsz; char modname[128]; - while (fscanf (f, "%128s %lu %*s %*s %*s %" PRIx64 "\n", - modname, &modsz, &modaddr) == 3) + char *line = NULL; + size_t linesz = 0; + /* We can't just use fscanf here because it's not easy to distinguish \n + from other whitespace so as to take the optional word following the + address but always stop at the end of the line. */ + while (getline (&line, &linesz, f) > 0 + && sscanf (line, "%128s %lu %*s %*s %*s %" PRIx64 " %*s\n", + modname, &modsz, &modaddr) == 3) if (INTUSE(dwfl_report_module) (dwfl, modname, modaddr, modaddr + modsz) == NULL) { result = -1; break; } + free (line); if (result == 0) result = ferror_unlocked (f) ? errno : feof_unlocked (f) ? 0 : ENOEXEC; diff --git a/libdwfl/offline.c b/libdwfl/offline.c index beeb0abf2..0a0645ef3 100644 --- a/libdwfl/offline.c +++ b/libdwfl/offline.c @@ -65,21 +65,53 @@ dwfl_offline_section_address (Dwfl_Module *mod, const GElf_Shdr *shdr __attribute__ ((unused)), Dwarf_Addr *addr) { - GElf_Shdr shdr_mem; - GElf_Shdr *main_shdr = gelf_getshdr (elf_getscn (mod->main.elf, shndx), - &shdr_mem); - if (unlikely (main_shdr == NULL)) - return -1; - + assert (mod->e_type == ET_REL); assert (shdr->sh_addr == 0); assert (shdr->sh_flags & SHF_ALLOC); - assert (main_shdr->sh_flags == shdr->sh_flags); - if (main_shdr->sh_addr != 0) - assert (mod->symfile != &mod->main); + if (mod->symfile == &mod->main) + { + /* Because the actual address is zero, we failed to notice + we in fact had the right address cached already. */ + *addr = 0; + return 0; + } + + /* The section numbers might not match between the two files. + The best we can rely on is the order of SHF_ALLOC sections. */ + + Elf_Scn *ourscn = elf_getscn (mod->symfile->elf, shndx); + Elf_Scn *scn = NULL; + uint_fast32_t skip_alloc = 0; + while ((scn = elf_nextscn (mod->symfile->elf, scn)) != ourscn) + { + assert (scn != NULL); + GElf_Shdr shdr_mem; + GElf_Shdr *sh = gelf_getshdr (scn, &shdr_mem); + if (unlikely (sh == NULL)) + return -1; + if (sh->sh_flags & SHF_ALLOC) + ++skip_alloc; + } + + scn = NULL; + while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL) + { + GElf_Shdr shdr_mem; + GElf_Shdr *main_shdr = gelf_getshdr (elf_getscn (mod->main.elf, shndx), + &shdr_mem); + if (unlikely (main_shdr == NULL)) + return -1; + if ((main_shdr->sh_flags & SHF_ALLOC) && skip_alloc-- == 0) + { + assert (main_shdr->sh_flags == shdr->sh_flags); + *addr = main_shdr->sh_addr; + return 0; + } + } - *addr = main_shdr->sh_addr; - return 0; + /* This should never happen. */ + return -1; } INTDEF (dwfl_offline_section_address) diff --git a/src/ChangeLog b/src/ChangeLog index 39b64ff09..d22769513 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,58 @@ +2007-05-18 Roland McGrath + + * unstrip.c (copy_elided_sections): Match up non-NOBITS sections with + stripped file, so as not to duplicate a section copied in both. + + * strip.c (handle_elf): Keep SHT_NOTE section copies in the debug file. + +2007-05-17 Roland McGrath + + * unstrip.c (copy_elided_sections): Don't call gelf_newphdr for 0. + + * unstrip.c (handle_file): Tweak BIAS != 0 warning. + + * unstrip.c (handle_file): Take new arg CREATE_DIRS. If set, + call make_directories here. + (handle_explicit_files): Take new arg CREATE_DIRS, pass it down. + (handle_dwfl_module): Likewise. + (handle_implicit_modules): Update callers. + (handle_output_dir_module): Likewise. Don't do make_directories here. + + * unstrip.c (get_section_name): New function, broken out of ... + (copy_elided_sections): here. Update callers. + (find_alloc_section): Broken out of ... + (copy_elided_sections): ... here. Update caller. + (symtab_count_leading_section_symbols): Take new arg NEWSYMDATA, + update STT_SECTION symbols' st_value fields as a side effect. + (check_symtab_section_symbols): Update caller. + (add_new_section_symbols): Set st_value in symbols added. + (collect_symbols): Reset S->value for STT_SECTION symbols recorded. + Take new arg SPLIT_BSS. Adjust S->shndx recorded for symbols moved + from .bss to .dynbss. + (find_alloc_sections_prelink): New function. Associate debug file + allocated SHT_NOBITS shdrs with stripped moved by prelink via + .gnu.prelink_undo information. + (copy_elided_sections): Call it when we couldn't find every allocated + section. Don't use a debug file non-NOBITS section if SHF_ALLOC. + Take STRIPPED_EHDR arg instead of E_TYPE and PHNUM. + (handle_file): Update callers. + + * unstrip.c (copy_elided_sections): Ignore unfound unallocated section + named ".comment". + + * elflint.c (check_sections): Fix association of segments with + sections when p_memsz > p_filesz. + +2007-04-29 Roland McGrath + + * addr2line.c (options, main): Tweak argp group settings to fix + usage output. + +2007-04-28 Roland McGrath + + * strip.c (handle_elf): Update debug file's SHT_NOBITS sections' + sizes to match sections adjusted in the stripped file. + 2007-04-24 Roland McGrath * elfcmp.c (OPT_HASH_INEXACT): New macro. diff --git a/src/addr2line.c b/src/addr2line.c index e133e7af9..6f6de1f7e 100644 --- a/src/addr2line.c +++ b/src/addr2line.c @@ -61,7 +61,7 @@ const char *argp_program_bug_address = PACKAGE_BUGREPORT; /* Definitions of arguments for argp functions. */ static const struct argp_option options[] = { - { NULL, 0, NULL, 0, N_("Output Selection:"), 0 }, + { NULL, 0, NULL, 0, N_("Output selection options:"), 2 }, { "basenames", 's', NULL, 0, N_("Show only base names of source files"), 0 }, { "absolute", 'A', NULL, 0, N_("Show absolute file names using compilation directory"), 0 }, @@ -131,6 +131,7 @@ main (int argc, char *argv[]) /* Parse and process arguments. This includes opening the modules. */ argp_children[0].argp = dwfl_standard_argp (); + argp_children[0].group = 1; Dwfl *dwfl = NULL; (void) argp_parse (&argp, argc, argv, 0, &remaining, &dwfl); assert (dwfl != NULL); diff --git a/src/elflint.c b/src/elflint.c index 09c7fbd2f..db3b49c1b 100644 --- a/src/elflint.c +++ b/src/elflint.c @@ -3407,7 +3407,9 @@ section [%2zu] '%s': merge flag set but entry size is zero\n"), || (phdr->p_type == PT_TLS && (shdr->sh_flags & SHF_TLS) != 0)) && phdr->p_offset <= shdr->sh_offset - && phdr->p_offset + phdr->p_memsz > shdr->sh_offset) + && (phdr->p_offset + phdr->p_filesz > shdr->sh_offset + || (phdr->p_offset + phdr->p_memsz > shdr->sh_offset + && shdr->sh_type == SHT_NOBITS))) { /* Found the segment. */ if (phdr->p_offset + phdr->p_memsz diff --git a/src/strip.c b/src/strip.c index 95eded657..5a2da6464 100644 --- a/src/strip.c +++ b/src/strip.c @@ -835,6 +835,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, elf_errmsg (-1)); bool discard_section = (shdr_info[cnt].idx > 0 + && shdr_info[cnt].shdr.sh_type != SHT_NOTE && cnt != ehdr->e_shstrndx); /* Set the section header in the new file. */ @@ -1251,6 +1252,24 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, symbol table. */ for (cnt = 1; cnt <= shdridx; ++cnt) { + /* Update section headers when the data size has changed. + We also update the SHT_NOBITS section in the debug + file so that the section headers match in sh_size. */ + inline void update_section_size (const Elf_Data *newdata) + { + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + shdr->sh_size = newdata->d_size; + (void) gelf_update_shdr (scn, shdr); + if (debugelf != NULL) + { + /* libelf will use d_size to set sh_size. */ + Elf_Data *debugdata = elf_getdata (elf_getscn (debugelf, + cnt), NULL); + debugdata->d_size = newdata->d_size; + } + } + if (shdr_info[cnt].idx == 0 && debug_fname == NULL) /* Ignore sections which are discarded. When we are saving a relocation section in a separate debug file, we must fix up @@ -1354,12 +1373,9 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, Elf32_Word *chain = bucket + nbucket; /* New size of the section. */ - GElf_Shdr shdr_mem; - GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); - shdr->sh_size = hashd->d_size - = (2 + symd->d_size / elsize + nbucket) - * sizeof (Elf32_Word); - (void) gelf_update_shdr (scn, shdr); + hashd->d_size = ((2 + symd->d_size / elsize + nbucket) + * sizeof (Elf32_Word)); + update_section_size (hashd); /* Clear the arrays. */ memset (bucket, '\0', @@ -1411,12 +1427,9 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, Elf64_Xword *chain = bucket + nbucket; /* New size of the section. */ - GElf_Shdr shdr_mem; - GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); - shdr->sh_size = hashd->d_size - = (2 + symd->d_size / elsize + nbucket) - * sizeof (Elf64_Xword); - (void) gelf_update_shdr (scn, shdr); + hashd->d_size = ((2 + symd->d_size / elsize + nbucket) + * sizeof (Elf64_Xword)); + update_section_size (hashd); /* Clear the arrays. */ memset (bucket, '\0', @@ -1492,14 +1505,12 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, verstab[newsymidx[inner]] = verstab[inner]; /* New size of the section. */ - GElf_Shdr shdr_mem; - GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); - shdr->sh_size = verd->d_size - = gelf_fsize (newelf, verd->d_type, - symd->d_size / gelf_fsize (elf, symd->d_type, 1, - ehdr->e_version), - ehdr->e_version); - (void) gelf_update_shdr (scn, shdr); + verd->d_size = gelf_fsize (newelf, verd->d_type, + symd->d_size + / gelf_fsize (elf, symd->d_type, 1, + ehdr->e_version), + ehdr->e_version); + update_section_size (verd); } else if (shdr_info[cnt].shdr.sh_type == SHT_GROUP) { diff --git a/src/unstrip.c b/src/unstrip.c index 25ce1f37b..98e165ce8 100644 --- a/src/unstrip.c +++ b/src/unstrip.c @@ -270,6 +270,27 @@ copy_elf (Elf *outelf, Elf *inelf) } } +/* Create directories containing PATH. */ +static void +make_directories (const char *path) +{ + const char *lastslash = strrchr (path, '/'); + if (lastslash == NULL) + return; + + while (lastslash > path && lastslash[-1] == '/') + --lastslash; + if (lastslash == path) + return; + + char *dir = strndupa (path, lastslash - path); + while (mkdir (dir, 0777) < 0 && errno != EEXIST) + if (errno == ENOENT) + make_directories (dir); + else + error (EXIT_FAILURE, errno, _("cannot create directory '%s'"), dir); +} + /* The binutils linker leaves gratuitous section symbols in .symtab that strip has to remove. Older linkers likewise include a @@ -293,9 +314,11 @@ section_can_shrink (const GElf_Shdr *shdr) } /* See if this symbol table has a leading section symbol for every single - section, in order. The binutils linker produces this. */ + section, in order. The binutils linker produces this. While we're here, + update each section symbol's st_value. */ static size_t -symtab_count_leading_section_symbols (Elf_Scn *scn, size_t shnum) +symtab_count_leading_section_symbols (Elf *elf, Elf_Scn *scn, size_t shnum, + Elf_Data *newsymdata) { Elf_Data *data = elf_getdata (scn, NULL); Elf_Data *shndxdata = NULL; /* XXX */ @@ -306,11 +329,22 @@ symtab_count_leading_section_symbols (Elf_Scn *scn, size_t shnum) GElf_Word shndx = SHN_UNDEF; GElf_Sym *sym = gelf_getsymshndx (data, shndxdata, i, &sym_mem, &shndx); ELF_CHECK (sym != NULL, _("cannot get symbol table entry: %s")); + + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (elf_getscn (elf, i), &shdr_mem); + ELF_CHECK (shdr != NULL, _("cannot get section header: %s")); + if (sym->st_shndx != SHN_XINDEX) shndx = sym->st_shndx; if (shndx != i || GELF_ST_TYPE (sym->st_info) != STT_SECTION) return i; + + sym->st_value = shdr->sh_addr; + if (sym->st_shndx != SHN_XINDEX) + shndx = SHN_UNDEF; + ELF_CHECK (gelf_update_symshndx (newsymdata, shndxdata, i, sym, shndx), + _("cannot update symbol table: %s")); } return shnum; @@ -489,7 +523,7 @@ adjust_all_relocs (Elf *elf, Elf_Scn *symtab, const GElf_Shdr *symshdr, /* The original file probably had section symbols for all of its sections, even the unallocated ones. To match it as closely as - possible, to add in section symbols for the added sections. */ + possible, add in section symbols for the added sections. */ static Elf_Data * add_new_section_symbols (Elf_Scn *old_symscn, size_t old_shnum, Elf *elf, Elf_Scn *symscn, size_t shnum) @@ -534,8 +568,12 @@ add_new_section_symbols (Elf_Scn *old_symscn, size_t old_shnum, /* Add in the new section symbols. */ for (size_t i = old_shnum; i < shnum; ++i) { + GElf_Shdr i_shdr_mem; + GElf_Shdr *i_shdr = gelf_getshdr (elf_getscn (elf, i), &i_shdr_mem); + ELF_CHECK (i_shdr != NULL, _("cannot get section header: %s")); GElf_Sym sym = { + .st_value = i_shdr->sh_addr, .st_info = GELF_ST_INFO (STB_LOCAL, STT_SECTION), .st_shndx = i < SHN_LORESERVE ? i : SHN_XINDEX }; @@ -565,13 +603,16 @@ add_new_section_symbols (Elf_Scn *old_symscn, size_t old_shnum, return symdata; } +/* This has the side effect of updating STT_SECTION symbols' values, + in case of prelink adjustments. */ static Elf_Data * check_symtab_section_symbols (Elf *elf, Elf_Scn *scn, size_t shnum, size_t shstrndx, Elf_Scn *oscn, size_t oshnum, size_t oshstrndx, size_t debuglink) { - size_t n = symtab_count_leading_section_symbols (oscn, oshnum); + size_t n = symtab_count_leading_section_symbols (elf, oscn, oshnum, + elf_getdata (scn, NULL)); if (n == oshnum) return add_new_section_symbols (oscn, n, elf, scn, shnum); @@ -659,9 +700,10 @@ struct symbol /* Collect input symbols into our internal form. */ static void -collect_symbols (Elf_Scn *symscn, Elf_Scn *strscn, +collect_symbols (Elf *outelf, Elf_Scn *symscn, Elf_Scn *strscn, const size_t nent, const GElf_Addr bias, - const size_t scnmap[], struct symbol *table, size_t *map) + const size_t scnmap[], struct symbol *table, size_t *map, + struct section *split_bss) { Elf_Data *symdata = elf_getdata (symscn, NULL); Elf_Data *strdata = elf_getdata (strscn, NULL); @@ -677,9 +719,6 @@ collect_symbols (Elf_Scn *symscn, Elf_Scn *strscn, if (sym->st_shndx != SHN_XINDEX) shndx = sym->st_shndx; - if (scnmap != NULL && shndx != SHN_UNDEF && shndx < SHN_LORESERVE) - shndx = scnmap[shndx - 1]; - if (sym->st_name >= strdata->d_size) error (EXIT_FAILURE, 0, _("invalid string offset in symbol [%Zu]"), i); @@ -692,6 +731,27 @@ collect_symbols (Elf_Scn *symscn, Elf_Scn *strscn, s->shndx = shndx; s->info.info = sym->st_info; s->info.other = sym->st_other; + + if (scnmap != NULL && shndx != SHN_UNDEF && shndx < SHN_LORESERVE) + s->shndx = scnmap[shndx - 1]; + + if (GELF_ST_TYPE (s->info.info) == STT_SECTION) + { + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (elf_getscn (outelf, shndx), + &shdr_mem); + ELF_CHECK (shdr != NULL, _("cannot get section header: %s")); + + if (GELF_ST_TYPE (s->info.info) == STT_SECTION) + /* Update the value to match the output section. */ + s->value = shdr->sh_addr; + } + else if (split_bss != NULL + && s->value < split_bss->shdr.sh_addr + && s->value >= split_bss[-1].shdr.sh_addr + && shndx == elf_ndxscn (split_bss->outscn)) + /* This symbol was in .bss and was split into .dynbss. */ + s->shndx = elf_ndxscn (split_bss[-1].outscn); } } @@ -759,11 +819,286 @@ compare_symbols_output (const void *a, const void *b) #undef CMP +/* Locate a matching allocated section in SECTIONS. */ +static struct section * +find_alloc_section (const GElf_Shdr *shdr, GElf_Addr bias, const char *name, + struct section sections[], size_t nalloc) +{ + const GElf_Addr addr = shdr->sh_addr + bias; + size_t l = 0, u = nalloc; + while (l < u) + { + size_t i = (l + u) / 2; + if (addr < sections[i].shdr.sh_addr) + u = i; + else if (addr > sections[i].shdr.sh_addr) + l = i + 1; + else + { + /* We've found allocated sections with this address. + Find one with matching size, flags, and name. */ + while (i > 0 && sections[i - 1].shdr.sh_addr == addr) + --i; + for (; i < nalloc && sections[i].shdr.sh_addr == addr; + ++i) + if (sections[i].shdr.sh_flags == shdr->sh_flags + && (sections[i].shdr.sh_size == shdr->sh_size + || (sections[i].shdr.sh_size < shdr->sh_size + && section_can_shrink (§ions[i].shdr))) + && !strcmp (sections[i].name, name)) + return §ions[i]; + break; + } + } + return NULL; +} + +static inline const char * +get_section_name (size_t ndx, const GElf_Shdr *shdr, const Elf_Data *shstrtab) +{ + if (shdr->sh_name >= shstrtab->d_size) + error (EXIT_FAILURE, 0, _("cannot read section [%Zu] name: %s"), + ndx, elf_errmsg (-1)); + return shstrtab->d_buf + shdr->sh_name; +} + +/* Fix things up when prelink has moved some allocated sections around + and the debuginfo file's section headers no longer match up. + This fills in SECTIONS[0..NALLOC-1].outscn or exits. + If there was a .bss section that was split into two sections + with the new one preceding it in sh_addr, we return that pointer. */ +static struct section * +find_alloc_sections_prelink (Elf *debug, Elf_Data *debug_shstrtab, + Elf *main, const GElf_Ehdr *main_ehdr, + Elf_Data *main_shstrtab, GElf_Addr bias, + struct section *sections, + size_t nalloc, size_t nsections) +{ + /* Clear assignments that might have been bogus. */ + for (size_t i = 0; i < nalloc; ++i) + sections[i].outscn = NULL; + + Elf_Scn *undo = NULL; + for (size_t i = nalloc; i < nsections; ++i) + { + const struct section *sec = §ions[i]; + if (sec->shdr.sh_type == SHT_PROGBITS + && !(sec->shdr.sh_flags & SHF_ALLOC) + && !strcmp (sec->name, ".gnu.prelink_undo")) + { + undo = sec->scn; + break; + } + } + + /* Find the original allocated sections before prelinking. */ + struct section *undo_sections = NULL; + size_t undo_nalloc = 0; + if (undo != NULL) + { + Elf_Data *undodata = elf_rawdata (undo, NULL); + ELF_CHECK (undodata != NULL, + _("cannot read '.gnu.prelink_undo' section: %s")); + + union + { + Elf32_Ehdr e32; + Elf64_Ehdr e64; + } ehdr; + Elf_Data dst = + { + .d_buf = &ehdr, + .d_size = sizeof ehdr, + .d_type = ELF_T_EHDR, + .d_version = EV_CURRENT + }; + Elf_Data src = *undodata; + src.d_size = gelf_fsize (main, ELF_T_EHDR, 1, EV_CURRENT); + src.d_type = ELF_T_EHDR; + ELF_CHECK (gelf_xlatetom (main, &dst, &src, + main_ehdr->e_ident[EI_DATA]) != NULL, + _("cannot read '.gnu.prelink_undo' section: %s")); + + uint_fast16_t phnum; + uint_fast16_t shnum; + if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32) + { + phnum = ehdr.e32.e_phnum; + shnum = ehdr.e32.e_shnum; + } + else + { + phnum = ehdr.e64.e_phnum; + shnum = ehdr.e64.e_shnum; + } + + size_t phsize = gelf_fsize (main, ELF_T_PHDR, phnum, EV_CURRENT); + src.d_buf += src.d_size + phsize; + src.d_size = gelf_fsize (main, ELF_T_SHDR, shnum - 1, EV_CURRENT); + src.d_type = ELF_T_SHDR; + if ((size_t) (src.d_buf - undodata->d_buf) > undodata->d_size + || undodata->d_size - (src.d_buf - undodata->d_buf) != src.d_size) + error (EXIT_FAILURE, 0, _("invalid contents in '%s' section"), + ".gnu.prelink_undo"); + + union + { + Elf32_Shdr s32[shnum - 1]; + Elf64_Shdr s64[shnum - 1]; + } shdr; + dst.d_buf = &shdr; + dst.d_size = sizeof shdr; + ELF_CHECK (gelf_xlatetom (main, &dst, &src, + main_ehdr->e_ident[EI_DATA]) != NULL, + _("cannot read '.gnu.prelink_undo' section: %s")); + + undo_sections = xmalloc ((shnum - 1) * sizeof undo_sections[0]); + for (size_t i = 0; i < shnum - 1; ++i) + { + struct section *sec = &undo_sections[undo_nalloc]; + if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32) + { +#define COPY(field) sec->shdr.field = shdr.s32[i].field + COPY (sh_name); + COPY (sh_type); + COPY (sh_flags); + COPY (sh_addr); + COPY (sh_offset); + COPY (sh_size); + COPY (sh_link); + COPY (sh_info); + COPY (sh_addralign); + COPY (sh_entsize); +#undef COPY + } + else + sec->shdr = shdr.s64[i]; + if (sec->shdr.sh_flags & SHF_ALLOC) + { + sec->shdr.sh_addr += bias; + sec->name = get_section_name (i + 1, &sec->shdr, main_shstrtab); + sec->scn = elf_getscn (main, i + 1); /* Really just for ndx. */ + sec->outscn = NULL; + sec->strent = NULL; + ++undo_nalloc; + } + } + qsort (undo_sections, undo_nalloc, + sizeof undo_sections[0], compare_sections); + } + + bool fail = false; + inline void check_match (bool match, Elf_Scn *scn, const char *name) + { + if (!match) + { + fail = true; + error (0, 0, _("cannot find matching section for [%Zu] '%s'"), + elf_ndxscn (scn), name); + } + } + + Elf_Scn *scn = NULL; + while ((scn = elf_nextscn (debug, scn)) != NULL) + { + GElf_Shdr shdr_mem; + GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); + ELF_CHECK (shdr != NULL, _("cannot get section header: %s")); + + if (!(shdr->sh_flags & SHF_ALLOC)) + continue; + + const char *name = get_section_name (elf_ndxscn (scn), shdr, + debug_shstrtab); + + if (undo_sections != NULL) + { + struct section *sec = find_alloc_section (shdr, 0, name, + undo_sections, + undo_nalloc); + if (sec != NULL) + { + sec->outscn = scn; + continue; + } + } + + /* If there is no prelink info, we are just here to find + the sections to give error messages about. */ + for (size_t i = 0; shdr != NULL && i < nalloc; ++i) + if (sections[i].outscn == scn) + shdr = NULL; + check_match (shdr == NULL, scn, name); + } + + if (fail) + exit (EXIT_FAILURE); + + /* Now we have lined up output sections for each of the original sections + before prelinking. Translate those to the prelinked sections. + This matches what prelink's undo_sections does. */ + struct section *split_bss = NULL; + for (size_t i = 0; i < undo_nalloc; ++i) + { + const struct section *undo_sec = &undo_sections[i]; + + const char *name = undo_sec->name; + scn = undo_sec->scn; /* This is just for elf_ndxscn. */ + + for (size_t j = 0; j < nalloc; ++j) + { + struct section *sec = §ions[j]; +#define RELA_SCALED(field) \ + (2 * sec->shdr.field == 3 * undo_sec->shdr.field) + if (sec->outscn == NULL + && sec->shdr.sh_name == undo_sec->shdr.sh_name + && sec->shdr.sh_flags == undo_sec->shdr.sh_flags + && sec->shdr.sh_addralign == undo_sec->shdr.sh_addralign + && (((sec->shdr.sh_type == undo_sec->shdr.sh_type + && sec->shdr.sh_entsize == undo_sec->shdr.sh_entsize + && (sec->shdr.sh_size == undo_sec->shdr.sh_size + || (sec->shdr.sh_size > undo_sec->shdr.sh_size + && main_ehdr->e_type == ET_EXEC + && !strcmp (sec->name, ".dynstr")))) + || (sec->shdr.sh_size == undo_sec->shdr.sh_size + && ((sec->shdr.sh_entsize == undo_sec->shdr.sh_entsize + && undo_sec->shdr.sh_type == SHT_NOBITS) + || undo_sec->shdr.sh_type == SHT_PROGBITS) + && !strcmp (sec->name, ".plt"))) + || (sec->shdr.sh_type == SHT_RELA + && undo_sec->shdr.sh_type == SHT_REL + && RELA_SCALED (sh_entsize) && RELA_SCALED (sh_size)) + || (sec->shdr.sh_entsize == undo_sec->shdr.sh_entsize + && (sec->shdr.sh_type == undo_sec->shdr.sh_type + || (sec->shdr.sh_type == SHT_PROGBITS + && undo_sec->shdr.sh_type == SHT_NOBITS)) + && sec->shdr.sh_size < undo_sec->shdr.sh_size + && (!strcmp (sec->name, ".bss") + || !strcmp (sec->name, ".sbss")) + && (split_bss = sec) > sections))) + { + sec->outscn = undo_sec->outscn; + undo_sec = NULL; + break; + } + } + + check_match (undo_sec == NULL, scn, name); + } + + free (undo_sections); + + if (fail) + exit (EXIT_FAILURE); + + return split_bss; +} + /* Fill in any SHT_NOBITS sections in UNSTRIPPED by copying their contents and sh_type from STRIPPED. */ static void -copy_elided_sections (Elf *unstripped, Elf *stripped, uint_fast16_t e_type, - uint_fast16_t phnum, GElf_Addr bias) +copy_elided_sections (Elf *unstripped, Elf *stripped, + const GElf_Ehdr *stripped_ehdr, GElf_Addr bias) { size_t unstripped_shstrndx; ELF_CHECK (elf_getshstrndx (unstripped, &unstripped_shstrndx) == 0, @@ -811,39 +1146,6 @@ copy_elided_sections (Elf *unstripped, Elf *stripped, uint_fast16_t e_type, stripped_symtab = §ions[nalloc]; } - /* Locate a matching allocated section in SECTIONS. */ - inline struct section *find_alloc_section (const GElf_Shdr *shdr, - const char *name) - { - const GElf_Addr addr = shdr->sh_addr + bias; - size_t l = 0, u = nalloc; - while (l < u) - { - size_t i = (l + u) / 2; - if (addr < sections[i].shdr.sh_addr) - u = i; - else if (addr > sections[i].shdr.sh_addr) - l = i + 1; - else - { - /* We've found allocated sections with this address. - Find one with matching size, flags, and name. */ - while (i > 0 && sections[i - 1].shdr.sh_addr == addr) - --i; - for (; i < nalloc && sections[i].shdr.sh_addr == addr; - ++i) - if (sections[i].shdr.sh_flags == shdr->sh_flags - && (sections[i].shdr.sh_size == shdr->sh_size - || (sections[i].shdr.sh_size < shdr->sh_size - && section_can_shrink (§ions[i].shdr))) - && !strcmp (sections[i].name, name)) - return §ions[i]; - break; - } - } - return NULL; - } - /* Locate a matching unallocated section in SECTIONS. */ inline struct section *find_unalloc_section (const GElf_Shdr *shdr, const char *name) @@ -869,16 +1171,9 @@ copy_elided_sections (Elf *unstripped, Elf *stripped, uint_fast16_t e_type, unstripped_shstrndx), NULL); ELF_CHECK (shstrtab != NULL, _("cannot read section header string table: %s")); - inline const char *unstripped_section_name (Elf_Scn *sec, - const GElf_Shdr *shdr) - { - if (shdr->sh_name >= shstrtab->d_size) - error (EXIT_FAILURE, 0, _("cannot read section [%Zu] name: %s"), - elf_ndxscn (sec), elf_errmsg (-1)); - return shstrtab->d_buf + shdr->sh_name; - } /* Match each debuginfo section with its corresponding stripped section. */ + bool check_prelink = false; Elf_Scn *unstripped_symtab = NULL; size_t unstripped_strtab_ndx = SHN_UNDEF; scn = NULL; @@ -888,31 +1183,68 @@ copy_elided_sections (Elf *unstripped, Elf *stripped, uint_fast16_t e_type, GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); ELF_CHECK (shdr != NULL, _("cannot get section header: %s")); - /* Anything not already SHT_NOBITS is fine as it stands. */ - if (shdr->sh_type != SHT_NOBITS) + if (shdr->sh_type == SHT_SYMTAB) { - if (shdr->sh_type == SHT_SYMTAB) - { - unstripped_symtab = scn; - unstripped_strtab_ndx = shdr->sh_link; - } + unstripped_symtab = scn; + unstripped_strtab_ndx = shdr->sh_link; continue; } - const char *name = unstripped_section_name (scn, shdr); + const size_t ndx = elf_ndxscn (scn); + if (ndx == unstripped_shstrndx) + continue; + + const char *name = get_section_name (ndx, shdr, shstrtab); /* Look for the section that matches. */ struct section *sec = ((shdr->sh_flags & SHF_ALLOC) - ? find_alloc_section (shdr, name) + ? find_alloc_section (shdr, bias, name, + sections, nalloc) : find_unalloc_section (shdr, name)); if (sec == NULL) - error (EXIT_FAILURE, 0, - _("cannot find matching section for [%Zu] '%s'"), - elf_ndxscn (scn), name); + { + if ((shdr->sh_flags & SHF_ALLOC) && stripped_ehdr->e_type != ET_REL) + { + /* If we couldn't figure it out, it may be a prelink issue. */ + check_prelink = true; + continue; + } + + /* An additional unallocated section is fine if not SHT_NOBITS. + We looked it up anyway in case it's an unallocated section + copied in both files (e.g. SHT_NOTE), so we don't keep both. */ + if (shdr->sh_type != SHT_NOBITS && !(shdr->sh_flags & SHF_ALLOC)) + continue; + + /* Somehow some old .debug files wound up with SHT_NOBITS + .comment sections, so let those pass. */ + if (!(shdr->sh_flags & SHF_ALLOC) && !strcmp (name, ".comment")) + continue; + + error (EXIT_FAILURE, 0, + _("cannot find matching section for [%Zu] '%s'"), + elf_ndxscn (scn), name); + } sec->outscn = scn; } + /* If that failed due to changes made by prelink, we take another tack. + We keep track of a .bss section that was partly split into .dynbss + so that collect_symbols can update symbols' st_shndx fields. */ + struct section *split_bss = NULL; + if (check_prelink) + { + Elf_Data *data = elf_getdata (elf_getscn (stripped, stripped_shstrndx), + NULL); + ELF_CHECK (data != NULL, + _("cannot read section header string table: %s")); + split_bss = find_alloc_sections_prelink (unstripped, shstrtab, + stripped, stripped_ehdr, + data, bias, sections, + nalloc, stripped_shnum - 1); + } + /* Make sure each main file section has a place to go. */ const struct section *stripped_dynsym = NULL; size_t debuglink = SHN_UNDEF; @@ -1006,7 +1338,7 @@ copy_elided_sections (Elf *unstripped, Elf *stripped, uint_fast16_t e_type, scn = elf_getscn (unstripped, i + 1); GElf_Shdr shdr_mem; GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); - const char *name = unstripped_section_name (scn, shdr); + const char *name = get_section_name (i + 1, shdr, shstrtab); unstripped_strent[i] = ebl_strtabadd (strtab, name, 0); ELF_CHECK (unstripped_strent[i] != NULL, _("cannot add section name to string table: %s")); @@ -1075,7 +1407,7 @@ copy_elided_sections (Elf *unstripped, Elf *stripped, uint_fast16_t e_type, elf_flagdata (outdata, ELF_C_SET, ELF_F_DIRTY); /* Preserve the file layout of the allocated sections. */ - if (e_type != ET_REL && (shdr_mem.sh_flags & SHF_ALLOC)) + if (stripped_ehdr->e_type != ET_REL && (shdr_mem.sh_flags & SHF_ALLOC)) { shdr_mem.sh_offset = sec->shdr.sh_offset; placed[elf_ndxscn (sec->outscn) - 1] = true; @@ -1140,7 +1472,9 @@ copy_elided_sections (Elf *unstripped, Elf *stripped, uint_fast16_t e_type, struct Ebl_Strtab *symstrtab = NULL; Elf_Data *symstrdata = NULL; if (unstripped_symtab != NULL && (stripped_symtab != NULL - || (e_type != ET_REL && bias != 0))) + || check_prelink /* Section adjustments. */ + || (stripped_ehdr->e_type != ET_REL + && bias != 0))) { /* Merge the stripped file's symbol table into the unstripped one. */ const size_t stripped_nsym = (stripped_symtab == NULL ? 1 @@ -1159,16 +1493,17 @@ copy_elided_sections (Elf *unstripped, Elf *stripped, uint_fast16_t e_type, size_t symndx_map[total_syms]; if (stripped_symtab != NULL) - collect_symbols (stripped_symtab->scn, + collect_symbols (unstripped, stripped_symtab->scn, elf_getscn (stripped, stripped_symtab->shdr.sh_link), stripped_nsym, 0, ndx_section, - symbols, symndx_map); + symbols, symndx_map, NULL); Elf_Scn *unstripped_strtab = elf_getscn (unstripped, shdr->sh_link); - collect_symbols (unstripped_symtab, unstripped_strtab, - unstripped_nsym, e_type == ET_REL ? 0 : bias, NULL, + collect_symbols (unstripped, + unstripped_symtab, unstripped_strtab, unstripped_nsym, + stripped_ehdr->e_type == ET_REL ? 0 : bias, NULL, &symbols[stripped_nsym - 1], - &symndx_map[stripped_nsym - 1]); + &symndx_map[stripped_nsym - 1], split_bss); /* Next, sort our array of all symbols. */ qsort (symbols, total_syms, sizeof symbols[0], compare_symbols); @@ -1243,13 +1578,17 @@ copy_elided_sections (Elf *unstripped, Elf *stripped, uint_fast16_t e_type, ELF_CHECK (gelf_update_shdr (unstripped_symtab, shdr), _("cannot update section header: %s")); - /* Adjust any relocations referring to the old symbol table. */ - const size_t old_sh_link = elf_ndxscn (stripped_symtab->scn); - for (const struct section *sec = sections; - sec < §ions[stripped_shnum - 1]; - ++sec) - if (sec->outscn != NULL && sec->shdr.sh_link == old_sh_link) - adjust_relocs (sec->outscn, sec->scn, &sec->shdr, symndx_map, shdr); + if (stripped_symtab != NULL) + { + /* Adjust any relocations referring to the old symbol table. */ + const size_t old_sh_link = elf_ndxscn (stripped_symtab->scn); + for (const struct section *sec = sections; + sec < §ions[stripped_shnum - 1]; + ++sec) + if (sec->outscn != NULL && sec->shdr.sh_link == old_sh_link) + adjust_relocs (sec->outscn, sec->scn, &sec->shdr, + symndx_map, shdr); + } /* Also adjust references to the other old symbol table. */ adjust_all_relocs (unstripped, unstripped_symtab, shdr, @@ -1328,8 +1667,12 @@ copy_elided_sections (Elf *unstripped, Elf *stripped, uint_fast16_t e_type, } } while (skip_reloc); + if (stripped_ehdr->e_phnum > 0) + ELF_CHECK (gelf_newphdr (unstripped, stripped_ehdr->e_phnum), + _("cannot create program headers: %s")); + /* Copy each program header from the stripped file. */ - for (uint_fast16_t i = 0; i < phnum; ++i) + for (uint_fast16_t i = 0; i < stripped_ehdr->e_phnum; ++i) { GElf_Phdr phdr_mem; GElf_Phdr *phdr = gelf_getphdr (stripped, i, &phdr_mem); @@ -1360,7 +1703,7 @@ copy_elided_sections (Elf *unstripped, Elf *stripped, uint_fast16_t e_type, /* Process one pair of files, already opened. */ static void -handle_file (const char *output_file, +handle_file (const char *output_file, bool create_dirs, Elf *stripped, const GElf_Ehdr *stripped_ehdr, Elf *unstripped) { @@ -1387,15 +1730,24 @@ handle_file (const char *output_file, /* One day we could adjust all the DWARF data (like prelink itself does). */ if (bias != 0) - error (0, 0, - _("DWARF output not adjusted for prelinking bias; use prelink -u")); + { + if (output_file == NULL) + error (0, 0, _("\ +DWARF data not adjusted for prelinking bias; consider prelink -u")); + else + error (0, 0, _("\ +DWARF data in '%s' not adjusted for prelinking bias; consider prelink -u"), + output_file); + } if (output_file == NULL) /* Modify the unstripped file in place. */ - copy_elided_sections (unstripped, stripped, stripped_ehdr->e_type, - stripped_ehdr->e_phnum, bias); + copy_elided_sections (unstripped, stripped, stripped_ehdr, bias); else { + if (create_dirs) + make_directories (output_file); + /* Copy the unstripped file and then modify it. */ int outfd = open64 (output_file, O_RDWR | O_CREAT, stripped_ehdr->e_type == ET_REL ? 0666 : 0777); @@ -1416,8 +1768,7 @@ handle_file (const char *output_file, else { copy_elf (outelf, unstripped); - copy_elided_sections (outelf, stripped, stripped_ehdr->e_type, - stripped_ehdr->e_phnum, bias); + copy_elided_sections (outelf, stripped, stripped_ehdr, bias); } elf_end (outelf); @@ -1436,7 +1787,7 @@ open_file (const char *file, bool writable) /* Handle a pair of files we need to open by name. */ static void -handle_explicit_files (const char *output_file, +handle_explicit_files (const char *output_file, bool create_dirs, const char *stripped_file, const char *unstripped_file) { int stripped_fd = open_file (stripped_file, false); @@ -1465,7 +1816,7 @@ handle_explicit_files (const char *output_file, stripped_file, unstripped_file); } - handle_file (output_file, stripped, &stripped_ehdr, unstripped); + handle_file (output_file, create_dirs, stripped, &stripped_ehdr, unstripped); elf_end (stripped); close (stripped_fd); @@ -1477,8 +1828,8 @@ handle_explicit_files (const char *output_file, /* Handle a pair of files opened implicitly by libdwfl for one module. */ static void -handle_dwfl_module (const char *output_file, Dwfl_Module *mod, - bool all, bool ignore) +handle_dwfl_module (const char *output_file, bool create_dirs, + Dwfl_Module *mod, bool all, bool ignore) { GElf_Addr bias; Elf *stripped = dwfl_module_getelf (mod, &bias); @@ -1547,31 +1898,11 @@ handle_dwfl_module (const char *output_file, Dwfl_Module *mod, (void) dwfl_module_info (mod, NULL, NULL, NULL, NULL, NULL, &stripped_file, &unstripped_file); - handle_explicit_files (output_file, stripped_file, unstripped_file); + handle_explicit_files (output_file, create_dirs, + stripped_file, unstripped_file); } else - handle_file (output_file, stripped, &stripped_ehdr, debug); -} - -/* Create directories containing PATH. */ -static void -make_directories (const char *path) -{ - const char *lastslash = strrchr (path, '/'); - if (lastslash == NULL) - return; - - while (lastslash > path && lastslash[-1] == '/') - --lastslash; - if (lastslash == path) - return; - - char *dir = strndupa (path, lastslash - path); - while (mkdir (dir, 0777) < 0 && errno != EEXIST) - if (errno == ENOENT) - make_directories (dir); - else - error (EXIT_FAILURE, errno, _("cannot create directory '%s'"), dir); + handle_file (output_file, create_dirs, stripped, &stripped_ehdr, debug); } /* Handle one module being written to the output directory. */ @@ -1597,8 +1928,7 @@ handle_output_dir_module (const char *output_dir, Dwfl_Module *mod, if (asprintf (&output_file, "%s/%s", output_dir, modnames ? name : file) < 0) error (EXIT_FAILURE, 0, _("memory exhausted")); - make_directories (output_file); - handle_dwfl_module (output_file, mod, all, ignore); + handle_dwfl_module (output_file, true, mod, all, ignore); } @@ -1665,7 +1995,7 @@ handle_implicit_modules (const struct arg_info *info) { if (next (offset) != 0) error (EXIT_FAILURE, 0, _("matched more than one module")); - handle_dwfl_module (info->output_file, mmi.found, + handle_dwfl_module (info->output_file, false, mmi.found, info->all, info->ignore); } else @@ -1747,12 +2077,12 @@ name of the main file complete with directory underneath OUTPUT-DIRECTORY.") char *file; if (asprintf (&file, "%s/%s", info.output_dir, info.args[0]) < 0) error (EXIT_FAILURE, 0, _("memory exhausted")); - make_directories (file); - handle_explicit_files (file, info.args[0], info.args[1]); + handle_explicit_files (file, true, info.args[0], info.args[1]); free (file); } else - handle_explicit_files (info.output_file, info.args[0], info.args[1]); + handle_explicit_files (info.output_file, false, + info.args[0], info.args[1]); } else { diff --git a/tests/ChangeLog b/tests/ChangeLog index 89fbab7cb..3424c1e2c 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,28 @@ +2007-05-18 Roland McGrath + + * run-strip-test4.sh (stripped, debugfile): Use new reference files. + * testfile37.bz2: New data file. + * testfile37.debug.bz2: New data file. + * run-unstrip-test2.sh: New file. + * Makefile.am (TESTS, EXTRA_DIST): Add them. + +2007-05-10 Roland McGrath + + * run-dwfl-bug-offline-rel.sh: New file. + * testfile36.bz2: New data file. + * testfile36.debug.bz2: New data file. + * Makefile.am (TESTS, EXTRA_DIST): Add them. + +2007-04-28 Roland McGrath + + * run-strip-test6.sh (stripped, debugfile): Use new reference files. + * testfile35.bz2: New data file. + * testfile35.debug.bz2: New data file. + * run-unstrip-test.sh: New file. + * Makefile.am (TESTS, EXTRA_DIST): Add them. + + * run-strip-test.sh: Do all elflint and cmp runs even when some fail. + 2007-04-26 Roland McGrath * run-elflint-self.sh: Run all tests even if one fails. diff --git a/tests/Makefile.am b/tests/Makefile.am index 0715fff83..f485acd11 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -71,13 +71,15 @@ TESTS = run-arextract.sh run-arsymtest.sh newfile test-nlist \ run-show-abbrev.sh run-line2addr.sh hash \ newscn run-strip-test.sh run-strip-test2.sh \ run-strip-test3.sh run-strip-test4.sh run-strip-test5.sh \ - run-strip-test6.sh run-ecp-test.sh run-ecp-test2.sh \ + run-strip-test6.sh run-unstrip-test.sh run-unstrip-test2.sh \ + run-ecp-test.sh run-ecp-test2.sh \ run-elflint-test.sh run-elflint-self.sh run-ranlib-test.sh \ run-ranlib-test2.sh run-ranlib-test3.sh run-ranlib-test4.sh \ run-addrscopes.sh run-strings-test.sh run-funcscopes.sh \ run-find-prologues.sh run-allregs.sh run-readelf-test1.sh \ run-native-test.sh run-bug1-test.sh \ - dwfl-bug-addr-overflow run-addrname-test.sh dwfl-bug-fd-leak + dwfl-bug-addr-overflow run-addrname-test.sh dwfl-bug-fd-leak \ + run-dwfl-bug-offline-rel.sh # run-show-ciefde.sh if !STANDALONE @@ -102,11 +104,12 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh \ testfile13.bz2 run-strip-test3.sh run-allfcts.sh \ run-line2addr.sh run-elflint-test.sh testfile14.bz2 \ run-strip-test4.sh run-strip-test5.sh run-strip-test6.sh \ + run-unstrip-test.sh run-unstrip-test2.sh \ run-elflint-self.sh run-ranlib-test.sh run-ranlib-test2.sh \ run-ranlib-test3.sh run-ranlib-test4.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-addrname-test.sh run-dwfl-bug-offline-rel.sh \ testfile15.bz2 testfile15.debug.bz2 \ testfile16.bz2 testfile16.debug.bz2 \ testfile17.bz2 testfile17.debug.bz2 \ @@ -119,7 +122,8 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh \ run-bug1-test.sh testfile28.bz2 testfile28.rdwr.bz2 \ testfile29.bz2 testfile29.rdwr.bz2 \ testfile30.bz2 testfile31.bz2 testfile32.bz2 testfile33.bz2 \ - testfile34.bz2 + testfile34.bz2 testfile35.bz2 testfile35.debug.bz2 + testfile36.bz2 testfile36.debug.bz2 installed_TESTS_ENVIRONMENT = libdir=$(DESTDIR)$(libdir) \ bindir=$(DESTDIR)$(bindir) \ diff --git a/tests/run-dwfl-bug-offline-rel.sh b/tests/run-dwfl-bug-offline-rel.sh new file mode 100755 index 000000000..40e90bec6 --- /dev/null +++ b/tests/run-dwfl-bug-offline-rel.sh @@ -0,0 +1,36 @@ +#! /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 +# . + +. $srcdir/test-subr.sh + +testfiles testfile36 testfile36.debug + +testrun_compare ./dwflmodtest -e testfile36 <<\EOF +module: 00000000..00002308 testfile36 (null) +module: 00000000 (nil) 0 (Callback returned failure) +module: 00000000..00002308 testfile36 testfile36.debug +EOF + +exit 0 diff --git a/tests/run-strip-test.sh b/tests/run-strip-test.sh index 9a82d53d2..480101ebd 100755 --- a/tests/run-strip-test.sh +++ b/tests/run-strip-test.sh @@ -36,16 +36,18 @@ tempfiles testfile.temp testfile.debug.temp testfile.unstrip testrun ../src/strip -o testfile.temp $debugout $original -cmp $stripped testfile.temp +status=0 + +cmp $stripped testfile.temp || status=$? # Check elflint and the expected result. -testrun ../src/elflint -q testfile.temp +testrun ../src/elflint -q testfile.temp || status=$? test -z "$debugfile" || { -cmp $debugfile testfile.debug.temp +cmp $debugfile testfile.debug.temp || status=$? # Check elflint and the expected result. -testrun ../src/elflint -q -d testfile.debug.temp +testrun ../src/elflint -q -d testfile.debug.temp || status=$? # Now test unstrip recombining those files. testrun ../src/unstrip -o testfile.unstrip testfile.temp testfile.debug.temp @@ -54,4 +56,4 @@ testrun ../src/unstrip -o testfile.unstrip testfile.temp testfile.debug.temp testrun ../src/elfcmp --hash-inexact $original testfile.unstrip } -exit 0 +exit $status diff --git a/tests/run-strip-test4.sh b/tests/run-strip-test4.sh index 8e9be228b..64924a928 100755 --- a/tests/run-strip-test4.sh +++ b/tests/run-strip-test4.sh @@ -1,5 +1,5 @@ original=testfile11 -stripped=testfile15 -debugfile=testfile15.debug +stripped=testfile37 +debugfile=testfile37.debug . $srcdir/run-strip-test.sh diff --git a/tests/run-strip-test6.sh b/tests/run-strip-test6.sh index 8ee5f02cb..c59bf5e43 100755 --- a/tests/run-strip-test6.sh +++ b/tests/run-strip-test6.sh @@ -1,5 +1,5 @@ original=testfile12 -stripped=testfile17 -debugfile=testfile17.debug +stripped=testfile35 +debugfile=testfile35.debug . $srcdir/run-strip-test.sh diff --git a/tests/run-unstrip-test.sh b/tests/run-unstrip-test.sh new file mode 100755 index 000000000..670290515 --- /dev/null +++ b/tests/run-unstrip-test.sh @@ -0,0 +1,41 @@ +#! /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 +# . + +. $srcdir/test-subr.sh + +original=${original:-testfile12} +stripped=${stripped:-testfile17} +debugfile=${debugfile:-${stripped}.debug} + +testfiles $original $stripped $debugfile + +# These are old reference output from run-test-strip6.sh, when +# strip left the .debug file with unchanged sh_size in +# stripped sections that shrank in the stripped file. strip +# no longer does that, but unstrip must still handle it. + +testrun ../src/unstrip -o testfile.unstrip $stripped $debugfile + +testrun ../src/elfcmp --hash-inexact $original testfile.unstrip diff --git a/tests/run-unstrip-test2.sh b/tests/run-unstrip-test2.sh new file mode 100755 index 000000000..44074c19a --- /dev/null +++ b/tests/run-unstrip-test2.sh @@ -0,0 +1,5 @@ +original=testfile11 +stripped=testfile15 +debugfile=testfile15.debug + +. $srcdir/run-unstrip-test.sh diff --git a/tests/testfile35.bz2 b/tests/testfile35.bz2 new file mode 100644 index 000000000..b59130157 Binary files /dev/null and b/tests/testfile35.bz2 differ diff --git a/tests/testfile35.debug.bz2 b/tests/testfile35.debug.bz2 new file mode 100644 index 000000000..f19186272 Binary files /dev/null and b/tests/testfile35.debug.bz2 differ diff --git a/tests/testfile36.bz2 b/tests/testfile36.bz2 new file mode 100644 index 000000000..e912a1979 Binary files /dev/null and b/tests/testfile36.bz2 differ diff --git a/tests/testfile36.debug.bz2 b/tests/testfile36.debug.bz2 new file mode 100644 index 000000000..76aca42e5 Binary files /dev/null and b/tests/testfile36.debug.bz2 differ diff --git a/tests/testfile37.bz2 b/tests/testfile37.bz2 new file mode 100644 index 000000000..254ce324a Binary files /dev/null and b/tests/testfile37.bz2 differ diff --git a/tests/testfile37.debug.bz2 b/tests/testfile37.debug.bz2 new file mode 100644 index 000000000..74e46a87f Binary files /dev/null and b/tests/testfile37.debug.bz2 differ