From: Pedro Alves Date: Thu, 26 Apr 2018 12:02:26 +0000 (+0100) Subject: Fix breakpoints in ifunc after inferior resolved it (@got.plt symbol creation) X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=02e169e2dac9b0354162eb0e7ee3fc95134b232d;p=binutils-gdb.git Fix breakpoints in ifunc after inferior resolved it (@got.plt symbol creation) 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: 2018-04-26 Pedro Alves * elfread.c (elf_rel_plt_read): Look for relocations for .got.plt too. --- diff --git a/gdb/ChangeLog b/gdb/ChangeLog index a5cb3bbd825..3266d7fc621 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,7 @@ +2018-04-26 Pedro Alves + + * elfread.c (elf_rel_plt_read): Look for relocations for .got.plt too. + 2018-04-25 Pedro Alves * infcmd.c (kill_command): Print the pid as string, not the whole diff --git a/gdb/elfread.c b/gdb/elfread.c index 260789062d0..16a692d3713 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,25 @@ 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) + { + if (this_hdr.sh_info == plt_elf_idx + || this_hdr.sh_info == got_plt_elf_idx) + break; + } + } if (relplt == NULL) return; @@ -573,6 +580,17 @@ 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; + + 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 +603,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; /* We cannot check if NAME is a reference to mst_text_gnu_ifunc as in @@ -600,8 +623,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); }