From patchwork Fri Feb 10 16:17:24 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Di Chen X-Patchwork-Id: 64678 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 3702B385B519 for ; Fri, 10 Feb 2023 16:17:54 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 3702B385B519 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1676045874; bh=XRrso8b+DDiY7YMSbKFFeB/R/5LGVsplbrXGPmpZG8w=; h=Date:Subject:To:List-Id:List-Unsubscribe:List-Archive:List-Help: List-Subscribe:From:Reply-To:From; b=CkrgSZe0Tctfm5JDVNef8u4YcxMoxv1J7qoxf0JANmOfkstEvLdDjs9bkjirC00va Ys21sY45Y9SpZYTSolOC7Ud0ooL5WLg86i92/w5yQ+5wHCY/sdy75QgTbR+Xknc51/ asq2fyjh0EX0sT/BC3BfTxwg4QGTjLAvaeGE2TYo= X-Original-To: elfutils-devel@sourceware.org Delivered-To: elfutils-devel@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTPS id 2A0293858C5F for ; Fri, 10 Feb 2023 16:17:41 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 2A0293858C5F Received: from mail-lf1-f69.google.com (mail-lf1-f69.google.com [209.85.167.69]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_128_GCM_SHA256) id us-mta-267-M6k5wRhAMUG_3gFG7kEQpA-1; Fri, 10 Feb 2023 11:17:38 -0500 X-MC-Unique: M6k5wRhAMUG_3gFG7kEQpA-1 Received: by mail-lf1-f69.google.com with SMTP id l15-20020a056512110f00b004b6fe4513b7so2481864lfg.23 for ; Fri, 10 Feb 2023 08:17:38 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=to:subject:message-id:date:from:mime-version:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=2253CZZk8w0pAyMhNFvx0I3Qiu1XMd3QPmqbgLiJtKo=; b=IT8KeD+J/FMUy/Fl3JkoYqfMSoYiP53Roxbydn850t7Svf3bJAWApQGBHk2Er66PiD 069JfXFnbrdB//3tL30GNULqBZgWqMw9xZ9WgTxvsQqmQc8JKeg07Go3rnaZML8v7W4R yzJKElk+WJaTqkqAg5jZtA1xiVmuayGJUDuy1WiVKmqTNPEfL2NYtMjARoNohB/99mAc JVBxLUN2Ylti1JUu3CTu0varbHHfGmk/LQjeLHzTaBtzfNM2DvwDmm/ZxaEpC/KHG/s3 Sv76p6RWTC/hnifcyy82ClBrECGMC+RbmRLkbpVnemAcXUBl1KmHESrFUn/iI0rX4gBi 6SbA== X-Gm-Message-State: AO0yUKWZOOXdjnPt3TMTwvRK2EVWg1ZFOX9Lj6UrK/9Fv5a8cTUNO9Xh Gw4Y3mEhFmlcE2+W3YVQ9L2xkYpJJZg0IQlfJJYxp3Eht5MnklH790ycynkiV6vj4nwlI1TcGIW wblhbvm/N5Y6zLV/fbUNVUcfU4ri8uIDwOOklgPopaWPl7VNUaA+j1rs= X-Received: by 2002:a05:651c:1054:b0:293:341d:b765 with SMTP id x20-20020a05651c105400b00293341db765mr1019365ljm.90.1676045857031; Fri, 10 Feb 2023 08:17:37 -0800 (PST) X-Google-Smtp-Source: AK7set+bG8XEcgCjxTqdsKeS2O/hbFDli19vUNMtOfCgqxlD9Rv2d5dkBANuDRU+kiNbMVsKJV3ogCzBajp5GQCf1sQ= X-Received: by 2002:a05:651c:1054:b0:293:341d:b765 with SMTP id x20-20020a05651c105400b00293341db765mr1019359ljm.90.1676045856602; Fri, 10 Feb 2023 08:17:36 -0800 (PST) MIME-Version: 1.0 Date: Sat, 11 Feb 2023 00:17:24 +0800 Message-ID: Subject: [PATCH] PR28873 - Implement eu-readelf -D To: elfutils-devel@sourceware.org X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-12.6 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, HTML_MESSAGE, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-Content-Filtered-By: Mailman/MimeDel 2.1.29 X-BeenThere: elfutils-devel@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Elfutils-devel mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-Patchwork-Original-From: Di Chen via Elfutils-devel From: Di Chen Reply-To: Di Chen Errors-To: elfutils-devel-bounces+patchwork=sourceware.org@sourceware.org Sender: "Elfutils-devel" From bdc19de94bff8f8812611b9ba8c0116a650d0fb5 Mon Sep 17 00:00:00 2001 From: Di Chen Date: Fri, 13 Jan 2023 20:12:43 +0800 Subject: [PATCH] readelf: display dynamic symtab without section headers This commit adds a new option "-D/--use-dynamic" to support printing the dynamic symbol table from the PT_DYNAMIC segment. By using the PT_DYNAMIC segment, eu-readelf can go through the contents of dynamic section entries and the values of each tag. From that, we can get the address and size of the dynamic symbol table, the address of the string table, etc. By using the new option "-D/--use-dynamic", eu-readelf can list the symbols without section headers. Example: $ ./src/readelf -Ds a.out 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UNDEF 1: 0000000000000000 0 FUNC GLOBAL DEFAULT UNDEF __libc_start_main@GLIBC_2.34 (2) 2: 0000000000000000 0 NOTYPE WEAK DEFAULT UNDEF __gmon_start__ https://sourceware.org/bugzilla/show_bug.cgi?id=28873 Signed-off-by: Di Chen Signed-off-by: Di Chen --- src/readelf.c | 289 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 283 insertions(+), 6 deletions(-) static void handle_verdef (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr); @@ -327,7 +328,9 @@ enum dyn_idx { i_strsz, i_verneed, + i_verneednum, i_verdef, + i_verdefnum, i_versym, i_symtab, i_strtab, @@ -1042,7 +1045,7 @@ process_elf_file (Dwfl_Module *dwflmod, int fd) symtab_printed |= print_symtab (ebl, SHT_DYNSYM); if (print_version_info) print_verinfo (ebl); - if (print_symbol_table) + if (print_symbol_table && !use_dynamic_segment) symtab_printed |= print_symtab (ebl, SHT_SYMTAB); if ((print_symbol_table || print_dynsym_table) @@ -2442,6 +2445,12 @@ handle_relocs_rela (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr) static bool print_symtab (Ebl *ebl, int type) { + /* Use the dynamic section info to display symbol tables. */ + if (use_dynamic_segment && type == SHT_DYNSYM) + { + return handle_dynamic_symtab(ebl); + } + /* Find the symbol table(s). For this we have to search through the section table. */ Elf_Scn *scn = NULL; @@ -2480,16 +2489,275 @@ print_symtab (Ebl *ebl, int type) _("cannot get section [%zd] header: %s"), elf_ndxscn (scn), elf_errmsg (-1)); } - handle_symtab (ebl, scn, shdr); - symtab_printed = true; + symtab_printed = handle_symtab (ebl, scn, shdr); } } return symtab_printed; } +static bool +handle_dynamic_symtab (Ebl *ebl) +{ + GElf_Phdr *phdr = NULL; + /* phnum is a static variable which already fetched in function process_elf_file. */ + for (size_t i = 0; i < phnum; ++i) { + GElf_Phdr phdr_mem; + phdr = gelf_getphdr(ebl->elf, i, &phdr_mem); + if (phdr->p_type == PT_DYNAMIC) { + break; + } + } + if (phdr == NULL) + return false; -static void + GElf_Addr addrs[i_max] = {0,}; + GElf_Off offs[i_max] = {0,}; + get_dynscn_addrs(ebl->elf, phdr, addrs); + find_offsets(ebl->elf, 0, i_max, addrs, offs); + + size_t syments; + + GElf_Ehdr ehdr_mem; + GElf_Ehdr *ehdr = gelf_getehdr(ebl->elf, &ehdr_mem); + + 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(ebl->elf, offs[i_hash] + entsz, entsz, + (entsz == 4 ? ELF_T_WORD : ELF_T_XWORD)); + if (data != NULL) + syments = (entsz == 4 ? *(const GElf_Word *)data->d_buf + : *(const GElf_Xword *)data->d_buf); + } + if (offs[i_gnu_hash] != 0 && 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(ebl->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(ebl->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(ebl->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(ebl->elf, hasharr_at, + sizeof(Elf32_Word), ELF_T_WORD); + if (data != NULL && (*(const Elf32_Word *)data->d_buf & 1u)) { + syments = maxndx + 1; + break; + } + ++maxndx; + hasharr_at += sizeof(Elf32_Word); + } while (data != NULL); + } + } + } + if (offs[i_strtab] > offs[i_symtab] && syments == 0) + syments = ((offs[i_strtab] - offs[i_symtab]) / + gelf_fsize(ebl->elf, ELF_T_SYM, 1, EV_CURRENT)); + + if (syments <= 0 || offs[i_strtab] == 0 || offs[i_symtab] == 0) { + error_exit(0, _("Dynamic symbol information is not available for displaying symbols.")); + } + + /* All the data chunk initializaion. */ + Elf_Data *symdata = NULL; + Elf_Data *symstrdata = NULL; + Elf_Data *versym_data = NULL; + Elf_Data *verdef_data = NULL; + Elf_Data *verneed_data = NULL; + + symdata = elf_getdata_rawchunk( + ebl->elf, offs[i_symtab], + gelf_fsize(ebl->elf, ELF_T_SYM, syments, EV_CURRENT), ELF_T_SYM); + symstrdata = elf_getdata_rawchunk(ebl->elf, offs[i_strtab], addrs[i_strsz], + ELF_T_BYTE); + versym_data = elf_getdata_rawchunk(ebl->elf, offs[i_versym], + syments * sizeof(Elf64_Half), ELF_T_HALF); + + /* Get the verneed_data without vernaux. */ + verneed_data = elf_getdata_rawchunk( + ebl->elf, offs[i_verneed], addrs[i_verneednum] * sizeof(Elf64_Verneed), + ELF_T_VNEED); + size_t vernauxnum = 0; + size_t vn_next_offset = 0; + + for (size_t i = 0; i < addrs[i_verneednum]; i++) { + GElf_Verneed *verneed = + (GElf_Verneed *)(verneed_data->d_buf + vn_next_offset); + vernauxnum += verneed->vn_cnt; + vn_next_offset += verneed->vn_next; + } + + /* Update the verneed_data to include the vernaux. */ + verneed_data = elf_getdata_rawchunk( + ebl->elf, offs[i_verneed], + (addrs[i_verneednum] + vernauxnum) * sizeof(GElf_Verneed), ELF_T_VNEED); + + /* Get the verdef_data without verdaux. */ + verdef_data = elf_getdata_rawchunk(ebl->elf, offs[i_verdef], + addrs[i_verdefnum] * sizeof(Elf64_Verdef), + ELF_T_VDEF); + size_t verdauxnum = 0; + size_t vd_next_offset = 0; + + for (size_t i = 0; i < addrs[i_verdefnum]; i++) { + GElf_Verdef *verdef = (GElf_Verdef *)(verdef_data->d_buf + vd_next_offset); + verdauxnum += verdef->vd_cnt; + vd_next_offset += verdef->vd_next; + } + + /* Update the verdef_data to include the verdaux. */ + verdef_data = elf_getdata_rawchunk( + ebl->elf, offs[i_verdef], + (addrs[i_verdefnum] + verdauxnum) * sizeof(GElf_Verdef), ELF_T_VDEF); + + for (size_t i = 0; i < syments; i++) { + /* Get the symbol table entry. */ + GElf_Sym sym_mem; + GElf_Sym *sym; + sym = gelf_getsym(symdata, i, &sym_mem); + + char bindbuf[64]; + char typebuf[64]; + char scnbuf[64]; + int class = gelf_getclass(ebl->elf); + Elf32_Word xndx; + xndx = sym->st_shndx; + + printf(_("\ +%5ld: %0*" PRIx64 " %6" PRId64 " %-7s %-6s %-9s %6s %s"), + i, class == ELFCLASS32 ? 8 : 16, sym->st_value, sym->st_size, + ebl_symbol_type_name(ebl, GELF_ST_TYPE(sym->st_info), typebuf, + sizeof(typebuf)), + ebl_symbol_binding_name(ebl, GELF_ST_BIND(sym->st_info), bindbuf, + sizeof(bindbuf)), + get_visibility_type(GELF_ST_VISIBILITY(sym->st_other)), + ebl_section_name(ebl, sym->st_shndx, xndx, scnbuf, sizeof(scnbuf), + NULL, shnum), + ((char *)symstrdata->d_buf) + sym->st_name); + + if (versym_data != NULL) { + /* Get the version information. */ + GElf_Versym versym_mem; + GElf_Versym *versym = gelf_getversym(versym_data, i, &versym_mem); + + if (versym != NULL && ((*versym & 0x8000) != 0 || *versym > 1)) { + GElf_Vernaux vernaux_mem; + GElf_Vernaux *vernaux = NULL; + size_t vn_offset = 0; + GElf_Verneed verneed_mem; + GElf_Verneed *verneed = (GElf_Verneed *)verneed_data->d_buf; + + while (verneed != NULL) { + size_t vna_offset = vn_offset; + + vernaux = gelf_getvernaux(verneed_data, vna_offset += verneed->vn_aux, + &vernaux_mem); + while (vernaux != NULL && vernaux->vna_other != *versym && + vernaux->vna_next != 0 && + (verneed_data->d_size - vna_offset >= vernaux->vna_next)) { + /* Update the offset. */ + vna_offset += vernaux->vna_next; + + vernaux = + (vernaux->vna_next == 0 + ? NULL + : gelf_getvernaux(verneed_data, vna_offset, &vernaux_mem)); + } + + /* Check whether we found the version. */ + if (vernaux != NULL && vernaux->vna_other == *versym) + /* Found it. */ + break; + + if (verneed_data->d_size - vn_offset < verneed->vn_next) + break; + + vn_offset += verneed->vn_next; + verneed = + (verneed->vn_next == 0 + ? NULL + : gelf_getverneed(verneed_data, vn_offset, &verneed_mem)); + } + + if (vernaux != NULL && vernaux->vna_other == *versym) { + printf("@%s (%u)", (char *)symstrdata->d_buf + vernaux->vna_name, + (unsigned int)vernaux->vna_other); + } + + if (addrs[i_verdefnum] && *versym != 0x8001) { + /* We must test both. */ + size_t vd_offset = 0; + + GElf_Verdef verdef_mem; + GElf_Verdef *verdef = gelf_getverdef(verdef_data, 0, &verdef_mem); + while (verdef != NULL) { + if (verdef->vd_ndx == (*versym & 0x7fff)) + /* Found the definition. */ + break; + + if (verdef_data->d_size - vd_offset < verdef->vd_next) + break; + + vd_offset += verdef->vd_next; + verdef = + (verdef->vd_next == 0 + ? NULL + : gelf_getverdef(verdef_data, vd_offset, &verdef_mem)); + } + + if (verdef != NULL) { + GElf_Verdaux verdaux_mem; + GElf_Verdaux *verdaux = gelf_getverdaux( + verdef_data, vd_offset + verdef->vd_aux, &verdaux_mem); + + if (verdaux != NULL) + printf((*versym & 0x8000) ? "@%s" : "@@%s", + (char *)symstrdata->d_buf + verdaux->vda_name); + } + } + } + } + putchar_unlocked('\n'); + } + return true; +} + + + +static bool handle_symtab (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr) { Elf_Data *versym_data = NULL; @@ -2503,7 +2771,7 @@ handle_symtab (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr) /* Get the data of the section. */ Elf_Data *data = elf_getdata (scn, NULL); if (data == NULL) - return; + return false; /* Find out whether we have other sections we might need. */ Elf_Scn *runscn = NULL; @@ -2730,6 +2998,7 @@ handle_symtab (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr) putchar_unlocked ('\n'); } + return true; } @@ -4955,10 +5224,18 @@ get_dynscn_addrs(Elf *elf, GElf_Phdr *phdr, GElf_Addr addrs[i_max]) addrs[i_verdef] = dyn->d_un.d_ptr; break; + case DT_VERDEFNUM: + addrs[i_verdefnum] = dyn->d_un.d_val; + break; + case DT_VERNEED: addrs[i_verneed] = dyn->d_un.d_ptr; break; + case DT_VERNEEDNUM: + addrs[i_verneednum] = dyn->d_un.d_val; + break; + case DT_STRSZ: addrs[i_strsz] = dyn->d_un.d_val; break; From bdc19de94bff8f8812611b9ba8c0116a650d0fb5 Mon Sep 17 00:00:00 2001 From: Di Chen Date: Fri, 13 Jan 2023 20:12:43 +0800 Subject: [PATCH] readelf: display dynamic symtab without section headers This commit adds a new option "-D/--use-dynamic" to support printing the dynamic symbol table from the PT_DYNAMIC segment. By using the PT_DYNAMIC segment, eu-readelf can go through the contents of dynamic section entries and the values of each tag. From that, we can get the address and size of the dynamic symbol table, the address of the string table, etc. By using the new option "-D/--use-dynamic", eu-readelf can list the symbols without section headers. Example: $ ./src/readelf -Ds a.out 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UNDEF 1: 0000000000000000 0 FUNC GLOBAL DEFAULT UNDEF __libc_start_main@GLIBC_2.34 (2) 2: 0000000000000000 0 NOTYPE WEAK DEFAULT UNDEF __gmon_start__ https://sourceware.org/bugzilla/show_bug.cgi?id=28873 Signed-off-by: Di Chen --- src/readelf.c | 289 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 283 insertions(+), 6 deletions(-) diff --git a/src/readelf.c b/src/readelf.c index 451f8400..9e1e9b73 100644 --- a/src/readelf.c +++ b/src/readelf.c @@ -307,7 +307,8 @@ static void handle_relocs_rel (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, static void handle_relocs_rela (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr); static bool print_symtab (Ebl *ebl, int type); -static void handle_symtab (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr); +static bool handle_symtab (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr); +static bool handle_dynamic_symtab (Ebl *ebl); static void print_verinfo (Ebl *ebl); static void handle_verneed (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr); static void handle_verdef (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr); @@ -327,7 +328,9 @@ enum dyn_idx { i_strsz, i_verneed, + i_verneednum, i_verdef, + i_verdefnum, i_versym, i_symtab, i_strtab, @@ -1042,7 +1045,7 @@ process_elf_file (Dwfl_Module *dwflmod, int fd) symtab_printed |= print_symtab (ebl, SHT_DYNSYM); if (print_version_info) print_verinfo (ebl); - if (print_symbol_table) + if (print_symbol_table && !use_dynamic_segment) symtab_printed |= print_symtab (ebl, SHT_SYMTAB); if ((print_symbol_table || print_dynsym_table) @@ -2442,6 +2445,12 @@ handle_relocs_rela (Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr) static bool print_symtab (Ebl *ebl, int type) { + /* Use the dynamic section info to display symbol tables. */ + if (use_dynamic_segment && type == SHT_DYNSYM) + { + return handle_dynamic_symtab(ebl); + } + /* Find the symbol table(s). For this we have to search through the section table. */ Elf_Scn *scn = NULL; @@ -2480,16 +2489,275 @@ print_symtab (Ebl *ebl, int type) _("cannot get section [%zd] header: %s"), elf_ndxscn (scn), elf_errmsg (-1)); } - handle_symtab (ebl, scn, shdr); - symtab_printed = true; + symtab_printed = handle_symtab (ebl, scn, shdr); } } return symtab_printed; } +static bool +handle_dynamic_symtab (Ebl *ebl) +{ + GElf_Phdr *phdr = NULL; + /* phnum is a static variable which already fetched in function process_elf_file. */ + for (size_t i = 0; i < phnum; ++i) { + GElf_Phdr phdr_mem; + phdr = gelf_getphdr(ebl->elf, i, &phdr_mem); + if (phdr->p_type == PT_DYNAMIC) { + break; + } + } + if (phdr == NULL) + return false; -static void + GElf_Addr addrs[i_max] = {0,}; + GElf_Off offs[i_max] = {0,}; + get_dynscn_addrs(ebl->elf, phdr, addrs); + find_offsets(ebl->elf, 0, i_max, addrs, offs); + + size_t syments; + + GElf_Ehdr ehdr_mem; + GElf_Ehdr *ehdr = gelf_getehdr(ebl->elf, &ehdr_mem); + + 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(ebl->elf, offs[i_hash] + entsz, entsz, + (entsz == 4 ? ELF_T_WORD : ELF_T_XWORD)); + if (data != NULL) + syments = (entsz == 4 ? *(const GElf_Word *)data->d_buf + : *(const GElf_Xword *)data->d_buf); + } + if (offs[i_gnu_hash] != 0 && 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(ebl->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(ebl->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(ebl->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(ebl->elf, hasharr_at, + sizeof(Elf32_Word), ELF_T_WORD); + if (data != NULL && (*(const Elf32_Word *)data->d_buf & 1u)) { + syments = maxndx + 1; + break; + } + ++maxndx; + hasharr_at += sizeof(Elf32_Word); + } while (data != NULL); + } + } + } + if (offs[i_strtab] > offs[i_symtab] && syments == 0) + syments = ((offs[i_strtab] - offs[i_symtab]) / + gelf_fsize(ebl->elf, ELF_T_SYM, 1, EV_CURRENT)); + + if (syments <= 0 || offs[i_strtab] == 0 || offs[i_symtab] == 0) { + error_exit(0, _("Dynamic symbol information is not available for displaying symbols.")); + } + + /* All the data chunk initializaion. */ + Elf_Data *symdata = NULL; + Elf_Data *symstrdata = NULL; + Elf_Data *versym_data = NULL; + Elf_Data *verdef_data = NULL; + Elf_Data *verneed_data = NULL; + + symdata = elf_getdata_rawchunk( + ebl->elf, offs[i_symtab], + gelf_fsize(ebl->elf, ELF_T_SYM, syments, EV_CURRENT), ELF_T_SYM); + symstrdata = elf_getdata_rawchunk(ebl->elf, offs[i_strtab], addrs[i_strsz], + ELF_T_BYTE); + versym_data = elf_getdata_rawchunk(ebl->elf, offs[i_versym], + syments * sizeof(Elf64_Half), ELF_T_HALF); + + /* Get the verneed_data without vernaux. */ + verneed_data = elf_getdata_rawchunk( + ebl->elf, offs[i_verneed], addrs[i_verneednum] * sizeof(Elf64_Verneed), + ELF_T_VNEED); + size_t vernauxnum = 0; + size_t vn_next_offset = 0; + + for (size_t i = 0; i < addrs[i_verneednum]; i++) { + GElf_Verneed *verneed = + (GElf_Verneed *)(verneed_data->d_buf + vn_next_offset); + vernauxnum += verneed->vn_cnt; + vn_next_offset += verneed->vn_next; + } + + /* Update the verneed_data to include the vernaux. */ + verneed_data = elf_getdata_rawchunk( + ebl->elf, offs[i_verneed], + (addrs[i_verneednum] + vernauxnum) * sizeof(GElf_Verneed), ELF_T_VNEED); + + /* Get the verdef_data without verdaux. */ + verdef_data = elf_getdata_rawchunk(ebl->elf, offs[i_verdef], + addrs[i_verdefnum] * sizeof(Elf64_Verdef), + ELF_T_VDEF); + size_t verdauxnum = 0; + size_t vd_next_offset = 0; + + for (size_t i = 0; i < addrs[i_verdefnum]; i++) { + GElf_Verdef *verdef = (GElf_Verdef *)(verdef_data->d_buf + vd_next_offset); + verdauxnum += verdef->vd_cnt; + vd_next_offset += verdef->vd_next; + } + + /* Update the verdef_data to include the verdaux. */ + verdef_data = elf_getdata_rawchunk( + ebl->elf, offs[i_verdef], + (addrs[i_verdefnum] + verdauxnum) * sizeof(GElf_Verdef), ELF_T_VDEF); + + for (size_t i = 0; i < syments; i++) { + /* Get the symbol table entry. */ + GElf_Sym sym_mem; + GElf_Sym *sym; + sym = gelf_getsym(symdata, i, &sym_mem); + + char bindbuf[64]; + char typebuf[64]; + char scnbuf[64]; + int class = gelf_getclass(ebl->elf); + Elf32_Word xndx; + xndx = sym->st_shndx; + + printf(_("\ +%5ld: %0*" PRIx64 " %6" PRId64 " %-7s %-6s %-9s %6s %s"), + i, class == ELFCLASS32 ? 8 : 16, sym->st_value, sym->st_size, + ebl_symbol_type_name(ebl, GELF_ST_TYPE(sym->st_info), typebuf, + sizeof(typebuf)), + ebl_symbol_binding_name(ebl, GELF_ST_BIND(sym->st_info), bindbuf, + sizeof(bindbuf)), + get_visibility_type(GELF_ST_VISIBILITY(sym->st_other)), + ebl_section_name(ebl, sym->st_shndx, xndx, scnbuf, sizeof(scnbuf), + NULL, shnum), + ((char *)symstrdata->d_buf) + sym->st_name); + + if (versym_data != NULL) { + /* Get the version information. */ + GElf_Versym versym_mem; + GElf_Versym *versym = gelf_getversym(versym_data, i, &versym_mem); + + if (versym != NULL && ((*versym & 0x8000) != 0 || *versym > 1)) { + GElf_Vernaux vernaux_mem; + GElf_Vernaux *vernaux = NULL; + size_t vn_offset = 0; + GElf_Verneed verneed_mem; + GElf_Verneed *verneed = (GElf_Verneed *)verneed_data->d_buf; + + while (verneed != NULL) { + size_t vna_offset = vn_offset; + + vernaux = gelf_getvernaux(verneed_data, vna_offset += verneed->vn_aux, + &vernaux_mem); + while (vernaux != NULL && vernaux->vna_other != *versym && + vernaux->vna_next != 0 && + (verneed_data->d_size - vna_offset >= vernaux->vna_next)) { + /* Update the offset. */ + vna_offset += vernaux->vna_next; + + vernaux = + (vernaux->vna_next == 0 + ? NULL + : gelf_getvernaux(verneed_data, vna_offset, &vernaux_mem)); + } + + /* Check whether we found the version. */ + if (vernaux != NULL && vernaux->vna_other == *versym) + /* Found it. */ + break; + + if (verneed_data->d_size - vn_offset < verneed->vn_next) + break; + + vn_offset += verneed->vn_next; + verneed = + (verneed->vn_next == 0 + ? NULL + : gelf_getverneed(verneed_data, vn_offset, &verneed_mem)); + } + + if (vernaux != NULL && vernaux->vna_other == *versym) { + printf("@%s (%u)", (char *)symstrdata->d_buf + vernaux->vna_name, + (unsigned int)vernaux->vna_other); + } + + if (addrs[i_verdefnum] && *versym != 0x8001) { + /* We must test both. */ + size_t vd_offset = 0; + + GElf_Verdef verdef_mem; + GElf_Verdef *verdef = gelf_getverdef(verdef_data, 0, &verdef_mem); + while (verdef != NULL) { + if (verdef->vd_ndx == (*versym & 0x7fff)) + /* Found the definition. */ + break; + + if (verdef_data->d_size - vd_offset < verdef->vd_next) + break; + + vd_offset += verdef->vd_next; + verdef = + (verdef->vd_next == 0 + ? NULL + : gelf_getverdef(verdef_data, vd_offset, &verdef_mem)); + } + + if (verdef != NULL) { + GElf_Verdaux verdaux_mem; + GElf_Verdaux *verdaux = gelf_getverdaux( + verdef_data, vd_offset + verdef->vd_aux, &verdaux_mem); + + if (verdaux != NULL) + printf((*versym & 0x8000) ? "@%s" : "@@%s", + (char *)symstrdata->d_buf + verdaux->vda_name); + } + } + } + } + putchar_unlocked('\n'); + } + return true; +} + + + +static bool handle_symtab (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr) { Elf_Data *versym_data = NULL; @@ -2503,7 +2771,7 @@ handle_symtab (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr) /* Get the data of the section. */ Elf_Data *data = elf_getdata (scn, NULL); if (data == NULL) - return; + return false; /* Find out whether we have other sections we might need. */ Elf_Scn *runscn = NULL; @@ -2730,6 +2998,7 @@ handle_symtab (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr) putchar_unlocked ('\n'); } + return true; } @@ -4955,10 +5224,18 @@ get_dynscn_addrs(Elf *elf, GElf_Phdr *phdr, GElf_Addr addrs[i_max]) addrs[i_verdef] = dyn->d_un.d_ptr; break; + case DT_VERDEFNUM: + addrs[i_verdefnum] = dyn->d_un.d_val; + break; + case DT_VERNEED: addrs[i_verneed] = dyn->d_un.d_ptr; break; + case DT_VERNEEDNUM: + addrs[i_verneednum] = dyn->d_un.d_val; + break; + case DT_STRSZ: addrs[i_strsz] = dyn->d_un.d_val; break; -- 2.39.1