summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog4
-rw-r--r--configure.ac3
-rw-r--r--libdwfl/ChangeLog20
-rw-r--r--libdwfl/linux-kernel-modules.c34
-rw-r--r--libdwfl/offline.c54
-rw-r--r--src/ChangeLog55
-rw-r--r--src/addr2line.c3
-rw-r--r--src/elflint.c4
-rw-r--r--src/strip.c51
-rw-r--r--src/unstrip.c570
-rw-r--r--tests/ChangeLog25
-rw-r--r--tests/Makefile.am12
-rwxr-xr-xtests/run-dwfl-bug-offline-rel.sh36
-rwxr-xr-xtests/run-strip-test.sh12
-rwxr-xr-xtests/run-strip-test4.sh4
-rwxr-xr-xtests/run-strip-test6.sh4
-rwxr-xr-xtests/run-unstrip-test.sh41
-rwxr-xr-xtests/run-unstrip-test2.sh5
-rw-r--r--tests/testfile35.bz2bin0 -> 1643 bytes
-rw-r--r--tests/testfile35.debug.bz2bin0 -> 9106 bytes
-rw-r--r--tests/testfile36.bz2bin0 -> 714 bytes
-rw-r--r--tests/testfile36.debug.bz2bin0 -> 24909 bytes
-rw-r--r--tests/testfile37.bz2bin0 -> 3140 bytes
-rw-r--r--tests/testfile37.debug.bz2bin0 -> 28522 bytes
24 files changed, 758 insertions, 179 deletions
diff --git a/ChangeLog b/ChangeLog
index 760c4d2d..b9f088a0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2007-05-16 Roland McGrath <[email protected]>
+
+ * configure.ac (AM_INIT_AUTOMAKE): Use -Wno-portability.
+
2006-11-02 Roland McGrath <[email protected]>
* Makefile.am (EXTRA_DIST): Add EXCEPTION file.
diff --git a/configure.ac b/configure.ac
index 596219e5..b6856ccd 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 39c7ee29..6e6407ae 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -1,3 +1,23 @@
+2007-05-17 Roland McGrath <[email protected]>
+
+ * 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 <[email protected]>
+
+ * 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 <[email protected]>
* argp-std.c (options): Fix group title string.
diff --git a/libdwfl/linux-kernel-modules.c b/libdwfl/linux-kernel-modules.c
index 2aaa25ac..98957521 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 beeb0abf..0a0645ef 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 39b64ff0..d2276951 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,58 @@
+2007-05-18 Roland McGrath <[email protected]>
+
+ * 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 <[email protected]>
+
+ * 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 <[email protected]>
+
+ * addr2line.c (options, main): Tweak argp group settings to fix
+ usage output.
+
+2007-04-28 Roland McGrath <[email protected]>
+
+ * 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 <[email protected]>
* elfcmp.c (OPT_HASH_INEXACT): New macro.
diff --git a/src/addr2line.c b/src/addr2line.c
index e133e7af..6f6de1f7 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 09c7fbd2..db3b49c1 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 95eded65..5a2da646 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 25ce1f37..98e165ce 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 (&sections[i].shdr)))
+ && !strcmp (sections[i].name, name))
+ return &sections[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 = &sections[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 = &sections[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 = &sections[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 (&sections[i].shdr)))
- && !strcmp (sections[i].name, name))
- return &sections[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 < &sections[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 < &sections[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 89fbab7c..3424c1e2 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,3 +1,28 @@
+2007-05-18 Roland McGrath <[email protected]>
+
+ * 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 <[email protected]>
+
+ * 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 <[email protected]>
+
+ * 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 <[email protected]>
* run-elflint-self.sh: Run all tests even if one fails.
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 0715fff8..f485acd1 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 00000000..40e90bec
--- /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
+# <http://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 9a82d53d..480101eb 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 8e9be228..64924a92 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 8ee5f02c..c59bf5e4 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 00000000..67029051
--- /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
+# <http://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 00000000..44074c19
--- /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 00000000..b5913015
--- /dev/null
+++ b/tests/testfile35.bz2
Binary files differ
diff --git a/tests/testfile35.debug.bz2 b/tests/testfile35.debug.bz2
new file mode 100644
index 00000000..f1918627
--- /dev/null
+++ b/tests/testfile35.debug.bz2
Binary files differ
diff --git a/tests/testfile36.bz2 b/tests/testfile36.bz2
new file mode 100644
index 00000000..e912a197
--- /dev/null
+++ b/tests/testfile36.bz2
Binary files differ
diff --git a/tests/testfile36.debug.bz2 b/tests/testfile36.debug.bz2
new file mode 100644
index 00000000..76aca42e
--- /dev/null
+++ b/tests/testfile36.debug.bz2
Binary files differ
diff --git a/tests/testfile37.bz2 b/tests/testfile37.bz2
new file mode 100644
index 00000000..254ce324
--- /dev/null
+++ b/tests/testfile37.bz2
Binary files differ
diff --git a/tests/testfile37.debug.bz2 b/tests/testfile37.debug.bz2
new file mode 100644
index 00000000..74e46a87
--- /dev/null
+++ b/tests/testfile37.debug.bz2
Binary files differ