From cc10cae34af928d41c47ed1014abafde99165c28 Mon Sep 17 00:00:00 2001 From: Alexandre Oliva Date: Tue, 28 Feb 2006 04:29:10 +0000 Subject: gdb/ChangeLog: * solib-svr4.h (struct link_map_offsets): Add l_ld_offset and l_ld_size fields. * solib-svr4.c (struct lm_info): Add l_addr field. (LM_ADDR_FROM_LINK_MAP): Renamed from LM_ADDR. (HAS_LM_DYNAMIC_FROM_LINK_MAP): New. (LM_DYNAMIC_FROM_LINK_MAP): New. (LM_ADDR_CHECK): New. Use it instead of LM_ADDR. (svr4_current_sos): Initialize l_addr. Adjust. (svr4_relocate_section_addresses): Adjust. (svr4_ilp32_fetch_link_map_offsets): Define new members. (svr4_lp64_fetch_link_map_offsets): Likewise. * solib-legacy.c (legacy_svr4_fetch_link_map_offsets): Likewise. * mipsnbsd-tdep.c (mipsnbsd_ilp32_fetch_link_map_offsets): Likewise. (mipsnbsd_lp64_fetch_link_map_offsets): Likewise. * Makefile.in (solib-svr4.o): Depend on $(elf_bfd_h). gdb/testsuite/ChangeLog: * gdb.base/prelink.exp: New test. * gdb.base/prelink.c, gdb.base/prelink-lib.c: New sources. --- gdb/ChangeLog | 18 +++++ gdb/Makefile.in | 3 +- gdb/mipsnbsd-tdep.c | 4 ++ gdb/solib-legacy.c | 11 +++ gdb/solib-svr4.c | 113 +++++++++++++++++++++++++++++-- gdb/solib-svr4.h | 6 ++ gdb/testsuite/ChangeLog | 5 ++ gdb/testsuite/gdb.base/prelink-lib.c | 34 ++++++++++ gdb/testsuite/gdb.base/prelink.c | 30 ++++++++ gdb/testsuite/gdb.base/prelink.exp | 128 +++++++++++++++++++++++++++++++++++ 10 files changed, 346 insertions(+), 6 deletions(-) create mode 100644 gdb/testsuite/gdb.base/prelink-lib.c create mode 100644 gdb/testsuite/gdb.base/prelink.c create mode 100644 gdb/testsuite/gdb.base/prelink.exp (limited to 'gdb') diff --git a/gdb/ChangeLog b/gdb/ChangeLog index da2748a..dfe5cba 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,21 @@ +2006-02-28 Alexandre Oliva + + * solib-svr4.h (struct link_map_offsets): Add l_ld_offset and + l_ld_size fields. + * solib-svr4.c (struct lm_info): Add l_addr field. + (LM_ADDR_FROM_LINK_MAP): Renamed from LM_ADDR. + (HAS_LM_DYNAMIC_FROM_LINK_MAP): New. + (LM_DYNAMIC_FROM_LINK_MAP): New. + (LM_ADDR_CHECK): New. Use it instead of LM_ADDR. + (svr4_current_sos): Initialize l_addr. Adjust. + (svr4_relocate_section_addresses): Adjust. + (svr4_ilp32_fetch_link_map_offsets): Define new members. + (svr4_lp64_fetch_link_map_offsets): Likewise. + * solib-legacy.c (legacy_svr4_fetch_link_map_offsets): Likewise. + * mipsnbsd-tdep.c (mipsnbsd_ilp32_fetch_link_map_offsets): Likewise. + (mipsnbsd_lp64_fetch_link_map_offsets): Likewise. + * Makefile.in (solib-svr4.o): Depend on $(elf_bfd_h). + 2006-02-26 David S. Miller * config/sparc/linux.mt (TDEPFILES): Add sol2-tdep.o. diff --git a/gdb/Makefile.in b/gdb/Makefile.in index acba593..92bc0c4 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -2582,7 +2582,8 @@ solib-sunos.o: solib-sunos.c $(defs_h) $(gdb_string_h) $(symtab_h) $(bfd_h) \ solib-svr4.o: solib-svr4.c $(defs_h) $(elf_external_h) $(elf_common_h) \ $(elf_mips_h) $(symtab_h) $(bfd_h) $(symfile_h) $(objfiles_h) \ $(gdbcore_h) $(target_h) $(inferior_h) $(gdb_assert_h) \ - $(solist_h) $(solib_h) $(solib_svr4_h) $(bfd_target_h) $(exec_h) + $(solist_h) $(solib_h) $(solib_svr4_h) $(bfd_target_h) $(elf_bfd_h) \ + $(exec_h) sol-thread.o: sol-thread.c $(defs_h) $(gdbthread_h) $(target_h) \ $(inferior_h) $(gdb_stat_h) $(gdbcmd_h) $(gdbcore_h) $(regcache_h) \ $(solib_h) $(symfile_h) $(gdb_string_h) $(gregset_h) diff --git a/gdb/mipsnbsd-tdep.c b/gdb/mipsnbsd-tdep.c index dfdc01d..f9a8b73 100644 --- a/gdb/mipsnbsd-tdep.c +++ b/gdb/mipsnbsd-tdep.c @@ -339,6 +339,8 @@ mipsnbsd_ilp32_fetch_link_map_offsets (void) lmo.l_addr_size = 4; lmo.l_name_offset = 8; lmo.l_name_size = 4; + lmo.l_ld_offset = 12; + lmo.l_ld_size = 4; lmo.l_next_offset = 16; lmo.l_next_size = 4; lmo.l_prev_offset = 20; @@ -369,6 +371,8 @@ mipsnbsd_lp64_fetch_link_map_offsets (void) lmo.l_addr_size = 8; lmo.l_name_offset = 16; lmo.l_name_size = 8; + lmo.l_ld_offset = 24; + lmo.l_ld_size = 8; lmo.l_next_offset = 32; lmo.l_next_size = 8; lmo.l_prev_offset = 40; diff --git a/gdb/solib-legacy.c b/gdb/solib-legacy.c index 6789993..eba92d0 100644 --- a/gdb/solib-legacy.c +++ b/gdb/solib-legacy.c @@ -69,6 +69,9 @@ legacy_svr4_fetch_link_map_offsets (void) lmo.l_next_offset = offsetof (struct link_map, l_next); lmo.l_next_size = fieldsize (struct link_map, l_next); + lmo.l_ld_offset = offsetof (struct link_map, l_ld); + lmo.l_ld_size = fieldsize (struct link_map, l_ld); + lmo.l_prev_offset = offsetof (struct link_map, l_prev); lmo.l_prev_size = fieldsize (struct link_map, l_prev); @@ -84,6 +87,10 @@ legacy_svr4_fetch_link_map_offsets (void) lmo.l_next_offset = offsetof (struct link_map, lm_next); lmo.l_next_size = fieldsize (struct link_map, lm_next); + /* FIXME: Is this the right field name, or is it available at all? */ + lmo.l_ld_offset = offsetof (struct link_map, lm_ld); + lmo.l_ld_size = fieldsize (struct link_map, lm_ld); + lmo.l_name_offset = offsetof (struct link_map, lm_name); lmo.l_name_size = fieldsize (struct link_map, lm_name); #else /* !defined(HAVE_STRUCT_LINK_MAP_WITH_LM_MEMBERS) */ @@ -98,6 +105,10 @@ legacy_svr4_fetch_link_map_offsets (void) lmo.l_name_offset = offsetof (struct so_map, som_path); lmo.l_name_size = fieldsize (struct so_map, som_path); + + /* FIXME: Is the address of the dynamic table available? */ + lmo.l_ld_offset = 0; + lmo.l_ld_size = 0; #endif /* HAVE_STRUCT_SO_MAP_WITH_SOM_MEMBERS */ #endif /* HAVE_STRUCT_LINK_MAP_WITH_LM_MEMBERS */ #endif /* HAVE_STRUCT_LINK_MAP_WITH_L_MEMBERS */ diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c index caadb4a..7d740a3 100644 --- a/gdb/solib-svr4.c +++ b/gdb/solib-svr4.c @@ -42,6 +42,7 @@ #include "solib-svr4.h" #include "bfd-target.h" +#include "elf-bfd.h" #include "exec.h" static struct link_map_offsets *svr4_fetch_link_map_offsets (void); @@ -59,6 +60,13 @@ struct lm_info rather than void *, so that we may use byte offsets to find the various fields without the need for a cast. */ gdb_byte *lm; + + /* Amount by which addresses in the binary should be relocated to + match the inferior. This could most often be taken directly + from lm, but when prelinking is involved and the prelink base + address changes, we may need a different offset, we want to + warn about the difference and compute it only once. */ + CORE_ADDR l_addr; }; /* On SVR4 systems, a list of symbols in the dynamic linker where @@ -127,14 +135,101 @@ static char *main_name_list[] = /* link map access functions */ static CORE_ADDR -LM_ADDR (struct so_list *so) +LM_ADDR_FROM_LINK_MAP (struct so_list *so) { struct link_map_offsets *lmo = svr4_fetch_link_map_offsets (); - return (CORE_ADDR) extract_signed_integer (so->lm_info->lm + lmo->l_addr_offset, + return (CORE_ADDR) extract_signed_integer (so->lm_info->lm + + lmo->l_addr_offset, lmo->l_addr_size); } +static int +HAS_LM_DYNAMIC_FROM_LINK_MAP () +{ + struct link_map_offsets *lmo = svr4_fetch_link_map_offsets (); + + return (lmo->l_ld_size != 0); +} + +static CORE_ADDR +LM_DYNAMIC_FROM_LINK_MAP (struct so_list *so) +{ + struct link_map_offsets *lmo = svr4_fetch_link_map_offsets (); + + gdb_assert (lmo->l_ld_size != 0); + + return (CORE_ADDR) extract_signed_integer (so->lm_info->lm + + lmo->l_ld_offset, + lmo->l_ld_size); +} + +static CORE_ADDR +LM_ADDR_CHECK (struct so_list *so, bfd *abfd) +{ + if (so->lm_info->l_addr == (CORE_ADDR)-1) + { + struct bfd_section *dyninfo_sect; + CORE_ADDR l_addr, l_dynaddr, dynaddr, align = 0x1000; + + l_addr = LM_ADDR_FROM_LINK_MAP (so); + + if (! abfd || ! HAS_LM_DYNAMIC_FROM_LINK_MAP ()) + goto set_addr; + + l_dynaddr = LM_DYNAMIC_FROM_LINK_MAP (so); + + dyninfo_sect = bfd_get_section_by_name (abfd, ".dynamic"); + if (dyninfo_sect == NULL) + goto set_addr; + + dynaddr = bfd_section_vma (abfd, dyninfo_sect); + + if (dynaddr + l_addr != l_dynaddr) + { + warning (_(".dynamic section for \"%s\" " + "is not at the expected address"), so->so_name); + + if (bfd_get_flavour (abfd) == bfd_target_elf_flavour) + { + Elf_Internal_Ehdr *ehdr = elf_tdata (abfd)->elf_header; + Elf_Internal_Phdr *phdr = elf_tdata (abfd)->phdr; + int i; + + align = 1; + + for (i = 0; i < ehdr->e_phnum; i++) + if (phdr[i].p_type == PT_LOAD && phdr[i].p_align > align) + align = phdr[i].p_align; + } + + /* Turn it into a mask. */ + align--; + + /* If the changes match the alignment requirements, we + assume we're using a core file that was generated by the + same binary, just prelinked with a different base offset. + If it doesn't match, we may have a different binary, the + same binary with the dynamic table loaded at an unrelated + location, or anything, really. To avoid regressions, + don't adjust the base offset in the latter case, although + odds are that, if things really changed, debugging won't + quite work. */ + if ((l_addr & align) == 0 && ((dynaddr - l_dynaddr) & align) == 0) + { + l_addr = l_dynaddr - dynaddr; + warning (_("difference appears to be caused by prelink, " + "adjusting expectations")); + } + } + + set_addr: + so->lm_info->l_addr = l_addr; + } + + return so->lm_info->l_addr; +} + static CORE_ADDR LM_NEXT (struct so_list *so) { @@ -649,6 +744,8 @@ svr4_current_sos (void) free_so (new); else { + new->lm_info->l_addr = (CORE_ADDR)-1; + new->next = 0; *link_ptr = new; link_ptr = &new->next; @@ -912,7 +1009,7 @@ enable_break (void) if (strcmp (buf, so->so_original_name) == 0) { load_addr_found = 1; - load_addr = LM_ADDR (so); + load_addr = LM_ADDR_CHECK (so, tmp_bfd); break; } so = so->next; @@ -1272,8 +1369,10 @@ static void svr4_relocate_section_addresses (struct so_list *so, struct section_table *sec) { - sec->addr = svr4_truncate_ptr (sec->addr + LM_ADDR (so)); - sec->endaddr = svr4_truncate_ptr (sec->endaddr + LM_ADDR (so)); + sec->addr = svr4_truncate_ptr (sec->addr + LM_ADDR_CHECK (so, + sec->bfd)); + sec->endaddr = svr4_truncate_ptr (sec->endaddr + LM_ADDR_CHECK (so, + sec->bfd)); } @@ -1362,6 +1461,8 @@ svr4_ilp32_fetch_link_map_offsets (void) lmo.l_addr_size = 4; lmo.l_name_offset = 4; lmo.l_name_size = 4; + lmo.l_ld_offset = 8; + lmo.l_ld_size = 4; lmo.l_next_offset = 12; lmo.l_next_size = 4; lmo.l_prev_offset = 16; @@ -1395,6 +1496,8 @@ svr4_lp64_fetch_link_map_offsets (void) lmo.l_addr_size = 8; lmo.l_name_offset = 8; lmo.l_name_size = 8; + lmo.l_ld_offset = 16; + lmo.l_ld_size = 8; lmo.l_next_offset = 24; lmo.l_next_size = 8; lmo.l_prev_offset = 32; diff --git a/gdb/solib-svr4.h b/gdb/solib-svr4.h index ae2740e..58b41e0 100644 --- a/gdb/solib-svr4.h +++ b/gdb/solib-svr4.h @@ -50,6 +50,12 @@ struct link_map_offsets /* Size of l_addr field in struct link_map. */ int l_addr_size; + /* Offset to l_ld field in struct link_map. */ + int l_ld_offset; + + /* Size of l_ld field in struct link_map. */ + int l_ld_size; + /* Offset to l_next field in struct link_map. */ int l_next_offset; diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index d271dd5..45f0711 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2006-02-28 Alexandre Oliva + + * gdb.base/prelink.exp: New test. + * gdb.base/prelink.c, gdb.base/prelink-lib.c: New sources. + 2006-02-24 Wu Zhou * gdb.fortran/derived-type.f90: New file. diff --git a/gdb/testsuite/gdb.base/prelink-lib.c b/gdb/testsuite/gdb.base/prelink-lib.c new file mode 100644 index 0000000..2a712ba --- /dev/null +++ b/gdb/testsuite/gdb.base/prelink-lib.c @@ -0,0 +1,34 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2006 Free Software Foundation, Inc. + + This program 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 2 of the License, or + (at your option) any later version. + + This program 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, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +int +g (void (*p)(void)) +{ + p (); +} + +void +f(void (*p)(void)) { + g (p); +} + +void (*h (void)) (void (*p)(void)) +{ + return f; +} diff --git a/gdb/testsuite/gdb.base/prelink.c b/gdb/testsuite/gdb.base/prelink.c new file mode 100644 index 0000000..c63d35b --- /dev/null +++ b/gdb/testsuite/gdb.base/prelink.c @@ -0,0 +1,30 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2006 Free Software Foundation, Inc. + + This program 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 2 of the License, or + (at your option) any later version. + + This program 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, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include + +extern void (*h (void)) (void (*)(void)); + +int +main (void) +{ + void (*f) (void (*)(void)) = h (); + printf ("%p\n", f); + f (0); +} diff --git a/gdb/testsuite/gdb.base/prelink.exp b/gdb/testsuite/gdb.base/prelink.exp new file mode 100644 index 0000000..c26d20e --- /dev/null +++ b/gdb/testsuite/gdb.base/prelink.exp @@ -0,0 +1,128 @@ +# Copyright 2006 Free Software Foundation, Inc. + +# This program 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 2 of the License, or +# (at your option) any later version. +# +# This program 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, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +# Please email any bugs, comments, and/or additions to this file to: +# bug-gdb@prep.ai.mit.edu + +# This file was written by Alexandre Oliva + +if $tracelevel then { + strace $tracelevel + } + +set prms_id 0 +set bug_id 0 + +# are we on a target board +if ![isnative] then { + return +} + +if [get_compiler_info "ignored"] { + return -1 +} + +if {$gcc_compiled == 0} { + return -1 +} + +set testfile "prelink" +set srcfile ${testfile}.c +set binfile ${objdir}/${subdir}/${testfile} + +set libsrcfile ${testfile}-lib.c +set libfile ${objdir}/${subdir}/${testfile}.so +if { [gdb_compile "${srcdir}/${subdir}/${libsrcfile}" "${libfile}" executable [list debug "additional_flags=-fpic -shared -nodefaultlibs"]] != ""} { + # If creating the shared library fails, maybe we don't have the right tools + return -1 +} + +if {[catch "system \"prelink -NR ${libfile}\""] != 0} { + # Maybe we don't have prelink. + return -1 +} + +set srcfile ${testfile}.c +set binfile ${objdir}/${subdir}/${testfile} +if { [gdb_compile "${srcdir}/${subdir}/${srcfile} ${libfile}" "${binfile}" executable [list debug "additional_flags=-Wl,-rpath,${objdir}/${subdir}"]] != ""} { + return -1; +} + +set found 0 +set coredir "${objdir}/${subdir}/coredir.[getpid]" +file mkdir $coredir +catch "system \"(cd ${coredir}; ulimit -c unlimited; ${binfile}; true) >/dev/null 2>&1\"" + +foreach i "${coredir}/core ${coredir}/core.coremaker.c ${binfile}.core" { + if [remote_file build exists $i] { + remote_exec build "mv $i ${objdir}/${subdir}/prelink.core" + set found 1 + } +} +# Check for "core.PID". +if { $found == 0 } { + set names [glob -nocomplain -directory $coredir core.*] + if {[llength $names] == 1} { + set corefile [file join $coredir [lindex $names 0]] + remote_exec build "mv $corefile ${objdir}/${subdir}/prelink.core" + set found 1 + } +} + +catch "system \"prelink -u ${libfile}\"" +catch "system \"prelink -NR ${libfile}\"" + +# Try to clean up after ourselves. +remote_file build delete [file join $coredir coremmap.data] +remote_exec build "rmdir $coredir" + +if { $found == 0 } { + warning "can't generate a core file - prelink tests suppressed - check ulimit -c" + return 0 +} + +# Start with a fresh gdb + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +set oldtimeout $timeout +set timeout [expr "$timeout + 60"] +verbose "Timeout is now $timeout seconds" 2 +send_gdb "core-file $objdir/$subdir/prelink.core\n" +gdb_expect { + -re "warning: \.dynamic section.*not at the expected address" { + pass "changed base address" + } + -re ".*$gdb_prompt $" { fail "changed base address" } + timeout { fail "(timeout) changed base address" } +} +gdb_expect { + -re "warning: difference.*caused by prelink, adjusting" { + pass "prelink adjustment" + } + -re ".*$gdb_prompt $" { fail "prelink adjustment" } + timeout { fail "(timeout) prelink adjustment" } +} +set timeout $oldtimeout +verbose "Timeout is now $timeout seconds" 2 + +gdb_exit + +return 0 + -- cgit v1.1