From patchwork Thu May 5 13:01:24 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Di Chen X-Patchwork-Id: 53517 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 C3EA53851C07 for ; Thu, 5 May 2022 13:02:02 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org C3EA53851C07 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1651755722; bh=ZltBpf04r3tYuqfOERXX7HrfVU+gfNxVcXwUepX2ABE=; h=Date:Subject:To:List-Id:List-Unsubscribe:List-Archive:List-Help: List-Subscribe:From:Reply-To:From; b=QgrKhVg4WD1dy3wEN6l0bfSxl1k/LSQ5c55DQlgIzsqVMBAzoAx4Y8xOaIm8WLBFh Hxzu+FMHExWewV5KeU3Ech/2jwlkiD0rO9Jn2lLnnrQ3vRRqzJswgIIMce31tn2BFp V8TMvBKtOc0Bg/g+GkGVhEe8I1GStA2BNbPbXn34= X-Original-To: elfutils-devel@sourceware.org Delivered-To: elfutils-devel@sourceware.org Received: from us-smtp-delivery-74.mimecast.com (us-smtp-delivery-74.mimecast.com [170.10.133.74]) by sourceware.org (Postfix) with ESMTPS id 075CC3856256 for ; Thu, 5 May 2022 13:01:43 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 075CC3856256 Received: from mail-lf1-f72.google.com (mail-lf1-f72.google.com [209.85.167.72]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-154-y6ERniHFO6iJybSG6WCyXA-1; Thu, 05 May 2022 09:01:41 -0400 X-MC-Unique: y6ERniHFO6iJybSG6WCyXA-1 Received: by mail-lf1-f72.google.com with SMTP id k5-20020ac257c5000000b004723f6f25d6so1695857lfo.2 for ; Thu, 05 May 2022 06:01:39 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:mime-version:from:date:message-id:subject:to; bh=ZXEiUaFRexY2X4oai2kSp5YzuVOaqhcbPehNvVbN5qM=; b=OSjw+Zg/S/lF/mBsTmN7vv2gNRCoZEJPzlP5RiZPDImUGdEavMoPgeBtnDD01V8MUC sLDOqF2b5ddZ0mvw/wgYLAF1s1l/c9U8+o/0wEgeLE7/Um1v7PtRNo2Q3P044Fu4CKPt owRu77/X7Pbc+7st//uY3w/uBDhYJdsskf8/MB5TYlGhf19NzCKQaEaGoBft2o63PXt6 ZEuCnJ+gFsyt0UJo62eta7F8xB7fTh6alOxW4BSgGwf6JNmpltzCObXULqS/SxYOhAtc zK07s3xsulGpeDMHqhFF3QrZKBp7/kFrqpwW9aLblBV6uX1FND11qO+OP7PbfxLbTXBq fH7Q== X-Gm-Message-State: AOAM533ByF2MRRkBusQYkXcrGD0zgDZn28FPCT814Yn8q+KW3Z91eA2q VRlIjLmv10qms3+A6Q92nKo/oHVm9I0EvxOWbHJpSYSVTPMwHVuRfSAvleZSZSQBCADiROR057J rzUlcD0UVMBx8IWtLD5slNbvbie/qR4Sox6M1XeAlBQ== X-Received: by 2002:a05:6512:1189:b0:473:b9ee:30cf with SMTP id g9-20020a056512118900b00473b9ee30cfmr5981575lfr.282.1651755697604; Thu, 05 May 2022 06:01:37 -0700 (PDT) X-Google-Smtp-Source: ABdhPJygo8+f6kx1jMnoJw0wqhNu3CniJnMxqLNzvAz+TuGSrjOYQrjXU3FpCrvCFeuQuidk4uXxc2O58jwnv8qxqzY= X-Received: by 2002:a05:6512:1189:b0:473:b9ee:30cf with SMTP id g9-20020a056512118900b00473b9ee30cfmr5981431lfr.282.1651755695759; Thu, 05 May 2022 06:01:35 -0700 (PDT) MIME-Version: 1.0 Date: Thu, 5 May 2022 21:01:24 +0800 Message-ID: Subject: [PATCH] readelf: Support --dynamic with --use-dynamic To: elfutils-devel@sourceware.org X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-12.9 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, HTML_MESSAGE, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) 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 3ac23c2584d76114deab0c0af6f4af99068dc7f4 Mon Sep 17 00:00:00 2001 From: Di Chen Date: Thu, 28 Apr 2022 19:55:33 +0800 Subject: [PATCH] readelf: Support --dynamic with --use-dynamic Currently, eu-readelf is using section headers to dump the dynamic segment information (print_dynamic -> handle_dynamic). This patch adds new options to eu-readelf (-D, --use-dynamic) for (-d, --dynamic). https://sourceware.org/bugzilla/show_bug.cgi?id=28873 Signed-off-by: Di Chen --- src/readelf.c | 168 +++++++++++++++++++++++++++++++++++++--- tests/Makefile.am | 3 +- tests/run-readelf-Dd.sh | 65 ++++++++++++++++ 3 files changed, 223 insertions(+), 13 deletions(-) create mode 100755 tests/run-readelf-Dd.sh +exit 0 diff --git a/src/readelf.c b/src/readelf.c index 4b6aab2b..e578456b 100644 --- a/src/readelf.c +++ b/src/readelf.c @@ -137,6 +137,8 @@ static const struct argp_option options[] = { "string-dump", 'p', NULL, OPTION_ALIAS | OPTION_HIDDEN, NULL, 0 }, { "archive-index", 'c', NULL, 0, N_("Display the symbol index of an archive"), 0 }, + { "use-dynamic", 'D', NULL, 0, + N_("Use the dynamic section info when displaying symbols"), 0 }, { NULL, 0, NULL, 0, N_("Output control:"), 0 }, { "numeric-addresses", 'N', NULL, 0, @@ -195,6 +197,9 @@ static bool print_symbol_table; /* True if (only) the dynsym table should be printed. */ static bool print_dynsym_table; +/* True if reconstruct dynamic symbol table from the PT_DYNAMIC segment. */ +static bool use_dynamic_segment; + /* A specific section name, or NULL to print all symbol tables. */ static char *symbol_table_section; @@ -268,6 +273,19 @@ static enum section_e | section_macro | section_addr | section_types) } print_debug_sections, implicit_debug_sections; +enum dyn_idx +{ + i_strsz, + i_verneed, + i_verdef, + i_versym, + i_symtab, + i_strtab, + i_hash, + i_gnu_hash, + i_max +}; + /* Select hex dumping of sections. */ static struct section_argument *dump_data_sections; static struct section_argument **dump_data_sections_tail = &dump_data_sections; @@ -318,6 +336,11 @@ static void dump_strings (Ebl *ebl); static void print_strings (Ebl *ebl); static void dump_archive_index (Elf *, const char *); +/* Declarations of local functions for use-dynamic. */ +static Elf_Data * get_dynscn_strtab(Elf *elf, GElf_Phdr *phdr); +static void get_dynscn_addrs(Elf *elf, GElf_Phdr *phdr, GElf_Addr addrs[i_max]); +static void find_offsets(Elf *elf, GElf_Addr main_bias, size_t n, + GElf_Addr addrs[n], GElf_Off offs[n]); /* Looked up once with gettext in main. */ static char *yes_str; @@ -429,6 +452,9 @@ parse_opt (int key, char *arg, print_dynamic_table = true; any_control_option = true; break; + case 'D': + use_dynamic_segment = true; + break; case 'e': print_debug_sections |= section_exception; any_control_option = true; @@ -1791,7 +1817,7 @@ get_dyn_ents (Elf_Data * dyn_data) static void -handle_dynamic (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr) +handle_dynamic (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr, GElf_Phdr *phdr) { int class = gelf_getclass (ebl->elf); GElf_Shdr glink_mem; @@ -1802,13 +1828,20 @@ handle_dynamic (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr) size_t dyn_ents; /* Get the data of the section. */ - data = elf_getdata (scn, NULL); + if (use_dynamic_segment) + data = elf_getdata_rawchunk( + ebl->elf, phdr->p_offset, phdr->p_filesz, ELF_T_DYN); + else + data = elf_getdata (scn, NULL); + if (data == NULL) return; /* Get the dynamic section entry number */ dyn_ents = get_dyn_ents (data); + if (!use_dynamic_segment) +{ /* Get the section header string table index. */ if (unlikely (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0)) error_exit (0, _("cannot get section header string table index")); @@ -1828,8 +1861,25 @@ handle_dynamic (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr) shdr->sh_offset, (int) shdr->sh_link, elf_strptr (ebl->elf, shstrndx, glink->sh_name)); +} else { + printf (ngettext ("\ +\nDynamic segment contains %lu entry:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 "\n", + "\ +\nDynamic segment contains %lu entries:\n Addr: %#0*" PRIx64 " Offset: %#08" PRIx64 "\n", + dyn_ents), + (unsigned long int) dyn_ents, + class == ELFCLASS32 ? 10 : 18, phdr->p_paddr, + phdr->p_offset); +} + fputs_unlocked (_(" Type Value\n"), stdout); + /* if --use-dynamic option is enabled, + use the string table to get the related library info. */ + Elf_Data *strtab_data = NULL; + if (use_dynamic_segment) + strtab_data = get_dynscn_strtab(ebl->elf, phdr); + for (cnt = 0; cnt < dyn_ents; ++cnt) { GElf_Dyn dynmem; @@ -1841,6 +1891,12 @@ handle_dynamic (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr) printf (" %-17s ", ebl_dynamic_tag_name (ebl, dyn->d_tag, buf, sizeof (buf))); + char *lib_name = NULL; + if (use_dynamic_segment) + lib_name = ((char *)strtab_data->d_buf) + dyn->d_un.d_ptr; + else + lib_name = elf_strptr (ebl->elf, shdr->sh_link, dyn->d_un.d_val); + switch (dyn->d_tag) { case DT_NULL: @@ -1852,23 +1908,19 @@ handle_dynamic (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr) break; case DT_NEEDED: - printf (_("Shared library: [%s]\n"), - elf_strptr (ebl->elf, shdr->sh_link, dyn->d_un.d_val)); + printf (_("Shared library: [%s]\n"), lib_name); break; case DT_SONAME: - printf (_("Library soname: [%s]\n"), - elf_strptr (ebl->elf, shdr->sh_link, dyn->d_un.d_val)); + printf (_("Library soname: [%s]\n"),lib_name); break; case DT_RPATH: - printf (_("Library rpath: [%s]\n"), - elf_strptr (ebl->elf, shdr->sh_link, dyn->d_un.d_val)); + printf (_("Library rpath: [%s]\n"),lib_name); break; case DT_RUNPATH: - printf (_("Library runpath: [%s]\n"), - elf_strptr (ebl->elf, shdr->sh_link, dyn->d_un.d_val)); + printf (_("Library runpath: [%s]\n"), lib_name); break; case DT_PLTRELSZ: @@ -1942,8 +1994,8 @@ print_dynamic (Ebl *ebl) Elf_Scn *scn = gelf_offscn (ebl->elf, phdr->p_offset); GElf_Shdr shdr_mem; GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); - if (shdr != NULL && shdr->sh_type == SHT_DYNAMIC) - handle_dynamic (ebl, scn, shdr); + if (use_dynamic_segment || (shdr != NULL && shdr->sh_type == SHT_DYNAMIC)) + handle_dynamic (ebl, scn, shdr, phdr); break; } } @@ -4801,6 +4853,98 @@ print_ops (Dwfl_Module *dwflmod, Dwarf *dbg, int indent, int indentrest, } +static void +find_offsets(Elf *elf, GElf_Addr main_bias, size_t n, + GElf_Addr addrs[n], GElf_Off offs[n]) +{ + size_t unsolved = n; + for (size_t i = 0; i < phnum; ++i) { + GElf_Phdr phdr_mem; + GElf_Phdr *phdr = gelf_getphdr(elf, i, &phdr_mem); + 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 + main_bias && + addrs[j] - (phdr->p_vaddr + main_bias) < phdr->p_filesz) { + offs[j] = addrs[j] - (phdr->p_vaddr + main_bias) + phdr->p_offset; + if (--unsolved == 0) + break; + } + } +} + +/* The dynamic segment (type PT_DYNAMIC), contains the .dynamic section. + And .dynamic section contains an array of the dynamic structures. + We use the array to get: + DT_STRTAB: the address of the string table. + DT_SYMTAB: the address of the symbol table. + DT_STRSZ: the size, in bytes, of the string table. + , and etc. */ +static void +get_dynscn_addrs(Elf *elf, GElf_Phdr *phdr, GElf_Addr addrs[i_max]) +{ + Elf_Data *data = elf_getdata_rawchunk( + elf, phdr->p_offset, phdr->p_filesz, ELF_T_DYN); + + int dyn_idx = 0; + for (;; ++dyn_idx) { + GElf_Dyn dyn_mem; + GElf_Dyn *dyn = gelf_getdyn(data, dyn_idx, &dyn_mem); + /* DT_NULL Marks end of dynamic section. */ + if (dyn->d_tag == DT_NULL) + break; + + switch (dyn->d_tag) { + case DT_SYMTAB: + addrs[i_symtab] = dyn->d_un.d_ptr; + break; + + case DT_HASH: + addrs[i_hash] = dyn->d_un.d_ptr; + break; + + case DT_GNU_HASH: + addrs[i_gnu_hash] = dyn->d_un.d_ptr; + break; + + case DT_STRTAB: + addrs[i_strtab] = dyn->d_un.d_ptr; + break; + + case DT_VERSYM: + addrs[i_versym] = dyn->d_un.d_ptr; + break; + + case DT_VERDEF: + addrs[i_verdef] = dyn->d_un.d_ptr; + break; + + case DT_VERNEED: + addrs[i_verneed] = dyn->d_un.d_ptr; + break; + + case DT_STRSZ: + addrs[i_strsz] = dyn->d_un.d_val; + } + } + return; +} + + +/* Use dynamic segment to get data for the string table section. */ +static Elf_Data * +get_dynscn_strtab(Elf *elf, GElf_Phdr *phdr) +{ + Elf_Data *strtab_data; + GElf_Addr addrs[i_max] = {0,}; + GElf_Off offs[i_max] = {0,}; + get_dynscn_addrs(elf, phdr, addrs); + find_offsets(elf, 0, i_max, addrs, offs); + strtab_data = elf_getdata_rawchunk( + elf, offs[i_strtab], addrs[i_strsz], ELF_T_BYTE); + return strtab_data; +} + + struct listptr { Dwarf_Off offset:(64 - 3); diff --git a/tests/Makefile.am b/tests/Makefile.am index 84c3950a..b239a461 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -197,7 +197,8 @@ TESTS = run-arextract.sh run-arsymtest.sh run-ar.sh newfile test-nlist \ msg_tst system-elf-libelf-test \ $(asm_TESTS) run-disasm-bpf.sh run-low_high_pc-dw-form-indirect.sh \ run-nvidia-extended-linemap-libdw.sh run-nvidia-extended-linemap-readelf.sh \ - run-readelf-dw-form-indirect.sh run-strip-largealign.sh + run-readelf-dw-form-indirect.sh run-strip-largealign.sh \ + run-readelf-Dd.sh if !BIARCH export ELFUTILS_DISABLE_BIARCH = 1 diff --git a/tests/run-readelf-Dd.sh b/tests/run-readelf-Dd.sh new file mode 100755 index 00000000..6420a0fe --- /dev/null +++ b/tests/run-readelf-Dd.sh @@ -0,0 +1,65 @@ +#! /bin/sh +# Copyright (C) 2022 Red Hat, Inc. +# This file is part of elfutils. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# elfutils is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +. $srcdir/test-subr.sh + +# #include +# +# __thread int i; +# +# void print_i () +# { +# printf("%d\n", i); +# } +# +# gcc -fPIC -shared -o testlib_dynseg.so testlib_dynseg.c +# With ld --version +# GNU gold (GNU Binutils 2.22.52.20120402) 1.11 + +testfiles testlib_dynseg.so + +testrun_compare ${abs_top_builddir}/src/readelf -Dd testlib_dynseg.so <<\EOF + +Dynamic segment contains 23 entries: + Addr: 0x00000000000017e0 Offset: 0x0007e0 + Type Value + PLTGOT 0x00000000000019c8 + PLTRELSZ 72 (bytes) + JMPREL 0x0000000000000568 + PLTREL RELA + RELA 0x00000000000004d8 + RELASZ 144 (bytes) + RELAENT 24 (bytes) + RELACOUNT 1 + SYMTAB 0x0000000000000228 + SYMENT 24 (bytes) + STRTAB 0x0000000000000360 + STRSZ 190 (bytes) + GNU_HASH 0x0000000000000420 + NEEDED Shared library: [libc.so.6] + NEEDED Shared library: [ld-linux-x86-64.so.2] + INIT 0x00000000000005b0 + FINI 0x0000000000000748 + VERSYM 0x0000000000000460 + VERDEF 0x000000000000047c + VERDEFNUM 1 + VERNEED 0x0000000000000498 + VERNEEDNUM 2 + NULL +EOF +