X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=libdwfl%2Fdwfl_module_getdwarf.c;h=0e8810b1f837acbd406a7edd88cc17cdaed0eea2;hb=82c3b58b54026d061a4d81ad95f3023d5d883ab2;hp=7259984104a0b2e28f80ac314f5c2c65084c9975;hpb=a286dd013ef8d46edf013efc0908822a59d8ac81;p=platform%2Fupstream%2Felfutils.git diff --git a/libdwfl/dwfl_module_getdwarf.c b/libdwfl/dwfl_module_getdwarf.c index 7259984..0e8810b 100644 --- a/libdwfl/dwfl_module_getdwarf.c +++ b/libdwfl/dwfl_module_getdwarf.c @@ -1,5 +1,5 @@ /* Find debugging and symbol information for a module in libdwfl. - Copyright (C) 2005-2012, 2014 Red Hat, Inc. + Copyright (C) 2005-2012, 2014, 2015 Red Hat, Inc. This file is part of elfutils. This file is free software; you can redistribute it and/or modify @@ -46,7 +46,7 @@ open_elf_file (Elf **elf, int *fd, char **name) /* If there was a pre-primed file name left that the callback left behind, try to open that file name. */ if (*fd < 0 && *name != NULL) - *fd = TEMP_FAILURE_RETRY (open64 (*name, O_RDONLY)); + *fd = TEMP_FAILURE_RETRY (open (*name, O_RDONLY)); if (*fd < 0) return CBFAIL; @@ -231,6 +231,24 @@ __libdwfl_getelf (Dwfl_Module *mod) mod->main_bias = mod->e_type == ET_REL ? 0 : mod->low_addr - mod->main.vaddr; } +static inline void +consider_shdr (GElf_Addr interp, + GElf_Word sh_type, + GElf_Xword sh_flags, + GElf_Addr sh_addr, + GElf_Xword sh_size, + GElf_Addr *phighest) +{ + if ((sh_flags & SHF_ALLOC) + && ((sh_type == SHT_PROGBITS && sh_addr != interp) + || sh_type == SHT_NOBITS)) + { + const GElf_Addr sh_end = sh_addr + sh_size; + if (sh_end > *phighest) + *phighest = sh_end; + } +} + /* If the main file might have been prelinked, then we need to discover the correct synchronization address between the main and debug files. Because of prelink's section juggling, we cannot rely @@ -367,35 +385,44 @@ find_prelink_address_sync (Dwfl_Module *mod, struct dwfl_file *file) src.d_size = phnum * phentsize; GElf_Addr undo_interp = 0; + bool class32 = ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32; { - union - { - Elf32_Phdr p32[phnum]; - Elf64_Phdr p64[phnum]; - } phdr; - dst.d_buf = &phdr; - dst.d_size = sizeof phdr; + size_t phdr_size = class32 ? sizeof (Elf32_Phdr) : sizeof (Elf64_Phdr); + if (unlikely (phnum > SIZE_MAX / phdr_size)) + return DWFL_E_NOMEM; + const size_t phdrs_bytes = phnum * phdr_size; + void *phdrs = malloc (phdrs_bytes); + if (unlikely (phdrs == NULL)) + return DWFL_E_NOMEM; + dst.d_buf = phdrs; + dst.d_size = phdrs_bytes; if (unlikely (gelf_xlatetom (mod->main.elf, &dst, &src, ehdr.e32.e_ident[EI_DATA]) == NULL)) - return DWFL_E_LIBELF; - if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32) { + free (phdrs); + return DWFL_E_LIBELF; + } + if (class32) + { + Elf32_Phdr (*p32)[phnum] = phdrs; for (uint_fast16_t i = 0; i < phnum; ++i) - if (phdr.p32[i].p_type == PT_INTERP) + if ((*p32)[i].p_type == PT_INTERP) { - undo_interp = phdr.p32[i].p_vaddr; + undo_interp = (*p32)[i].p_vaddr; break; } } else { + Elf64_Phdr (*p64)[phnum] = phdrs; for (uint_fast16_t i = 0; i < phnum; ++i) - if (phdr.p64[i].p_type == PT_INTERP) + if ((*p64)[i].p_type == PT_INTERP) { - undo_interp = phdr.p64[i].p_vaddr; + undo_interp = (*p64)[i].p_vaddr; break; } } + free (phdrs); } if (unlikely ((main_interp == 0) != (undo_interp == 0))) @@ -405,16 +432,21 @@ find_prelink_address_sync (Dwfl_Module *mod, struct dwfl_file *file) src.d_type = ELF_T_SHDR; src.d_size = gelf_fsize (mod->main.elf, ELF_T_SHDR, shnum - 1, EV_CURRENT); - union - { - Elf32_Shdr s32[shnum - 1]; - Elf64_Shdr s64[shnum - 1]; - } shdr; - dst.d_buf = &shdr; - dst.d_size = sizeof shdr; + size_t shdr_size = class32 ? sizeof (Elf32_Shdr) : sizeof (Elf64_Shdr); + if (unlikely (shnum - 1 > SIZE_MAX / shdr_size)) + return DWFL_E_NOMEM; + const size_t shdrs_bytes = (shnum - 1) * shdr_size; + void *shdrs = malloc (shdrs_bytes); + if (unlikely (shdrs == NULL)) + return DWFL_E_NOMEM; + dst.d_buf = shdrs; + dst.d_size = shdrs_bytes; if (unlikely (gelf_xlatetom (mod->main.elf, &dst, &src, ehdr.e32.e_ident[EI_DATA]) == NULL)) - return DWFL_E_LIBELF; + { + free (shdrs); + return DWFL_E_LIBELF; + } /* Now we can look at the original section headers of the main file before it was prelinked. First we'll apply our method to the main @@ -434,22 +466,6 @@ find_prelink_address_sync (Dwfl_Module *mod, struct dwfl_file *file) GElf_Addr highest; - inline void consider_shdr (GElf_Addr interp, - GElf_Word sh_type, - GElf_Xword sh_flags, - GElf_Addr sh_addr, - GElf_Xword sh_size) - { - if ((sh_flags & SHF_ALLOC) - && ((sh_type == SHT_PROGBITS && sh_addr != interp) - || sh_type == SHT_NOBITS)) - { - const GElf_Addr sh_end = sh_addr + sh_size; - if (sh_end > highest) - highest = sh_end; - } - } - highest = 0; scn = NULL; while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL) @@ -457,30 +473,46 @@ find_prelink_address_sync (Dwfl_Module *mod, struct dwfl_file *file) GElf_Shdr sh_mem; GElf_Shdr *sh = gelf_getshdr (scn, &sh_mem); if (unlikely (sh == NULL)) - return DWFL_E_LIBELF; + { + free (shdrs); + return DWFL_E_LIBELF; + } consider_shdr (main_interp, sh->sh_type, sh->sh_flags, - sh->sh_addr, sh->sh_size); + sh->sh_addr, sh->sh_size, &highest); } if (highest > mod->main.vaddr) { mod->main.address_sync = highest; highest = 0; - if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32) - for (size_t i = 0; i < shnum - 1; ++i) - consider_shdr (undo_interp, shdr.s32[i].sh_type, shdr.s32[i].sh_flags, - shdr.s32[i].sh_addr, shdr.s32[i].sh_size); + if (class32) + { + Elf32_Shdr (*s32)[shnum - 1] = shdrs; + for (size_t i = 0; i < shnum - 1; ++i) + consider_shdr (undo_interp, (*s32)[i].sh_type, + (*s32)[i].sh_flags, (*s32)[i].sh_addr, + (*s32)[i].sh_size, &highest); + } else - for (size_t i = 0; i < shnum - 1; ++i) - consider_shdr (undo_interp, shdr.s64[i].sh_type, shdr.s64[i].sh_flags, - shdr.s64[i].sh_addr, shdr.s64[i].sh_size); + { + Elf64_Shdr (*s64)[shnum - 1] = shdrs; + for (size_t i = 0; i < shnum - 1; ++i) + consider_shdr (undo_interp, (*s64)[i].sh_type, + (*s64)[i].sh_flags, (*s64)[i].sh_addr, + (*s64)[i].sh_size, &highest); + } if (highest > file->vaddr) file->address_sync = highest; else - return DWFL_E_BAD_PRELINK; + { + free (shdrs); + return DWFL_E_BAD_PRELINK; + } } + free (shdrs); + return DWFL_E_NOERROR; } @@ -575,6 +607,8 @@ load_symtab (struct dwfl_file *file, struct dwfl_file **symfile, switch (shdr->sh_type) { case SHT_SYMTAB: + if (shdr->sh_entsize == 0) + break; symtab = true; *symscn = scn; *symfile = file; @@ -589,6 +623,8 @@ load_symtab (struct dwfl_file *file, struct dwfl_file **symfile, if (symtab) break; /* Use this if need be, but keep looking for SHT_SYMTAB. */ + if (shdr->sh_entsize == 0) + break; *symscn = scn; *symfile = file; *strshndx = shdr->sh_link; @@ -621,7 +657,7 @@ load_symtab (struct dwfl_file *file, struct dwfl_file **symfile, /* Translate addresses into file offsets. OFFS[*] start out zero and remain zero if unresolved. */ static void -find_offsets (Elf *elf, size_t phnum, size_t n, +find_offsets (Elf *elf, GElf_Addr main_bias, size_t phnum, size_t n, GElf_Addr addrs[n], GElf_Off offs[n]) { size_t unsolved = n; @@ -632,16 +668,151 @@ find_offsets (Elf *elf, size_t phnum, size_t n, if (phdr != NULL && phdr->p_type == PT_LOAD && phdr->p_memsz > 0) for (size_t j = 0; j < n; ++j) if (offs[j] == 0 - && addrs[j] >= phdr->p_vaddr - && addrs[j] - phdr->p_vaddr < phdr->p_filesz) + && addrs[j] >= phdr->p_vaddr + main_bias + && addrs[j] - (phdr->p_vaddr + main_bias) < phdr->p_filesz) { - offs[j] = addrs[j] - phdr->p_vaddr + phdr->p_offset; + offs[j] = addrs[j] - (phdr->p_vaddr + main_bias) + phdr->p_offset; if (--unsolved == 0) break; } } } +/* Various addresses we might want to pull from the dynamic segment. */ +enum +{ + i_symtab, + i_strtab, + i_hash, + i_gnu_hash, + i_max +}; + +/* Translate pointers into file offsets. ADJUST is either zero + in case the dynamic segment wasn't adjusted or mod->main_bias. + Will set mod->symfile if the translated offsets can be used as + symbol table. */ +static void +translate_offs (GElf_Addr adjust, + Dwfl_Module *mod, size_t phnum, + GElf_Addr addrs[i_max], GElf_Xword strsz, + GElf_Ehdr *ehdr) +{ + GElf_Off offs[i_max] = { 0, }; + find_offsets (mod->main.elf, adjust, phnum, i_max, addrs, offs); + + /* Figure out the size of the symbol table. */ + if (offs[i_hash] != 0) + { + /* In the original format, .hash says the size of .dynsym. */ + + size_t entsz = SH_ENTSIZE_HASH (ehdr); + Elf_Data *data = elf_getdata_rawchunk (mod->main.elf, + offs[i_hash] + entsz, entsz, + (entsz == 4 + ? ELF_T_WORD : ELF_T_XWORD)); + if (data != NULL) + mod->syments = (entsz == 4 + ? *(const GElf_Word *) data->d_buf + : *(const GElf_Xword *) data->d_buf); + } + if (offs[i_gnu_hash] != 0 && mod->syments == 0) + { + /* In the new format, we can derive it with some work. */ + + const struct + { + Elf32_Word nbuckets; + Elf32_Word symndx; + Elf32_Word maskwords; + Elf32_Word shift2; + } *header; + + Elf_Data *data = elf_getdata_rawchunk (mod->main.elf, offs[i_gnu_hash], + sizeof *header, ELF_T_WORD); + if (data != NULL) + { + header = data->d_buf; + Elf32_Word nbuckets = header->nbuckets; + Elf32_Word symndx = header->symndx; + GElf_Off buckets_at = (offs[i_gnu_hash] + sizeof *header + + (gelf_getclass (mod->main.elf) + * sizeof (Elf32_Word) + * header->maskwords)); + + // elf_getdata_rawchunk takes a size_t, make sure it + // doesn't overflow. +#if SIZE_MAX <= UINT32_MAX + if (nbuckets > SIZE_MAX / sizeof (Elf32_Word)) + data = NULL; + else +#endif + data = elf_getdata_rawchunk (mod->main.elf, buckets_at, + nbuckets * sizeof (Elf32_Word), + ELF_T_WORD); + if (data != NULL && symndx < nbuckets) + { + const Elf32_Word *const buckets = data->d_buf; + Elf32_Word maxndx = symndx; + for (Elf32_Word bucket = 0; bucket < nbuckets; ++bucket) + if (buckets[bucket] > maxndx) + maxndx = buckets[bucket]; + + GElf_Off hasharr_at = (buckets_at + + nbuckets * sizeof (Elf32_Word)); + hasharr_at += (maxndx - symndx) * sizeof (Elf32_Word); + do + { + data = elf_getdata_rawchunk (mod->main.elf, + hasharr_at, + sizeof (Elf32_Word), + ELF_T_WORD); + if (data != NULL + && (*(const Elf32_Word *) data->d_buf & 1u)) + { + mod->syments = maxndx + 1; + break; + } + ++maxndx; + hasharr_at += sizeof (Elf32_Word); + } + while (data != NULL); + } + } + } + if (offs[i_strtab] > offs[i_symtab] && mod->syments == 0) + mod->syments = ((offs[i_strtab] - offs[i_symtab]) + / gelf_fsize (mod->main.elf, + ELF_T_SYM, 1, EV_CURRENT)); + + if (mod->syments > 0) + { + mod->symdata = elf_getdata_rawchunk (mod->main.elf, + offs[i_symtab], + gelf_fsize (mod->main.elf, + ELF_T_SYM, + mod->syments, + EV_CURRENT), + ELF_T_SYM); + if (mod->symdata != NULL) + { + mod->symstrdata = elf_getdata_rawchunk (mod->main.elf, + offs[i_strtab], + strsz, + ELF_T_BYTE); + if (mod->symstrdata == NULL) + mod->symdata = NULL; + } + if (mod->symdata == NULL) + mod->symerr = DWFL_E (LIBELF, elf_errno ()); + else + { + mod->symfile = &mod->main; + mod->symerr = DWFL_E_NOERROR; + } + } +} + /* Try to find a dynamic symbol table via phdrs. */ static void find_dynsym (Dwfl_Module *mod) @@ -670,14 +841,6 @@ find_dynsym (Dwfl_Module *mod) if (data == NULL) continue; - enum - { - i_symtab, - i_strtab, - i_hash, - i_gnu_hash, - i_max - }; GElf_Addr addrs[i_max] = { 0, }; GElf_Xword strsz = 0; size_t n = data->d_size / gelf_fsize (mod->main.elf, @@ -718,113 +881,14 @@ find_dynsym (Dwfl_Module *mod) break; } - /* Translate pointers into file offsets. */ - GElf_Off offs[i_max] = { 0, }; - find_offsets (mod->main.elf, phnum, i_max, addrs, offs); - - /* Figure out the size of the symbol table. */ - if (offs[i_hash] != 0) - { - /* In the original format, .hash says the size of .dynsym. */ - - size_t entsz = SH_ENTSIZE_HASH (ehdr); - data = elf_getdata_rawchunk (mod->main.elf, - offs[i_hash] + entsz, entsz, - entsz == 4 ? ELF_T_WORD - : ELF_T_XWORD); - if (data != NULL) - mod->syments = (entsz == 4 - ? *(const GElf_Word *) data->d_buf - : *(const GElf_Xword *) data->d_buf); - } - if (offs[i_gnu_hash] != 0 && mod->syments == 0) - { - /* In the new format, we can derive it with some work. */ - - const struct - { - Elf32_Word nbuckets; - Elf32_Word symndx; - Elf32_Word maskwords; - Elf32_Word shift2; - } *header; - - data = elf_getdata_rawchunk (mod->main.elf, offs[i_gnu_hash], - sizeof *header, ELF_T_WORD); - if (data != NULL) - { - header = data->d_buf; - Elf32_Word nbuckets = header->nbuckets; - Elf32_Word symndx = header->symndx; - GElf_Off buckets_at = (offs[i_gnu_hash] + sizeof *header - + (gelf_getclass (mod->main.elf) - * sizeof (Elf32_Word) - * header->maskwords)); - - data = elf_getdata_rawchunk (mod->main.elf, buckets_at, - nbuckets * sizeof (Elf32_Word), - ELF_T_WORD); - if (data != NULL && symndx < nbuckets) - { - const Elf32_Word *const buckets = data->d_buf; - Elf32_Word maxndx = symndx; - for (Elf32_Word bucket = 0; bucket < nbuckets; ++bucket) - if (buckets[bucket] > maxndx) - maxndx = buckets[bucket]; - - GElf_Off hasharr_at = (buckets_at - + nbuckets * sizeof (Elf32_Word)); - hasharr_at += (maxndx - symndx) * sizeof (Elf32_Word); - do - { - data = elf_getdata_rawchunk (mod->main.elf, - hasharr_at, - sizeof (Elf32_Word), - ELF_T_WORD); - if (data != NULL - && (*(const Elf32_Word *) data->d_buf & 1u)) - { - mod->syments = maxndx + 1; - break; - } - ++maxndx; - hasharr_at += sizeof (Elf32_Word); - } while (data != NULL); - } - } - } - if (offs[i_strtab] > offs[i_symtab] && mod->syments == 0) - mod->syments = ((offs[i_strtab] - offs[i_symtab]) - / gelf_fsize (mod->main.elf, - ELF_T_SYM, 1, EV_CURRENT)); + /* First try unadjusted, like ELF files from disk, vdso. + Then try for already adjusted dynamic section, like ELF + from remote memory. */ + translate_offs (0, mod, phnum, addrs, strsz, ehdr); + if (mod->symfile == NULL) + translate_offs (mod->main_bias, mod, phnum, addrs, strsz, ehdr); - if (mod->syments > 0) - { - mod->symdata = elf_getdata_rawchunk (mod->main.elf, - offs[i_symtab], - gelf_fsize (mod->main.elf, - ELF_T_SYM, - mod->syments, - EV_CURRENT), - ELF_T_SYM); - if (mod->symdata != NULL) - { - mod->symstrdata = elf_getdata_rawchunk (mod->main.elf, - offs[i_strtab], - strsz, - ELF_T_BYTE); - if (mod->symstrdata == NULL) - mod->symdata = NULL; - } - if (mod->symdata == NULL) - mod->symerr = DWFL_E (LIBELF, elf_errno ()); - else - { - mod->symfile = &mod->main; - mod->symerr = DWFL_E_NOERROR; - } - return; - } + return; } } } @@ -1059,28 +1123,83 @@ find_symtab (Dwfl_Module *mod) if (elf_strptr (mod->symfile->elf, strshndx, 0) == NULL) { elferr: + mod->symdata = NULL; + mod->syments = 0; + mod->first_global = 0; mod->symerr = DWFL_E (LIBELF, elf_errno ()); - goto aux_cleanup; + 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; - mod->symstrdata = elf_getdata (elf_getscn (mod->symfile->elf, strshndx), - NULL); - if (mod->symstrdata == NULL) + 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); + + 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; if (xndxscn == NULL) 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) + 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) + if (mod->symdata == NULL || mod->symdata->d_buf == NULL) + goto elferr; + + // Sanity check number of symbols. + 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) goto elferr; /* Cache any auxiliary symbol info, when it fails, just ignore aux_sym. */ @@ -1094,26 +1213,76 @@ find_symtab (Dwfl_Module *mod) mod->aux_syments = 0; elf_end (mod->aux_sym.elf); mod->aux_sym.elf = NULL; + /* We thought we had something through shdrs, but it failed... + Last ditch, look for dynamic symbols without section headers. */ + find_dynsym (mod); return; } - mod->aux_symstrdata = elf_getdata (elf_getscn (mod->aux_sym.elf, - aux_strshndx), - NULL); - if (mod->aux_symstrdata == 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; if (aux_xndxscn == NULL) 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) + 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) + if (mod->aux_symdata == NULL || mod->aux_symdata->d_buf == NULL) + goto aux_cleanup; + + // Sanity check number of aux symbols. + shdr = gelf_getshdr (aux_symscn, &shdr_mem); + if (mod->aux_syments > mod->aux_symdata->d_size / shdr->sh_entsize + || (size_t) mod->aux_first_global > mod->aux_syments) goto aux_cleanup; } }