gdb/ChangeLog:
authorAlexandre Oliva <aoliva@redhat.com>
Tue, 28 Feb 2006 04:29:10 +0000 (04:29 +0000)
committerAlexandre Oliva <aoliva@redhat.com>
Tue, 28 Feb 2006 04:29:10 +0000 (04:29 +0000)
* 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
gdb/Makefile.in
gdb/mipsnbsd-tdep.c
gdb/solib-legacy.c
gdb/solib-svr4.c
gdb/solib-svr4.h
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.base/prelink-lib.c [new file with mode: 0644]
gdb/testsuite/gdb.base/prelink.c [new file with mode: 0644]
gdb/testsuite/gdb.base/prelink.exp [new file with mode: 0644]

index da2748ad010504992c17c3f79dd6c61aed1f1825..dfe5cba082fd569c986e626be3bed6004ced526d 100644 (file)
@@ -1,3 +1,21 @@
+2006-02-28  Alexandre Oliva  <aoliva@redhat.com>
+
+       * 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  <davem@sunset.davemloft.net>
 
        * config/sparc/linux.mt (TDEPFILES): Add sol2-tdep.o.
index acba593b0ebc92c0e14e57778fae41855d6eef6c..92bc0c403a9664d917ee0366707a10aec61af5d1 100644 (file)
@@ -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)
index dfdc01d8b9833ee6b67a12fb0f1f9d0a49354320..f9a8b733333d509d5b65139b8bbca9480fa75ca0 100644 (file)
@@ -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;
index 678999332686334104dc6b5c70ddfd61df73b499..eba92d0e4364e85ea46425cbab52c2998005fc4b 100644 (file)
@@ -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 */
index caadb4a26d616aaee3f29eed0a0f4662bd32d11d..7d740a33b404b8b0aa5b12a99fee3fc66a740470 100644 (file)
@@ -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));
 }
 \f
 
@@ -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;
index ae2740e0de7b7cf1ac26fbc80d50146c0f8a6f3b..58b41e03585938642b19286df03ea88cfb6c138c 100644 (file)
@@ -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;
 
index d271dd5ff38d2e1ca9d35253b4acbeaa7905a769..45f07116f39b17229497c5a418b5019deb55887c 100644 (file)
@@ -1,3 +1,8 @@
+2006-02-28  Alexandre Oliva  <aoliva@redhat.com>
+
+       * gdb.base/prelink.exp: New test.
+       * gdb.base/prelink.c, gdb.base/prelink-lib.c: New sources.
+
 2006-02-24  Wu Zhou  <woodzltc@cn.ibm.com>
 
        * 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 (file)
index 0000000..2a712ba
--- /dev/null
@@ -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 (file)
index 0000000..c63d35b
--- /dev/null
@@ -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 <stdio.h>
+
+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 (file)
index 0000000..c26d20e
--- /dev/null
@@ -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 <aoliva@redhat.com>
+
+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
+