From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 74265 invoked by alias); 1 Apr 2018 03:35:55 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Received: (qmail 74232 invoked by uid 89); 1 Apr 2018 03:35:53 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-25.4 required=5.0 tests=BAYES_00,GIT_PATCH_0,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,KAM_STOCKGEN,SPF_HELO_PASS,SPF_PASS,T_RP_MATCHES_RCVD autolearn=ham version=3.3.2 spammy=older, ifunc, reside, Depending X-HELO: simark.ca Received: from simark.ca (HELO simark.ca) (158.69.221.121) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Sun, 01 Apr 2018 03:35:51 +0000 Received: from [10.0.0.11] (unknown [192.222.164.54]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by simark.ca (Postfix) with ESMTPSA id 1F1B01E030; Sat, 31 Mar 2018 23:35:49 -0400 (EDT) Subject: Re: [PATCH v2 01/15] Fix breakpoints in ifunc after inferior resolved it (@got.plt symbol creation) To: Pedro Alves , gdb-patches@sourceware.org References: <20180325191943.8246-1-palves@redhat.com> <20180325191943.8246-2-palves@redhat.com> From: Simon Marchi Message-ID: <4c13e43f-bbad-3b55-12a2-d93f90196dc4@simark.ca> Date: Sun, 01 Apr 2018 03:35:00 -0000 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.7.0 MIME-Version: 1.0 In-Reply-To: <20180325191943.8246-2-palves@redhat.com> Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 7bit X-SW-Source: 2018-04/txt/msg00007.txt.bz2 On 2018-03-25 03:19 PM, Pedro Alves wrote: > In v2: - reworked to keep supporting rel.plt sections for .plt, and > to handle jump slot offsets pointing to .plt. > > Setting a breakpoint on an ifunc symbol after the ifunc has already > been resolved by the inferior should result in creating a breakpoint > location at the ifunc target. However, that's not what happens on > current Fedora: > > (gdb) n > 53 i = gnu_ifunc (1); /* break-at-call */ > (gdb) > 54 assert (i == 2); > (gdb) b gnu_ifunc > Breakpoint 2 at gnu-indirect-function resolver at 0x7ffff7bd36ee > (gdb) info breakpoints > Num Type Disp Enb Address What > 2 STT_GNU_IFUNC resolver keep y 0x00007ffff7bd36ee > > The problem is that elf_gnu_ifunc_resolve_by_got never manages to > resolve an ifunc target. The reason is that GDB never actually > creates the internal got.plt symbols: > > (gdb) p 'gnu_ifunc@got.plt' > No symbol "gnu_ifunc@got.plt" in current context. > > and this is because GDB expects that rela.plt has relocations for > .plt, while it actually has relocations for .got.plt: > > Relocation section [10] '.rela.plt' for section [22] '.got.plt' at offset 0x570 contains 2 entries: > Offset Type Value Addend Name > 0x0000000000601018 X86_64_JUMP_SLOT 000000000000000000 +0 __assert_fail > 0x0000000000601020 X86_64_JUMP_SLOT 000000000000000000 +0 gnu_ifunc > > > Using an older system on the GCC compile farm (machine gcc15, an > x86-64 running Debian 6.0.8, with GNU ld 2.20.1), we see that it used > to be that we'd get a .rela.plt section for .plt: > > Relocation section [ 9] '.rela.plt' for section [11] '.plt' at offset 0x578 contains 3 entries: > Offset Type Value Addend Name > 0x0000000000600cc0 X86_64_JUMP_SLOT 000000000000000000 +0 __assert_fail > 0x0000000000600cc8 X86_64_JUMP_SLOT 000000000000000000 +0 __libc_start_main > 0x0000000000600cd0 X86_64_JUMP_SLOT 000000000000000000 +0 gnu_ifunc > > Those offsets did point into .got.plt, as seen with objdump -h: > > 20 .got.plt 00000030 0000000000600ca8 0000000000600ca8 00000ca8 2**3 > CONTENTS, ALLOC, LOAD, DATA > > I also tested on gcc110 on the compile farm (PPC64 running CentOS > 7.4.1708, with GNU ld 2.25.1), and there we see instead: > > Relocation section [ 9] '.rela.plt' for section [23] '.plt' at offset 0x5d0 contains 4 entries: > Offset Type Value Addend Name > 0x0000000010020148 PPC64_JMP_SLOT 000000000000000000 +0 __libc_start_main > 0x0000000010020160 PPC64_JMP_SLOT 000000000000000000 +0 __gmon_start__ > 0x0000000010020178 PPC64_JMP_SLOT 000000000000000000 +0 __assert_fail > 0x0000000010020190 PPC64_JMP_SLOT 000000000000000000 +0 gnu_ifunc > > But note that those offsets point into .plt, not .got.plt, as seen > with objdump -h: > > 22 .plt 00000078 0000000010020130 0000000010020130 00010130 2**3 > ALLOC > > This commit makes us support all the different combinations above. > > With that addressed, we now get: > > (gdb) p 'gnu_ifunc@got.plt' > $1 = () 0x400753 > > And setting a breakpoint on the ifunc finds the ifunc target: > > (gdb) b gnu_ifunc > Breakpoint 2 at 0x400753 > (gdb) info breakpoints > Num Type Disp Enb Address What > 2 breakpoint keep y 0x0000000000400753 > > gdb/ChangeLog: > yyyy-mm-dd Pedro Alves > > * elfread.c (elf_rel_plt_read): Look for relocations for .got.plt too. > not .plt. > --- > gdb/elfread.c | 64 +++++++++++++++++++++++++++++++++++++++++++---------------- > 1 file changed, 47 insertions(+), 17 deletions(-) > > diff --git a/gdb/elfread.c b/gdb/elfread.c > index 260789062d0..9ffbf99db6e 100644 > --- a/gdb/elfread.c > +++ b/gdb/elfread.c > @@ -535,8 +535,7 @@ elf_rel_plt_read (minimal_symbol_reader &reader, > { > bfd *obfd = objfile->obfd; > const struct elf_backend_data *bed = get_elf_backend_data (obfd); > - asection *plt, *relplt, *got_plt; > - int plt_elf_idx; > + asection *relplt, *got_plt; > bfd_size_type reloc_count, reloc; > struct gdbarch *gdbarch = get_objfile_arch (objfile); > struct type *ptr_type = builtin_type (gdbarch)->builtin_data_ptr; > @@ -545,11 +544,6 @@ elf_rel_plt_read (minimal_symbol_reader &reader, > if (objfile->separate_debug_objfile_backlink) > return; > > - plt = bfd_get_section_by_name (obfd, ".plt"); > - if (plt == NULL) > - return; > - plt_elf_idx = elf_section_data (plt)->this_idx; > - > got_plt = bfd_get_section_by_name (obfd, ".got.plt"); > if (got_plt == NULL) > { > @@ -559,12 +553,31 @@ elf_rel_plt_read (minimal_symbol_reader &reader, > return; > } > > + /* Depending on system, we may find jump slots in a relocation > + section for either .got.plt or .plt. */ > + asection *plt = bfd_get_section_by_name (obfd, ".plt"); > + int plt_elf_idx = (plt != NULL) ? elf_section_data (plt)->this_idx : -1; > + > + int got_plt_elf_idx = elf_section_data (got_plt)->this_idx; > + > /* This search algorithm is from _bfd_elf_canonicalize_dynamic_reloc. */ > for (relplt = obfd->sections; relplt != NULL; relplt = relplt->next) > - if (elf_section_data (relplt)->this_hdr.sh_info == plt_elf_idx > - && (elf_section_data (relplt)->this_hdr.sh_type == SHT_REL > - || elf_section_data (relplt)->this_hdr.sh_type == SHT_RELA)) > - break; > + { > + const auto &this_hdr = elf_section_data (relplt)->this_hdr; > + > + if (this_hdr.sh_type == SHT_REL || this_hdr.sh_type == SHT_RELA) > + { > + asection *target_section = NULL; > + > + if (this_hdr.sh_info == plt_elf_idx) > + target_section = plt; > + else if (this_hdr.sh_info == got_plt_elf_idx) > + target_section = got_plt; > + > + if (target_section != NULL) > + break; Is it really useful to have/set target_section? Couldn't we just break out of the loop like this? if (this_hdr.sh_info == plt_elf_idx || this_hdr.sh_info == got_plt_elf_idx) break; > + } > + } > if (relplt == NULL) > return; > > @@ -573,6 +586,18 @@ elf_rel_plt_read (minimal_symbol_reader &reader, > > std::string string_buffer; > > + /* Does ADDRESS reside in SECTION of OBFD? */ > + auto within_section = [obfd] (asection *section, CORE_ADDR address) > + { > + if (section == NULL) > + return false; > + > + /* Does the pointer reside in the .got.plt section? */ That comment should change, since it's not stricly .got.plt. > + return (bfd_get_section_vma (obfd, section) <= address > + && (address < bfd_get_section_vma (obfd, section) > + + bfd_get_section_size (section))); > + }; > + > reloc_count = relplt->size / elf_section_data (relplt)->this_hdr.sh_entsize; > for (reloc = 0; reloc < reloc_count; reloc++) > { > @@ -585,10 +610,15 @@ elf_rel_plt_read (minimal_symbol_reader &reader, > name = bfd_asymbol_name (*relplt->relocation[reloc].sym_ptr_ptr); > address = relplt->relocation[reloc].address; > > - /* Does the pointer reside in the .got.plt section? */ > - if (!(bfd_get_section_vma (obfd, got_plt) <= address > - && address < bfd_get_section_vma (obfd, got_plt) > - + bfd_get_section_size (got_plt))) > + asection *msym_section; > + > + /* Does the pointer reside in either the .got.plt or .plt > + sections? */ > + if (within_section (got_plt, address)) > + msym_section = got_plt; > + else if (within_section (plt, address)) > + msym_section = plt; > + else > continue; Or maybe you intended to use target_section here at some point? Is there a relationship between the section that matched in the for loop above and the section that will contain the address? In other words, could we save the target_section from above and do if (!within_section (target_section, address)) continue; > > /* We cannot check if NAME is a reference to mst_text_gnu_ifunc as in > @@ -600,8 +630,8 @@ elf_rel_plt_read (minimal_symbol_reader &reader, > > msym = record_minimal_symbol (reader, string_buffer.c_str (), > string_buffer.size (), > - true, address, mst_slot_got_plt, got_plt, > - objfile); > + true, address, mst_slot_got_plt, > + msym_section, objfile); > if (msym) > SET_MSYMBOL_SIZE (msym, ptr_size); > } > Simon