summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ChangeLog28
-rw-r--r--src/elfcmp.c2
-rw-r--r--src/nm.c129
-rw-r--r--src/unstrip.c39
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);
diff --git a/src/nm.c b/src/nm.c
index 15d9da4a..2911afa8 100644
--- a/src/nm.c
+++ b/src/nm.c
@@ -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. */