summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Wielaard <mjw@redhat.com>2015-12-30 14:39:18 +0100
committerMark Wielaard <mjw@redhat.com>2016-01-06 14:27:10 +0100
commitd22cb04967a2396514abf28cc43e70c037ee9cf2 (patch)
tree832a0e99120271742752733a7ed199b447418c18
parentc495d754f33bd2ce3eeaaed936d8f045fbf53f30 (diff)
downloadandroid_external_elfutils-d22cb04967a2396514abf28cc43e70c037ee9cf2.tar.gz
android_external_elfutils-d22cb04967a2396514abf28cc43e70c037ee9cf2.tar.bz2
android_external_elfutils-d22cb04967a2396514abf28cc43e70c037ee9cf2.zip
libdwfl: Use elf_compress[_gnu] to decompress string, symbol and reloc data.
This makes usage of the libdwfl symbol functions work out of the box even when some sections (string, symbol or xndx) are compressed. For ET_REL files this makes relocations just work by making sure the target section is decompressed first before relocations are applied. Signed-off-by: Mark Wielaard <mjw@redhat.com>
-rw-r--r--libdwfl/ChangeLog10
-rw-r--r--libdwfl/dwfl_module_getdwarf.c99
-rw-r--r--libdwfl/relocate.c116
-rw-r--r--libebl/ChangeLog4
-rw-r--r--libebl/eblopenbackend.c4
5 files changed, 201 insertions, 32 deletions
diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog
index 06b8469d..7bb9b355 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -1,3 +1,13 @@
+2015-12-18 Mark Wielaard <mjw@redhat.com>
+
+ * dwfl_module_getdwarf.c (find_symtab): Uncompress symstr, xndx, sym
+ sections and aux_str, aux_xndx and aux_sym sections if necessary.
+ * relocate.c (relocate_getsym): Uncompress symtab and symtab_shndx
+ if necessary.
+ (resolve_symbol): Uncompress strtab section if necessary.
+ (relocate_section): Uncompress the section the relocations apply to
+ if necessary.
+
2015-11-18 Chih-Hung Hsieh <chh@google.com>
* linux-proc-maps.c (proc_maps_report): Move nested function
diff --git a/libdwfl/dwfl_module_getdwarf.c b/libdwfl/dwfl_module_getdwarf.c
index e9589b3f..0e8810b1 100644
--- a/libdwfl/dwfl_module_getdwarf.c
+++ b/libdwfl/dwfl_module_getdwarf.c
@@ -1130,10 +1130,39 @@ find_symtab (Dwfl_Module *mod)
goto aux_cleanup; /* This cleans up some more and tries find_dynsym. */
}
- /* Cache the data; MOD->syments and MOD->first_global were set above. */
+ /* Cache the data; MOD->syments and MOD->first_global were set
+ above. If any of the sections is compressed, uncompress it
+ first. Only the string data setion could theoretically be
+ compressed GNU style (as .zdebug_str). Everything else only ELF
+ gabi style (SHF_COMPRESSED). */
+
+ Elf_Scn *symstrscn = elf_getscn (mod->symfile->elf, strshndx);
+ if (symstrscn == NULL)
+ goto elferr;
+
+ GElf_Shdr shdr_mem;
+ GElf_Shdr *shdr = gelf_getshdr (symstrscn, &shdr_mem);
+ if (shdr == NULL)
+ goto elferr;
+
+ size_t shstrndx;
+ if (elf_getshdrstrndx (mod->symfile->elf, &shstrndx) < 0)
+ goto elferr;
+
+ const char *sname = elf_strptr (mod->symfile->elf, shstrndx, shdr->sh_name);
+ if (sname == NULL)
+ goto elferr;
+
+ if (strncmp (sname, ".zdebug", strlen (".zdebug")) == 0)
+ /* Try to uncompress, but it might already have been, an error
+ might just indicate, already uncompressed. */
+ elf_compress_gnu (symstrscn, 0, 0);
- mod->symstrdata = elf_getdata (elf_getscn (mod->symfile->elf, strshndx),
- NULL);
+ if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
+ if (elf_compress (symstrscn, 0, 0) < 0)
+ goto elferr;
+
+ mod->symstrdata = elf_getdata (symstrscn, NULL);
if (mod->symstrdata == NULL || mod->symstrdata->d_buf == NULL)
goto elferr;
@@ -1141,17 +1170,33 @@ find_symtab (Dwfl_Module *mod)
mod->symxndxdata = NULL;
else
{
+ shdr = gelf_getshdr (xndxscn, &shdr_mem);
+ if (shdr == NULL)
+ goto elferr;
+
+ if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
+ if (elf_compress (xndxscn, 0, 0) < 0)
+ goto elferr;
+
mod->symxndxdata = elf_getdata (xndxscn, NULL);
if (mod->symxndxdata == NULL || mod->symxndxdata->d_buf == NULL)
goto elferr;
}
+ shdr = gelf_getshdr (symscn, &shdr_mem);
+ if (shdr == NULL)
+ goto elferr;
+
+ if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
+ if (elf_compress (symscn, 0, 0) < 0)
+ goto elferr;
+
mod->symdata = elf_getdata (symscn, NULL);
if (mod->symdata == NULL || mod->symdata->d_buf == NULL)
goto elferr;
// Sanity check number of symbols.
- GElf_Shdr shdr_mem, *shdr = gelf_getshdr (symscn, &shdr_mem);
+ shdr = gelf_getshdr (symscn, &shdr_mem);
if (shdr == NULL || shdr->sh_entsize == 0
|| mod->syments > mod->symdata->d_size / shdr->sh_entsize
|| (size_t) mod->first_global > mod->syments)
@@ -1174,9 +1219,33 @@ find_symtab (Dwfl_Module *mod)
return;
}
- mod->aux_symstrdata = elf_getdata (elf_getscn (mod->aux_sym.elf,
- aux_strshndx),
- NULL);
+ Elf_Scn *aux_strscn = elf_getscn (mod->aux_sym.elf, aux_strshndx);
+ if (aux_strscn == NULL)
+ goto elferr;
+
+ shdr = gelf_getshdr (aux_strscn, &shdr_mem);
+ if (shdr == NULL)
+ goto elferr;
+
+ size_t aux_shstrndx;
+ if (elf_getshdrstrndx (mod->aux_sym.elf, &aux_shstrndx) < 0)
+ goto elferr;
+
+ sname = elf_strptr (mod->aux_sym.elf, aux_shstrndx,
+ shdr->sh_name);
+ if (sname == NULL)
+ goto elferr;
+
+ if (strncmp (sname, ".zdebug", strlen (".zdebug")) == 0)
+ /* Try to uncompress, but it might already have been, an error
+ might just indicate, already uncompressed. */
+ elf_compress_gnu (aux_strscn, 0, 0);
+
+ if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
+ if (elf_compress (aux_strscn, 0, 0) < 0)
+ goto elferr;
+
+ mod->aux_symstrdata = elf_getdata (aux_strscn, NULL);
if (mod->aux_symstrdata == NULL || mod->aux_symstrdata->d_buf == NULL)
goto aux_cleanup;
@@ -1184,12 +1253,28 @@ find_symtab (Dwfl_Module *mod)
mod->aux_symxndxdata = NULL;
else
{
+ shdr = gelf_getshdr (aux_xndxscn, &shdr_mem);
+ if (shdr == NULL)
+ goto elferr;
+
+ if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
+ if (elf_compress (aux_xndxscn, 0, 0) < 0)
+ goto elferr;
+
mod->aux_symxndxdata = elf_getdata (aux_xndxscn, NULL);
if (mod->aux_symxndxdata == NULL
|| mod->aux_symxndxdata->d_buf == NULL)
goto aux_cleanup;
}
+ shdr = gelf_getshdr (aux_symscn, &shdr_mem);
+ if (shdr == NULL)
+ goto elferr;
+
+ if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
+ if (elf_compress (aux_symscn, 0, 0) < 0)
+ goto elferr;
+
mod->aux_symdata = elf_getdata (aux_symscn, NULL);
if (mod->aux_symdata == NULL || mod->aux_symdata->d_buf == NULL)
goto aux_cleanup;
diff --git a/libdwfl/relocate.c b/libdwfl/relocate.c
index 2dc67374..fc88df30 100644
--- a/libdwfl/relocate.c
+++ b/libdwfl/relocate.c
@@ -123,23 +123,32 @@ relocate_getsym (Dwfl_Module *mod,
{
GElf_Shdr shdr_mem, *shdr = gelf_getshdr (scn, &shdr_mem);
if (shdr != NULL)
- switch (shdr->sh_type)
- {
- default:
- continue;
- case SHT_SYMTAB:
- cache->symelf = relocated;
- cache->symdata = elf_getdata (scn, NULL);
- cache->strtabndx = shdr->sh_link;
- if (unlikely (cache->symdata == NULL))
- return DWFL_E_LIBELF;
- break;
- case SHT_SYMTAB_SHNDX:
- cache->symxndxdata = elf_getdata (scn, NULL);
- if (unlikely (cache->symxndxdata == NULL))
+ {
+ /* We need uncompressed data. */
+ if ((shdr->sh_type == SHT_SYMTAB
+ || shdr->sh_type == SHT_SYMTAB_SHNDX)
+ && (shdr->sh_flags & SHF_COMPRESSED) != 0)
+ if (elf_compress (scn, 0, 0) < 0)
return DWFL_E_LIBELF;
- break;
- }
+
+ switch (shdr->sh_type)
+ {
+ default:
+ continue;
+ case SHT_SYMTAB:
+ cache->symelf = relocated;
+ cache->symdata = elf_getdata (scn, NULL);
+ cache->strtabndx = shdr->sh_link;
+ if (unlikely (cache->symdata == NULL))
+ return DWFL_E_LIBELF;
+ break;
+ case SHT_SYMTAB_SHNDX:
+ cache->symxndxdata = elf_getdata (scn, NULL);
+ if (unlikely (cache->symxndxdata == NULL))
+ return DWFL_E_LIBELF;
+ break;
+ }
+ }
if (cache->symdata != NULL && cache->symxndxdata != NULL)
break;
}
@@ -203,9 +212,34 @@ resolve_symbol (Dwfl_Module *referer, struct reloc_symtab_cache *symtab,
/* Cache the strtab for this symtab. */
assert (referer->symfile == NULL
|| referer->symfile->elf != symtab->symelf);
- symtab->symstrdata = elf_getdata (elf_getscn (symtab->symelf,
- symtab->strtabndx),
- NULL);
+
+ Elf_Scn *scn = elf_getscn (symtab->symelf, symtab->strtabndx);
+ if (scn == NULL)
+ return DWFL_E_LIBELF;
+
+ GElf_Shdr shdr_mem;
+ GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
+ if (shdr == NULL)
+ return DWFL_E_LIBELF;
+
+ if (symtab->symshstrndx == SHN_UNDEF
+ && elf_getshdrstrndx (symtab->symelf, &symtab->symshstrndx) < 0)
+ return DWFL_E_LIBELF;
+
+ const char *sname = elf_strptr (symtab->symelf, symtab->symshstrndx,
+ shdr->sh_name);
+ if (sname == NULL)
+ return DWFL_E_LIBELF;
+
+ /* If the section is already decompressed, that isn't an error. */
+ if (strncmp (sname, ".zdebug", strlen (".zdebug")) == 0)
+ elf_compress_gnu (scn, 0, 0);
+
+ if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
+ if (elf_compress (scn, 0, 0) < 0)
+ return DWFL_E_LIBELF;
+
+ symtab->symstrdata = elf_getdata (scn, NULL);
if (unlikely (symtab->symstrdata == NULL
|| symtab->symstrdata->d_buf == NULL))
return DWFL_E_LIBELF;
@@ -446,22 +480,56 @@ relocate_section (Dwfl_Module *mod, Elf *relocated, const GElf_Ehdr *ehdr,
Elf_Scn *scn, GElf_Shdr *shdr,
Elf_Scn *tscn, bool debugscn, bool partial)
{
- /* First, fetch the name of the section these relocations apply to. */
+ /* First, fetch the name of the section these relocations apply to.
+ Then try to decompress both relocation and target section. */
GElf_Shdr tshdr_mem;
GElf_Shdr *tshdr = gelf_getshdr (tscn, &tshdr_mem);
+ if (tshdr == NULL)
+ return DWFL_E_LIBELF;
+
const char *tname = elf_strptr (relocated, shstrndx, tshdr->sh_name);
if (tname == NULL)
return DWFL_E_LIBELF;
- if (unlikely (tshdr->sh_type == SHT_NOBITS) || unlikely (tshdr->sh_size == 0))
- /* No contents to relocate. */
- return DWFL_E_NOERROR;
-
if (debugscn && ! ebl_debugscn_p (mod->ebl, tname))
/* This relocation section is not for a debugging section.
Nothing to do here. */
return DWFL_E_NOERROR;
+ if (strncmp (tname, ".zdebug", strlen ("zdebug")) == 0)
+ elf_compress_gnu (tscn, 0, 0);
+
+ if ((tshdr->sh_flags & SHF_COMPRESSED) != 0)
+ if (elf_compress (tscn, 0, 0) < 0)
+ return DWFL_E_LIBELF;
+
+ /* Reload Shdr in case section was just decompressed. */
+ tshdr = gelf_getshdr (tscn, &tshdr_mem);
+ if (tshdr == NULL)
+ return DWFL_E_LIBELF;
+
+ if (unlikely (tshdr->sh_type == SHT_NOBITS)
+ || unlikely (tshdr->sh_size == 0))
+ /* No contents to relocate. */
+ return DWFL_E_NOERROR;
+
+ const char *sname = elf_strptr (relocated, shstrndx, shdr->sh_name);
+ if (sname == NULL)
+ return DWFL_E_LIBELF;
+
+ if (strncmp (sname, ".zdebug", strlen ("zdebug")) == 0)
+ elf_compress_gnu (scn, 0, 0);
+
+ if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
+ if (elf_compress (scn, 0, 0) < 0)
+ return DWFL_E_LIBELF;
+
+ /* Reload Shdr in case section was just decompressed. */
+ GElf_Shdr shdr_mem;
+ shdr = gelf_getshdr (scn, &shdr_mem);
+ if (shdr == NULL)
+ return DWFL_E_LIBELF;
+
/* Fetch the section data that needs the relocations applied. */
Elf_Data *tdata = elf_rawdata (tscn, NULL);
if (tdata == NULL)
diff --git a/libebl/ChangeLog b/libebl/ChangeLog
index a1a10224..312cf90d 100644
--- a/libebl/ChangeLog
+++ b/libebl/ChangeLog
@@ -1,3 +1,7 @@
+2015-12-18 Mark Wielaard <mjw@redhat.com>
+
+ * eblopenbackend.c (default_debugscn_p): Also match .zdebug sections.
+
2015-12-08 Jose E. Marchesi <jose.marchesi@oracle.com>
* libebl.h: Prototype for ebl_ra_offset.
diff --git a/libebl/eblopenbackend.c b/libebl/eblopenbackend.c
index b3014005..372ef2a4 100644
--- a/libebl/eblopenbackend.c
+++ b/libebl/eblopenbackend.c
@@ -662,7 +662,9 @@ default_debugscn_p (const char *name)
const size_t ndwarf_scn_names = (sizeof (dwarf_scn_names)
/ sizeof (dwarf_scn_names[0]));
for (size_t cnt = 0; cnt < ndwarf_scn_names; ++cnt)
- if (strcmp (name, dwarf_scn_names[cnt]) == 0)
+ if (strcmp (name, dwarf_scn_names[cnt]) == 0
+ || (strncmp (name, ".zdebug", strlen (".zdebug")) == 0
+ && strcmp (&name[2], &dwarf_scn_names[cnt][1]) == 0))
return true;
return false;