diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/ChangeLog | 28 | ||||
-rw-r--r-- | src/elfcmp.c | 2 | ||||
-rw-r--r-- | src/nm.c | 129 | ||||
-rw-r--r-- | src/unstrip.c | 39 |
4 files changed, 183 insertions, 15 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index d6d2936e..b5b5e4a4 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,31 @@ +2015-12-02 Mark Wielaard <mjw@redhat.com> + + * nm.c (process_file): Accept fd and pass it on. + (handle_elf): Likewise. + (find_no_debuginfo): New. + (struct getdbg): Likewise. + (getdbg_dwflmod): Likewise. + (show_symbols): Take fd. If the file is ET_REL use libdwfl to get + the relocated Dwarf. + +2015-12-02 Mark Wielaard <mjw@redhat.com> + + * nm.c (get_local_names): Check for duplicates in local_root tree. + +2015-12-02 Mark Wielaard <mjw@redhat.com> + + * unstrip.c (struct data_list): New. + (new_data_list): Likewise. + (record_new_data): Likewise. + (free_new_data): Likewise. + (adjust_relocs): Call record_new_data. + (add_new_section_symbols): Likewise. + (copy_elided_sections): Call free_new_data. + +2015-12-01 Mark Wielaard <mjw@redhat.com> + + * elfcmp.c (main): Close ebl1 and ebl2 backends. + 2015-10-16 Mark Wielaard <mjw@redhat.com> * Makefile.am [BUILD_STATIC](libdw): Add -lz. diff --git a/src/elfcmp.c b/src/elfcmp.c index 0250fbe3..852b92f5 100644 --- a/src/elfcmp.c +++ b/src/elfcmp.c @@ -655,6 +655,8 @@ cannot read note section [%zu] '%s' in '%s': %s"), out: elf_end (elf1); elf_end (elf2); + ebl_closebackend (ebl1); + ebl_closebackend (ebl2); close (fd1); close (fd2); @@ -45,6 +45,7 @@ #include <system.h> #include "../libebl/libeblP.h" +#include "../libdwfl/libdwflP.h" /* Name and version of program. */ @@ -131,7 +132,7 @@ static int handle_ar (int fd, Elf *elf, const char *prefix, const char *fname, const char *suffix); /* Handle ELF file. */ -static int handle_elf (Elf *elf, const char *prefix, const char *fname, +static int handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, const char *suffix); @@ -384,7 +385,7 @@ process_file (const char *fname, bool more_than_one) { if (elf_kind (elf) == ELF_K_ELF) { - int result = handle_elf (elf, more_than_one ? "" : NULL, + int result = handle_elf (fd, elf, more_than_one ? "" : NULL, fname, NULL); if (elf_end (elf) != 0) @@ -493,7 +494,7 @@ handle_ar (int fd, Elf *elf, const char *prefix, const char *fname, && strcmp (arhdr->ar_name, "/SYM64/") != 0) { if (elf_kind (subelf) == ELF_K_ELF) - result |= handle_elf (subelf, new_prefix, arhdr->ar_name, + result |= handle_elf (fd, subelf, new_prefix, arhdr->ar_name, new_suffix); else if (elf_kind (subelf) == ELF_K_AR) result |= handle_ar (fd, subelf, new_prefix, arhdr->ar_name, @@ -708,11 +709,16 @@ get_local_names (Dwarf *dbg) newp->lowpc = lowpc; newp->highpc = highpc; - /* Since we cannot deallocate individual memory we do not test - for duplicates in the tree. This should not happen anyway. */ - if (tsearch (newp, &local_root, local_compare) == NULL) - error (EXIT_FAILURE, errno, - gettext ("cannot create search tree")); + /* Check whether a similar local_name is already in the + cache. That should not happen. But if it does, we + don't want to leak memory. */ + struct local_name **tres = tsearch (newp, &local_root, + local_compare); + if (tres == NULL) + error (EXIT_FAILURE, errno, + gettext ("cannot create search tree")); + else if (*tres != newp) + free (newp); } while (dwarf_siblingof (die, die) == 0); } @@ -1148,8 +1154,63 @@ sort_by_name (const void *p1, const void *p2) return reverse_sort ? -result : result; } +/* Stub libdwfl callback, only the ELF handle already open is ever + used. Only used for finding the alternate debug file if the Dwarf + comes from the main file. We are not interested in separate + debuginfo. */ +static int +find_no_debuginfo (Dwfl_Module *mod, + void **userdata, + const char *modname, + Dwarf_Addr base, + const char *file_name, + const char *debuglink_file, + GElf_Word debuglink_crc, + char **debuginfo_file_name) +{ + Dwarf_Addr dwbias; + dwfl_module_info (mod, NULL, NULL, NULL, &dwbias, NULL, NULL, NULL); + + /* We are only interested if the Dwarf has been setup on the main + elf file but is only missing the alternate debug link. If dwbias + hasn't even been setup, this is searching for separate debuginfo + for the main elf. We don't care in that case. */ + if (dwbias == (Dwarf_Addr) -1) + return -1; + + return dwfl_standard_find_debuginfo (mod, userdata, modname, base, + file_name, debuglink_file, + debuglink_crc, debuginfo_file_name); +} + +/* Get the Dwarf for the module/file we want. */ +struct getdbg +{ + const char *name; + Dwarf **dbg; +}; + +static int +getdbg_dwflmod (Dwfl_Module *dwflmod, + void **userdata __attribute__ ((unused)), + const char *name, + Dwarf_Addr base __attribute__ ((unused)), + void *arg) +{ + struct getdbg *get = (struct getdbg *) arg; + if (get != NULL && get->name != NULL && strcmp (get->name, name) == 0) + { + Dwarf_Addr bias; + *get->dbg = dwfl_module_getdwarf (dwflmod, &bias); + return DWARF_CB_ABORT; + } + + return DWARF_CB_OK; +} + static void -show_symbols (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, Elf_Scn *xndxscn, +show_symbols (int fd, Ebl *ebl, GElf_Ehdr *ehdr, + Elf_Scn *scn, Elf_Scn *xndxscn, GElf_Shdr *shdr, const char *prefix, const char *fname, const char *fullname) { @@ -1189,9 +1250,48 @@ show_symbols (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, Elf_Scn *xndxscn, /* Get a DWARF debugging descriptor. It's no problem if this isn't possible. We just won't print any line number information. */ Dwarf *dbg = NULL; + Dwfl *dwfl = NULL; if (format == format_sysv) { - dbg = dwarf_begin_elf (ebl->elf, DWARF_C_READ, NULL); + if (ehdr->e_type != ET_REL) + dbg = dwarf_begin_elf (ebl->elf, DWARF_C_READ, NULL); + else + { + /* Abuse libdwfl to do the relocations for us. This is just + for the ET_REL file containing Dwarf, so no need for + fancy lookups. */ + + /* Duplicate an fd for dwfl_report_offline to swallow. */ + int dwfl_fd = dup (fd); + if (likely (dwfl_fd >= 0)) + { + static const Dwfl_Callbacks callbacks = + { + .section_address = dwfl_offline_section_address, + .find_debuginfo = find_no_debuginfo + }; + dwfl = dwfl_begin (&callbacks); + if (likely (dwfl != NULL)) + { + /* Let 0 be the logical address of the file (or + first in archive). */ + dwfl->offline_next_address = 0; + if (dwfl_report_offline (dwfl, fname, fname, dwfl_fd) + == NULL) + { + /* Consumed on success, not on failure. */ + close (dwfl_fd); + } + else + { + dwfl_report_end (dwfl, NULL, NULL); + + struct getdbg get = { .name = fname, .dbg = &dbg }; + dwfl_getmodules (dwfl, &getdbg_dwflmod, &get, 0); + } + } + } + } if (dbg != NULL) { (void) dwarf_getpubnames (dbg, get_global, NULL, 0); @@ -1396,13 +1496,16 @@ show_symbols (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, Elf_Scn *xndxscn, tdestroy (local_root, free); local_root = NULL; - (void) dwarf_end (dbg); + if (dwfl == NULL) + (void) dwarf_end (dbg); } + if (dwfl != NULL) + dwfl_end (dwfl); } static int -handle_elf (Elf *elf, const char *prefix, const char *fname, +handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, const char *suffix) { size_t prefix_len = prefix == NULL ? 0 : strlen (prefix); @@ -1481,7 +1584,7 @@ handle_elf (Elf *elf, const char *prefix, const char *fname, } } - show_symbols (ebl, ehdr, scn, xndxscn, shdr, prefix, fname, + show_symbols (fd, ebl, ehdr, scn, xndxscn, shdr, prefix, fname, fullname); } } diff --git a/src/unstrip.c b/src/unstrip.c index bc8ed503..85e0a1da 100644 --- a/src/unstrip.c +++ b/src/unstrip.c @@ -311,6 +311,38 @@ make_directories (const char *path) error (EXIT_FAILURE, errno, _("cannot create directory '%s'"), dir); } +/* Keep track of new section data we are creating, so we can free it + when done. */ +struct data_list +{ + void *data; + struct data_list *next; +}; + +struct data_list *new_data_list; + +static void +record_new_data (void *data) +{ + struct data_list *next = new_data_list; + new_data_list = xmalloc (sizeof (struct data_list)); + new_data_list->data = data; + new_data_list->next = next; +} + +static void +free_new_data (void) +{ + struct data_list *list = new_data_list; + while (list != NULL) + { + struct data_list *next = list->next; + free (list->data); + free (list); + list = next; + } + new_data_list = NULL; +} /* The binutils linker leaves gratuitous section symbols in .symtab that strip has to remove. Older linkers likewise include a @@ -472,6 +504,7 @@ adjust_relocs (Elf_Scn *outscn, Elf_Scn *inscn, const GElf_Shdr *shdr, if (old_chain[i] != STN_UNDEF) \ new_chain[map[i - 1]] = map[old_chain[i] - 1]; \ \ + record_new_data (new_hash); \ data->d_buf = new_hash; \ data->d_size = nent * sizeof new_hash[0]; \ } @@ -514,6 +547,7 @@ adjust_relocs (Elf_Scn *outscn, Elf_Scn *inscn, const GElf_Shdr *shdr, ELF_CHECK (v != NULL, _("cannot get symbol version: %s")); } + record_new_data (versym); data->d_buf = versym; data->d_size = nent * shdr->sh_entsize; elf_flagdata (data, ELF_C_SET, ELF_F_DIRTY); @@ -571,6 +605,7 @@ add_new_section_symbols (Elf_Scn *old_symscn, size_t old_shnum, symdata->d_size = shdr->sh_size; symdata->d_buf = xmalloc (symdata->d_size); + record_new_data (symdata->d_buf); /* Copy the existing section symbols. */ Elf_Data *old_symdata = elf_getdata (old_symscn, NULL); @@ -1762,6 +1797,7 @@ more sections in stripped file than debug file -- arguments reversed?")); shdr->sh_size = symdata->d_size = (1 + nsym) * shdr->sh_entsize; symdata->d_buf = xmalloc (symdata->d_size); + record_new_data (symdata->d_buf); GElf_Sym sym; memset (&sym, 0, sizeof sym); @@ -1927,13 +1963,12 @@ more sections in stripped file than debug file -- arguments reversed?")); free (strtab_data->d_buf); } - if (symdata != NULL) - free (symdata->d_buf); if (symstrtab != NULL) { ebl_strtabfree (symstrtab); free (symstrdata->d_buf); } + free_new_data (); } /* Process one pair of files, already opened. */ |