Patchwork [02/11] Fix breakpoints in ifunc after inferior resolved it (@got.plt symbol creation)

login
register
mail settings
Submitter Pedro Alves
Date March 9, 2018, 9:16 p.m.
Message ID <20180309211612.12941-3-palves@redhat.com>
Download mbox | patch
Permalink /patch/26260/
State New
Headers show

Comments

Pedro Alves - March 9, 2018, 9:16 p.m.
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 today:

  (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 <gnu_ifunc+4>

The problem is that elf_gnu_ifunc_resolve_by_got never manages to
revolve 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

With that addressed, we now get:

 (gdb) p 'gnu_ifunc@got.plt'
 $1 = (<text from jump slot in .got.plt, no debug info>) 0x400753 <final>

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 <final>

gdb/ChangeLog:
yyyy-mm-dd  Pedro Alves  <palves@redhat.com>

	* elfread.c (elf_rel_plt_read): Look for relocation for .got.plt,
	not .plt.
---
 gdb/elfread.c | 12 ++++--------
 1 file changed, 4 insertions(+), 8 deletions(-)
Simon Marchi - March 11, 2018, 7:59 p.m.
On 2018-03-09 04:16 PM, Pedro Alves wrote:
> 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 today:
> 
>   (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 <gnu_ifunc+4>
> 
> The problem is that elf_gnu_ifunc_resolve_by_got never manages to
> revolve an ifunc target.  The reason is that GDB never actually

revolve -> resolve

> 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:

Was it ever the case that rela.plt contained relocations for .plt, or
has it always been a mistake?

Simon

Patch

diff --git a/gdb/elfread.c b/gdb/elfread.c
index 103b2144c3a..454b77e9bdc 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,9 +553,11 @@  elf_rel_plt_read (minimal_symbol_reader &reader,
 	return;
     }
 
+  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
+    if (elf_section_data (relplt)->this_hdr.sh_info == got_plt_elf_idx
 	&& (elf_section_data (relplt)->this_hdr.sh_type == SHT_REL
 	    || elf_section_data (relplt)->this_hdr.sh_type == SHT_RELA))
       break;