* cope with varying prelink base addresses
@ 2006-02-08 5:35 Alexandre Oliva
2006-02-08 6:25 ` Eli Zaretskii
` (2 more replies)
0 siblings, 3 replies; 19+ messages in thread
From: Alexandre Oliva @ 2006-02-08 5:35 UTC (permalink / raw)
To: gdb-patches, cagney
[-- Attachment #1: Type: text/plain, Size: 2280 bytes --]
If you take a core file created on a box whose libraries have been
prelinked with random base addresses and try to use it for debugging
on another box that has the very same binaries, but prelinked with a
different base address, gdb will get all confused.
That's because the load_addr of the prelinked binaries will be
whatever difference there was between the base address selected by
prelink and the base address used at run time by the dynamic loader.
If everything is prelinked successfully, the load addresses will all
be zero.
So when gdb reads the binary prelinked with a different base address,
and applies to it the load address read from the core file, it won't
get the correct address if the prelinked binary on the debugging host
got a different address.
This is arguably a change in the binary, so debugging is not expected
to work anyway, but it definitely is surprising, especially when
prelink is enabled by default. This would render core files useless
across different hosts.
This patch gets gdb to try to recognize the situation in which a
binary got prelinked but is otherwise unchanged, and figure out the
difference between the base addresses at core-generating host and at
the debugging host.
The only piece of information available for this that I could find was
the address of the dynamic table in the dynamic loader data
structures. The heuristics I used was to check whether the dynamic
table address changed but remained at the same position within a
page. If so, I assume the difference is caused by prelinking, and
then I adjust the load_addr that gdb is going to use for that binary.
Otherwise, it will face the same problems you're expected to face when
debugging a core file using a different binary.
I'd appreciate if whoever reviews this would pay particular attention
to the gdb testcase; it's the first time I write one, and I could use
some guidance to make sure I'm not making undeserved assumptions.
It's bad enough that I have to use compile- and run-time flags that
will likely only work with GCC and GNU ld, and that the test requires
the prelink program to be in the PATH; I hope I'm coping well with
cases in which the flags are not accepted or prelink is not in place.
Comments? Ok to install? Tested on amd64-linux-gnu.
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: gdb-prelink-core-2.patch --]
[-- Type: text/x-patch, Size: 15222 bytes --]
for gdb/ChangeLog
from 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.
for gdb/testsuite/ChangeLog
from Alexandre Oliva <aoliva@redhat.com>
* gdb.base/prelink.exp: New test.
* gdb.base/prelink.c, gdb.base/prelink-lib.c: New sources.
Index: gdb/mipsnbsd-tdep.c
===================================================================
--- gdb/mipsnbsd-tdep.c.orig 2006-02-08 00:09:27.000000000 -0200
+++ gdb/mipsnbsd-tdep.c 2006-02-08 00:38:54.000000000 -0200
@@ -339,6 +339,8 @@ mipsnbsd_ilp32_fetch_link_map_offsets (v
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 (vo
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: gdb/solib-legacy.c
===================================================================
--- gdb/solib-legacy.c.orig 2006-02-08 00:09:27.000000000 -0200
+++ gdb/solib-legacy.c 2006-02-08 00:38:54.000000000 -0200
@@ -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: gdb/solib-svr4.c
===================================================================
--- gdb/solib-svr4.c.orig 2006-02-08 00:09:27.000000000 -0200
+++ gdb/solib-svr4.c 2006-02-08 02:58:15.000000000 -0200
@@ -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: gdb/solib-svr4.h
===================================================================
--- gdb/solib-svr4.h.orig 2006-02-08 00:09:27.000000000 -0200
+++ gdb/solib-svr4.h 2006-02-08 00:38:54.000000000 -0200
@@ -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: gdb/Makefile.in
===================================================================
--- gdb/Makefile.in.orig 2006-02-06 03:44:14.000000000 -0200
+++ gdb/Makefile.in 2006-02-08 01:19:32.000000000 -0200
@@ -2570,7 +2570,8 @@ solib-sunos.o: solib-sunos.c $(defs_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: gdb/testsuite/gdb.base/prelink-lib.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ gdb/testsuite/gdb.base/prelink-lib.c 2006-02-08 02:42:10.000000000 -0200
@@ -0,0 +1,15 @@
+int
+g (void (*p)(void))
+{
+ p ();
+}
+
+void
+f(void (*p)(void)) {
+ g (p);
+}
+
+void (*h (void)) (void (*p)(void))
+{
+ return f;
+}
Index: gdb/testsuite/gdb.base/prelink.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ gdb/testsuite/gdb.base/prelink.c 2006-02-08 02:42:13.000000000 -0200
@@ -0,0 +1,11 @@
+#include <stdio.h>
+
+extern void (*h (void)) (void (*)(void));
+
+int
+main (void)
+{
+ void (*f) (void (*)(void)) = h ();
+ printf ("%p\n", f);
+ f (0);
+}
Index: gdb/testsuite/gdb.base/prelink.exp
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ gdb/testsuite/gdb.base/prelink.exp 2006-02-08 03:00:21.000000000 -0200
@@ -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
+}
+
+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;
+}
+
+if [get_compiler_info ${binfile}] {
+ return -1
+}
+
+if {$gcc_compiled == 0} {
+ 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
+
[-- Attachment #3: Type: text/plain, Size: 249 bytes --]
--
Alexandre Oliva http://www.lsd.ic.unicamp.br/~oliva/
Secretary for FSF Latin America http://www.fsfla.org/
Red Hat Compiler Engineer aoliva@{redhat.com, gcc.gnu.org}
Free Software Evangelist oliva@{lsd.ic.unicamp.br, gnu.org}
^ permalink raw reply [flat|nested] 19+ messages in thread* Re: cope with varying prelink base addresses 2006-02-08 5:35 cope with varying prelink base addresses Alexandre Oliva @ 2006-02-08 6:25 ` Eli Zaretskii 2006-02-10 0:15 ` Alexandre Oliva 2006-02-08 21:40 ` Mark Kettenis 2006-02-20 17:43 ` Daniel Jacobowitz 2 siblings, 1 reply; 19+ messages in thread From: Eli Zaretskii @ 2006-02-08 6:25 UTC (permalink / raw) To: Alexandre Oliva; +Cc: gdb-patches, cagney > From: Alexandre Oliva <aoliva@redhat.com> > Date: Wed, 08 Feb 2006 03:18:01 -0200 > > The only piece of information available for this that I could find was > the address of the dynamic table in the dynamic loader data > structures. The heuristics I used was to check whether the dynamic > table address changed but remained at the same position within a > page. If so, I assume the difference is caused by prelinking, and > then I adjust the load_addr that gdb is going to use for that binary. > Otherwise, it will face the same problems you're expected to face when > debugging a core file using a different binary. Would it make sense to add a user command/variable that will tell GDB the difference between the two base addresses? I guess it would be a good idea if the user has a way of finding out this number by some means that are unavailable to GDB (e.g., by gaining access to the other machine or talking to someone sitting in front of it). WDYT? ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: cope with varying prelink base addresses 2006-02-08 6:25 ` Eli Zaretskii @ 2006-02-10 0:15 ` Alexandre Oliva 0 siblings, 0 replies; 19+ messages in thread From: Alexandre Oliva @ 2006-02-10 0:15 UTC (permalink / raw) To: Eli Zaretskii; +Cc: gdb-patches, cagney On Feb 8, 2006, Eli Zaretskii <eliz@gnu.org> wrote: > Would it make sense to add a user command/variable that will tell GDB > the difference between the two base addresses? Err... Not really. Unless you mean some per-dynamic-object setting. And I really think it's overkill. Perhaps it migth make sense to ask the user what to do whenever we detect an inconsistency between the expected address of l_ld and the address it is on, offering a reasonable default, but even that is probably overkill, and it might change the behavior if l_ld doesn't mean what we think it does. Besides, we already sort-of have the means to do it. GDB has commands to set the addresses of individual sections. It would be a pain, but it can be done. -- Alexandre Oliva http://www.lsd.ic.unicamp.br/~oliva/ Secretary for FSF Latin America http://www.fsfla.org/ Red Hat Compiler Engineer aoliva@{redhat.com, gcc.gnu.org} Free Software Evangelist oliva@{lsd.ic.unicamp.br, gnu.org} ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: cope with varying prelink base addresses 2006-02-08 5:35 cope with varying prelink base addresses Alexandre Oliva 2006-02-08 6:25 ` Eli Zaretskii @ 2006-02-08 21:40 ` Mark Kettenis 2006-02-10 0:09 ` Alexandre Oliva 2006-02-20 17:43 ` Daniel Jacobowitz 2 siblings, 1 reply; 19+ messages in thread From: Mark Kettenis @ 2006-02-08 21:40 UTC (permalink / raw) To: aoliva; +Cc: gdb-patches, cagney > From: Alexandre Oliva <aoliva@redhat.com> > Date: Wed, 08 Feb 2006 03:18:01 -0200 > > --=-=-= > > If you take a core file created on a box whose libraries have been > prelinked with random base addresses and try to use it for debugging > on another box that has the very same binaries, but prelinked with a > different base address, gdb will get all confused. > > That's because the load_addr of the prelinked binaries will be > whatever difference there was between the base address selected by > prelink and the base address used at run time by the dynamic loader. > If everything is prelinked successfully, the load addresses will all > be zero. > > So when gdb reads the binary prelinked with a different base address, > and applies to it the load address read from the core file, it won't > get the correct address if the prelinked binary on the debugging host > got a different address. > > This is arguably a change in the binary, so debugging is not expected > to work anyway, but it definitely is surprising, especially when > prelink is enabled by default. This would render core files useless > across different hosts. > > This patch gets gdb to try to recognize the situation in which a > binary got prelinked but is otherwise unchanged, and figure out the > difference between the base addresses at core-generating host and at > the debugging host. > > The only piece of information available for this that I could find was > the address of the dynamic table in the dynamic loader data > structures. The heuristics I used was to check whether the dynamic > table address changed but remained at the same position within a > page. If so, I assume the difference is caused by prelinking, and > then I adjust the load_addr that gdb is going to use for that binary. > Otherwise, it will face the same problems you're expected to face when > debugging a core file using a different binary. > > I'd appreciate if whoever reviews this would pay particular attention > to the gdb testcase; it's the first time I write one, and I could use > some guidance to make sure I'm not making undeserved assumptions. > It's bad enough that I have to use compile- and run-time flags that > will likely only work with GCC and GNU ld, and that the test requires > the prelink program to be in the PATH; I hope I'm coping well with > cases in which the flags are not accepted or prelink is not in place. > > Comments? Ok to install? Tested on amd64-linux-gnu. This code is very fragile, and defenitely should be tested on more than a single platform. In the past, we've seen that not every OS interprets the l_addr field of `struct link_map'. And MIPS targets have a history of doing things differently even for the same OS. Basically the two interpretations are: a. l_addr is the absolute address at which the shared object is loaded. b. l_addr is the relative address used to relocate the shared object. The confusion arises because many platforms traditionally "pre-link" at address 0, and then the difference doesn't matter. I'm afraid my knowledge of pre-linking isn't detailed enough to check whether this has any impact on the pre-linking problem. The word "heuristic" makes me a bit nervous. It seems to me that the dynamic linker should be able to provide the necessary information. Perhaps you should raise the issue with the glibc developers, to see what they can do? Mark ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: cope with varying prelink base addresses 2006-02-08 21:40 ` Mark Kettenis @ 2006-02-10 0:09 ` Alexandre Oliva 2006-02-10 1:42 ` Daniel Jacobowitz 0 siblings, 1 reply; 19+ messages in thread From: Alexandre Oliva @ 2006-02-10 0:09 UTC (permalink / raw) To: Mark Kettenis; +Cc: gdb-patches, cagney On Feb 8, 2006, Mark Kettenis <mark.kettenis@xs4all.nl> wrote: > This code is very fragile, and defenitely should be tested on more > than a single platform. Seriously, what's fragile about it? Only if we meet a certain set of conditions that are only likely to hold in the case of prelinking are we going to get any change in behavior, and I don't see anything fragile about the set of conditions. Sure enough it might not work on all OSs, but where it does not, it won't make any difference whatsoever. > In the past, we've seen that not every OS > interprets the l_addr field of `struct link_map'. I don't change in any way the way l_addr is handled. What I do is apply an offset atop of l_addr if the conditions are met, where the conditions are designed to ensure that, if you are to apply it, you'll be bringing in a definite improvement, rather than perhaps making things worse. > And MIPS targets > have a history of doing things differently even for the same OS. > Basically the two interpretations are: > a. l_addr is the absolute address at which the shared object is loaded. > b. l_addr is the relative address used to relocate the shared object. Actually, both interpretations are the same. It looks one or the other because of the base addresses that appear in the program headers. In general, dynamic libraries start at address zero, but when they're prelinked, they don't, and then l_addr may remain as zero to reflect that no additional offset was applied. > The word "heuristic" makes me a bit nervous. It seems to me that the > dynamic linker should be able to provide the necessary information. I don't see how, without duplicating phdr information in read-write segments, degrading performance and memory use at run time for the unlikely benefit of a debugger in case of a core dump. Core files won't contain copies of phdrs or any other read-only segments, so we can't compare them with what's in the binary to tell whether we have a match, and comparing modifyable data, that is in the core file, is unlikely to work, since the data may have been modified. The only piece of information available to aid the decision is the dynamic table address. If the binary changes in any way and you try to use a core file referencing the other binary, all bets are off already. This will just try to increase the odds of proper functioning in case the only change to the binary was a change in its base load address, something that prelink and the dynamic loader will cooperate to do. > Perhaps you should raise the issue with the glibc developers, to see > what they can do? It doesn't make sense for glibc to do anything about this. We already have all the information we need, at least as far as glibc is concerned. My worry is about other platforms that might represent a different a different piece of information in l_ld. For those, we just won't get a match, and everything will proceed just like it did before, which I've carefully designed the code to do. -- Alexandre Oliva http://www.lsd.ic.unicamp.br/~oliva/ Secretary for FSF Latin America http://www.fsfla.org/ Red Hat Compiler Engineer aoliva@{redhat.com, gcc.gnu.org} Free Software Evangelist oliva@{lsd.ic.unicamp.br, gnu.org} ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: cope with varying prelink base addresses 2006-02-10 0:09 ` Alexandre Oliva @ 2006-02-10 1:42 ` Daniel Jacobowitz 2006-02-13 19:03 ` Alexandre Oliva 0 siblings, 1 reply; 19+ messages in thread From: Daniel Jacobowitz @ 2006-02-10 1:42 UTC (permalink / raw) To: Alexandre Oliva; +Cc: Mark Kettenis, gdb-patches, cagney On Thu, Feb 09, 2006 at 10:08:47PM -0200, Alexandre Oliva wrote: > > And MIPS targets > > have a history of doing things differently even for the same OS. > > Basically the two interpretations are: > > > a. l_addr is the absolute address at which the shared object is loaded. > > > b. l_addr is the relative address used to relocate the shared object. > > Actually, both interpretations are the same. It looks one or the > other because of the base addresses that appear in the program > headers. In general, dynamic libraries start at address zero, but > when they're prelinked, they don't, and then l_addr may remain as zero > to reflect that no additional offset was applied. No, Alexandre, Mark is talking about something that we actually experienced. The interpretations are _not_ the same when the base address in the program header is non-zero. There was at least one dynamic loader which set l_addr to the absolute address the segment was loaded to, even though the program header's l_addr was non-zero. I believe that this was, at varying times, MIPS Linux and MIPS NetBSD. At least one of the loaders was later changed to avoid the problem, and I'm not sure what happened to the other. The linker was also updated. -- Daniel Jacobowitz CodeSourcery ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: cope with varying prelink base addresses 2006-02-10 1:42 ` Daniel Jacobowitz @ 2006-02-13 19:03 ` Alexandre Oliva 2006-02-14 0:56 ` Kevin Buettner 0 siblings, 1 reply; 19+ messages in thread From: Alexandre Oliva @ 2006-02-13 19:03 UTC (permalink / raw) To: Mark Kettenis; +Cc: gdb-patches, cagney On Feb 9, 2006, Daniel Jacobowitz <drow@false.org> wrote: > On Thu, Feb 09, 2006 at 10:08:47PM -0200, Alexandre Oliva wrote: >> > And MIPS targets >> > have a history of doing things differently even for the same OS. >> > Basically the two interpretations are: >> >> > a. l_addr is the absolute address at which the shared object is loaded. >> >> > b. l_addr is the relative address used to relocate the shared object. >> >> Actually, both interpretations are the same. It looks one or the >> other because of the base addresses that appear in the program >> headers. In general, dynamic libraries start at address zero, but >> when they're prelinked, they don't, and then l_addr may remain as zero >> to reflect that no additional offset was applied. > No, Alexandre, Mark is talking about something that we actually > experienced. The interpretations are _not_ the same when the base > address in the program header is non-zero. There was at least > one dynamic loader which set l_addr to the absolute address > the segment was loaded to, even though the program header's l_addr > was non-zero. Yuck. Fair enough. Anyhow, I don't see any evidence that GDB actually supports any such broken l_addr semantics, so it's not like the patch would be breaking anything. If anything, it would be enabling gdb to work on such a system work, assuming l_ld is set up correctly. -- Alexandre Oliva http://www.lsd.ic.unicamp.br/~oliva/ Secretary for FSF Latin America http://www.fsfla.org/ Red Hat Compiler Engineer aoliva@{redhat.com, gcc.gnu.org} Free Software Evangelist oliva@{lsd.ic.unicamp.br, gnu.org} ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: cope with varying prelink base addresses 2006-02-13 19:03 ` Alexandre Oliva @ 2006-02-14 0:56 ` Kevin Buettner 2006-02-14 2:08 ` Daniel Jacobowitz 0 siblings, 1 reply; 19+ messages in thread From: Kevin Buettner @ 2006-02-14 0:56 UTC (permalink / raw) To: gdb-patches On Mon, 13 Feb 2006 17:03:30 -0200 Alexandre Oliva <aoliva@redhat.com> wrote: > On Feb 9, 2006, Daniel Jacobowitz <drow@false.org> wrote: > > > On Thu, Feb 09, 2006 at 10:08:47PM -0200, Alexandre Oliva wrote: > >> > And MIPS targets > >> > have a history of doing things differently even for the same OS. > >> > Basically the two interpretations are: > >> > >> > a. l_addr is the absolute address at which the shared object is loaded. > >> > >> > b. l_addr is the relative address used to relocate the shared object. > >> > >> Actually, both interpretations are the same. It looks one or the > >> other because of the base addresses that appear in the program > >> headers. In general, dynamic libraries start at address zero, but > >> when they're prelinked, they don't, and then l_addr may remain as zero > >> to reflect that no additional offset was applied. > > > No, Alexandre, Mark is talking about something that we actually > > experienced. The interpretations are _not_ the same when the base > > address in the program header is non-zero. There was at least > > one dynamic loader which set l_addr to the absolute address > > the segment was loaded to, even though the program header's l_addr > > was non-zero. > > Yuck. Fair enough. Anyhow, I don't see any evidence that GDB > actually supports any such broken l_addr semantics, so it's not like > the patch would be breaking anything. If anything, it would be > enabling gdb to work on such a system work, assuming l_ld is set up > correctly. I agree. (I've been careful to not let in any patches which would support alternate l_addr semantics.) I've been looking over your patch and would like to see it committed so long as it receives a some more testing first. Would it be possible for you to test it on Solaris system and a BSD system? Kevin ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: cope with varying prelink base addresses 2006-02-14 0:56 ` Kevin Buettner @ 2006-02-14 2:08 ` Daniel Jacobowitz 2006-02-14 18:40 ` Alexandre Oliva 0 siblings, 1 reply; 19+ messages in thread From: Daniel Jacobowitz @ 2006-02-14 2:08 UTC (permalink / raw) To: Kevin Buettner; +Cc: gdb-patches On Mon, Feb 13, 2006 at 05:56:37PM -0700, Kevin Buettner wrote: > On Mon, 13 Feb 2006 17:03:30 -0200 > Alexandre Oliva <aoliva@redhat.com> wrote: > > Yuck. Fair enough. Anyhow, I don't see any evidence that GDB > > actually supports any such broken l_addr semantics, so it's not like > > the patch would be breaking anything. If anything, it would be > > enabling gdb to work on such a system work, assuming l_ld is set up > > correctly. Yes - in fact I wish we'd thought of this at the time :-) > I agree. (I've been careful to not let in any patches which would support > alternate l_addr semantics.) > > I've been looking over your patch and would like to see it committed > so long as it receives a some more testing first. Would it be possible > for you to test it on Solaris system and a BSD system? If not, I can certainly manage Solaris; I don't have any BSD systems here but perhaps Mark K. can oblige? -- Daniel Jacobowitz CodeSourcery ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: cope with varying prelink base addresses 2006-02-14 2:08 ` Daniel Jacobowitz @ 2006-02-14 18:40 ` Alexandre Oliva 2006-02-14 18:53 ` Mark Kettenis 2006-02-20 17:37 ` Daniel Jacobowitz 0 siblings, 2 replies; 19+ messages in thread From: Alexandre Oliva @ 2006-02-14 18:40 UTC (permalink / raw) To: Kevin Buettner; +Cc: gdb-patches On Feb 14, 2006, Daniel Jacobowitz <drow@false.org> wrote: > On Mon, Feb 13, 2006 at 05:56:37PM -0700, Kevin Buettner wrote: >> I've been looking over your patch and would like to see it committed >> so long as it receives a some more testing first. Would it be possible >> for you to test it on Solaris system and a BSD system? After I moved from GES to OS Tools within Red Hat, all I have access to, that I know, is GNU/Linux. And, man, it feels good :-) (Actually, I can probably still log into GES Solaris boxes, but I don't know that I still have permission to use their resources, so I assume I shouldn't do it.) > If not, I can certainly manage Solaris; I don't have any BSD systems > here but perhaps Mark K. can oblige? May I accept your offer, and hope Mark K. extends one too? Thanks! -- Alexandre Oliva http://www.lsd.ic.unicamp.br/~oliva/ Secretary for FSF Latin America http://www.fsfla.org/ Red Hat Compiler Engineer aoliva@{redhat.com, gcc.gnu.org} Free Software Evangelist oliva@{lsd.ic.unicamp.br, gnu.org} ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: cope with varying prelink base addresses 2006-02-14 18:40 ` Alexandre Oliva @ 2006-02-14 18:53 ` Mark Kettenis 2006-02-20 18:16 ` Alexandre Oliva 2006-02-20 17:37 ` Daniel Jacobowitz 1 sibling, 1 reply; 19+ messages in thread From: Mark Kettenis @ 2006-02-14 18:53 UTC (permalink / raw) To: aoliva; +Cc: kevinb, gdb-patches > From: Alexandre Oliva <aoliva@redhat.com> > Date: Tue, 14 Feb 2006 16:40:36 -0200 > > On Feb 14, 2006, Daniel Jacobowitz <drow@false.org> wrote: > > > On Mon, Feb 13, 2006 at 05:56:37PM -0700, Kevin Buettner wrote: > > >> I've been looking over your patch and would like to see it committed > >> so long as it receives a some more testing first. Would it be possible > >> for you to test it on Solaris system and a BSD system? > > After I moved from GES to OS Tools within Red Hat, all I have access > to, that I know, is GNU/Linux. And, man, it feels good :-) > > (Actually, I can probably still log into GES Solaris boxes, but I > don't know that I still have permission to use their resources, so I > assume I shouldn't do it.) > > > If not, I can certainly manage Solaris; I don't have any BSD systems > > here but perhaps Mark K. can oblige? > > May I accept your offer, and hope Mark K. extends one too? Thanks! Yup, I'll test OpenBSD and FreeBSD. Mark ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: cope with varying prelink base addresses 2006-02-14 18:53 ` Mark Kettenis @ 2006-02-20 18:16 ` Alexandre Oliva 2006-02-20 21:49 ` Mark Kettenis 0 siblings, 1 reply; 19+ messages in thread From: Alexandre Oliva @ 2006-02-20 18:16 UTC (permalink / raw) To: Mark Kettenis; +Cc: kevinb, gdb-patches On Feb 14, 2006, Mark Kettenis <mark.kettenis@xs4all.nl> wrote: >> From: Alexandre Oliva <aoliva@redhat.com> >> Date: Tue, 14 Feb 2006 16:40:36 -0200 >> On Feb 14, 2006, Daniel Jacobowitz <drow@false.org> wrote: >> > If not, I can certainly manage Solaris; I don't have any BSD systems >> > here but perhaps Mark K. can oblige? >> May I accept your offer, and hope Mark K. extends one too? Thanks! > Yup, I'll test OpenBSD and FreeBSD. Ping? -- Alexandre Oliva http://www.lsd.ic.unicamp.br/~oliva/ Secretary for FSF Latin America http://www.fsfla.org/ Red Hat Compiler Engineer aoliva@{redhat.com, gcc.gnu.org} Free Software Evangelist oliva@{lsd.ic.unicamp.br, gnu.org} ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: cope with varying prelink base addresses 2006-02-20 18:16 ` Alexandre Oliva @ 2006-02-20 21:49 ` Mark Kettenis 0 siblings, 0 replies; 19+ messages in thread From: Mark Kettenis @ 2006-02-20 21:49 UTC (permalink / raw) To: aoliva; +Cc: mark.kettenis, kevinb, gdb-patches > From: Alexandre Oliva <aoliva@redhat.com> > Date: Mon, 20 Feb 2006 15:16:20 -0300 > > On Feb 14, 2006, Mark Kettenis <mark.kettenis@xs4all.nl> wrote: > > >> From: Alexandre Oliva <aoliva@redhat.com> > >> Date: Tue, 14 Feb 2006 16:40:36 -0200 > > >> On Feb 14, 2006, Daniel Jacobowitz <drow@false.org> wrote: > > >> > If not, I can certainly manage Solaris; I don't have any BSD systems > >> > here but perhaps Mark K. can oblige? > > >> May I accept your offer, and hope Mark K. extends one too? Thanks! > > > Yup, I'll test OpenBSD and FreeBSD. > > Ping? Tested it on OpenBSD/i386 and FreeBSD/amd64. Testsuite is still running on OpenBSD/mips64, but the shared library tests all passed, so I think this is ok. I don't really like the all-caps function names, but I realize you were just following the existing practice here. Anyway, the final call is Kevin's. Mark ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: cope with varying prelink base addresses 2006-02-14 18:40 ` Alexandre Oliva 2006-02-14 18:53 ` Mark Kettenis @ 2006-02-20 17:37 ` Daniel Jacobowitz 1 sibling, 0 replies; 19+ messages in thread From: Daniel Jacobowitz @ 2006-02-20 17:37 UTC (permalink / raw) To: Alexandre Oliva; +Cc: Kevin Buettner, gdb-patches On Tue, Feb 14, 2006 at 04:40:36PM -0200, Alexandre Oliva wrote: > > If not, I can certainly manage Solaris; I don't have any BSD systems > > here but perhaps Mark K. can oblige? > > May I accept your offer, and hope Mark K. extends one too? Thanks! FYI, I have tested this on Solaris, and it behaves fine. -- Daniel Jacobowitz CodeSourcery ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: cope with varying prelink base addresses 2006-02-08 5:35 cope with varying prelink base addresses Alexandre Oliva 2006-02-08 6:25 ` Eli Zaretskii 2006-02-08 21:40 ` Mark Kettenis @ 2006-02-20 17:43 ` Daniel Jacobowitz 2006-02-23 20:22 ` Alexandre Oliva 2 siblings, 1 reply; 19+ messages in thread From: Daniel Jacobowitz @ 2006-02-20 17:43 UTC (permalink / raw) To: Alexandre Oliva; +Cc: gdb-patches, cagney On Wed, Feb 08, 2006 at 03:18:01AM -0200, Alexandre Oliva wrote: > I'd appreciate if whoever reviews this would pay particular attention > to the gdb testcase; it's the first time I write one, and I could use > some guidance to make sure I'm not making undeserved assumptions. > It's bad enough that I have to use compile- and run-time flags that > will likely only work with GCC and GNU ld, and that the test requires > the prelink program to be in the PATH; I hope I'm coping well with > cases in which the flags are not accepted or prelink is not in place. The testcase behaves on Solaris, where there's no prelink binary. I'm a little worried about it being noisy where -shared doesn't work, and with various non-GCC tools. Maybe move the gcc_compiled check further up? Oh, and please add copyright notices to the testsuite files; they're pretty trivial, but we're trying to be consistent about that. -- Daniel Jacobowitz CodeSourcery ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: cope with varying prelink base addresses 2006-02-20 17:43 ` Daniel Jacobowitz @ 2006-02-23 20:22 ` Alexandre Oliva 2006-02-23 20:53 ` Daniel Jacobowitz 0 siblings, 1 reply; 19+ messages in thread From: Alexandre Oliva @ 2006-02-23 20:22 UTC (permalink / raw) To: Kevin Buettner, gdb-patches; +Cc: cagney [-- Attachment #1: Type: text/plain, Size: 736 bytes --] On Feb 20, 2006, Daniel Jacobowitz <drow@false.org> wrote: > The testcase behaves on Solaris, where there's no prelink binary. I'm > a little worried about it being noisy where -shared doesn't work, > and with various non-GCC tools. Maybe move the gcc_compiled check > further up? Isn't gcc_compiled only set when you actually try to compile something? That was my impression when I tried the test earlier, before I submitted the first version of this patch. > Oh, and please add copyright notices to the testsuite files; they're > pretty trivial, but we're trying to be consistent about that. Done, thanks for the info, I didn't realize that because other testcases I looked at didn't have any. Kevin, ok to install this one? [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: gdb-prelink-core-4.patch --] [-- Type: text/x-patch, Size: 16949 bytes --] for gdb/ChangeLog from 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). for gdb/testsuite/ChangeLog from Alexandre Oliva <aoliva@redhat.com> * gdb.base/prelink.exp: New test. * gdb.base/prelink.c, gdb.base/prelink-lib.c: New sources. Index: gdb/mipsnbsd-tdep.c =================================================================== --- gdb/mipsnbsd-tdep.c.orig 2006-02-14 16:30:44.000000000 -0200 +++ gdb/mipsnbsd-tdep.c 2006-02-23 17:07:50.000000000 -0300 @@ -339,6 +339,8 @@ mipsnbsd_ilp32_fetch_link_map_offsets (v 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 (vo 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: gdb/solib-legacy.c =================================================================== --- gdb/solib-legacy.c.orig 2006-02-14 16:30:44.000000000 -0200 +++ gdb/solib-legacy.c 2006-02-23 17:07:50.000000000 -0300 @@ -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: gdb/solib-svr4.c =================================================================== --- gdb/solib-svr4.c.orig 2006-02-14 16:30:44.000000000 -0200 +++ gdb/solib-svr4.c 2006-02-23 17:07:50.000000000 -0300 @@ -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: gdb/solib-svr4.h =================================================================== --- gdb/solib-svr4.h.orig 2006-02-14 16:30:44.000000000 -0200 +++ gdb/solib-svr4.h 2006-02-23 17:07:50.000000000 -0300 @@ -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: gdb/Makefile.in =================================================================== --- gdb/Makefile.in.orig 2006-02-23 17:06:06.000000000 -0300 +++ gdb/Makefile.in 2006-02-23 17:07:50.000000000 -0300 @@ -2582,7 +2582,8 @@ solib-sunos.o: solib-sunos.c $(defs_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: gdb/testsuite/gdb.base/prelink-lib.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ gdb/testsuite/gdb.base/prelink-lib.c 2006-02-23 17:14:55.000000000 -0300 @@ -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; +} Index: gdb/testsuite/gdb.base/prelink.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ gdb/testsuite/gdb.base/prelink.c 2006-02-23 17:14:58.000000000 -0300 @@ -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); +} Index: gdb/testsuite/gdb.base/prelink.exp =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ gdb/testsuite/gdb.base/prelink.exp 2006-02-23 17:07:50.000000000 -0300 @@ -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 +} + +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; +} + +if [get_compiler_info ${binfile}] { + return -1 +} + +if {$gcc_compiled == 0} { + 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 + [-- Attachment #3: Type: text/plain, Size: 249 bytes --] -- Alexandre Oliva http://www.lsd.ic.unicamp.br/~oliva/ Secretary for FSF Latin America http://www.fsfla.org/ Red Hat Compiler Engineer aoliva@{redhat.com, gcc.gnu.org} Free Software Evangelist oliva@{lsd.ic.unicamp.br, gnu.org} ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: cope with varying prelink base addresses 2006-02-23 20:22 ` Alexandre Oliva @ 2006-02-23 20:53 ` Daniel Jacobowitz 2006-02-24 7:42 ` Alexandre Oliva 0 siblings, 1 reply; 19+ messages in thread From: Daniel Jacobowitz @ 2006-02-23 20:53 UTC (permalink / raw) To: Alexandre Oliva; +Cc: Kevin Buettner, gdb-patches, cagney On Thu, Feb 23, 2006 at 05:18:11PM -0300, Alexandre Oliva wrote: > On Feb 20, 2006, Daniel Jacobowitz <drow@false.org> wrote: > > > The testcase behaves on Solaris, where there's no prelink binary. I'm > > a little worried about it being noisy where -shared doesn't work, > > and with various non-GCC tools. Maybe move the gcc_compiled check > > further up? > > Isn't gcc_compiled only set when you actually try to compile > something? That was my impression when I tried the test earlier, > before I submitted the first version of this patch. Once upon a time get_compiler_info needed $binfile. Now the argument is ignored, so you can move get_compiler_info up before the compilation. > > Oh, and please add copyright notices to the testsuite files; they're > > pretty trivial, but we're trying to be consistent about that. > > Done, thanks for the info, I didn't realize that because other > testcases I looked at didn't have any. Yes - retrofitting this is a bit tricky because some older testcases depend on line numbers. -- Daniel Jacobowitz CodeSourcery ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: cope with varying prelink base addresses 2006-02-23 20:53 ` Daniel Jacobowitz @ 2006-02-24 7:42 ` Alexandre Oliva 2006-02-28 1:50 ` Kevin Buettner 0 siblings, 1 reply; 19+ messages in thread From: Alexandre Oliva @ 2006-02-24 7:42 UTC (permalink / raw) To: Kevin Buettner; +Cc: gdb-patches, cagney [-- Attachment #1: Type: text/plain, Size: 851 bytes --] On Feb 23, 2006, Daniel Jacobowitz <drow@false.org> wrote: > On Thu, Feb 23, 2006 at 05:18:11PM -0300, Alexandre Oliva wrote: >> On Feb 20, 2006, Daniel Jacobowitz <drow@false.org> wrote: >> >> > The testcase behaves on Solaris, where there's no prelink binary. I'm >> > a little worried about it being noisy where -shared doesn't work, >> > and with various non-GCC tools. Maybe move the gcc_compiled check >> > further up? >> >> Isn't gcc_compiled only set when you actually try to compile >> something? That was my impression when I tried the test earlier, >> before I submitted the first version of this patch. > Once upon a time get_compiler_info needed $binfile. Now the argument > is ignored, so you can move get_compiler_info up before the > compilation. Aha! Ok, this should work, then (tested on GNU/Linux/x86_64) Ok to install? [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: gdb-prelink-core-5.patch --] [-- Type: text/x-patch, Size: 16948 bytes --] for gdb/ChangeLog from 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). for gdb/testsuite/ChangeLog from Alexandre Oliva <aoliva@redhat.com> * gdb.base/prelink.exp: New test. * gdb.base/prelink.c, gdb.base/prelink-lib.c: New sources. Index: gdb/mipsnbsd-tdep.c =================================================================== --- gdb/mipsnbsd-tdep.c.orig 2006-02-14 16:30:44.000000000 -0200 +++ gdb/mipsnbsd-tdep.c 2006-02-23 17:07:50.000000000 -0300 @@ -339,6 +339,8 @@ mipsnbsd_ilp32_fetch_link_map_offsets (v 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 (vo 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: gdb/solib-legacy.c =================================================================== --- gdb/solib-legacy.c.orig 2006-02-14 16:30:44.000000000 -0200 +++ gdb/solib-legacy.c 2006-02-23 17:07:50.000000000 -0300 @@ -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: gdb/solib-svr4.c =================================================================== --- gdb/solib-svr4.c.orig 2006-02-14 16:30:44.000000000 -0200 +++ gdb/solib-svr4.c 2006-02-23 17:07:50.000000000 -0300 @@ -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: gdb/solib-svr4.h =================================================================== --- gdb/solib-svr4.h.orig 2006-02-14 16:30:44.000000000 -0200 +++ gdb/solib-svr4.h 2006-02-23 17:07:50.000000000 -0300 @@ -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: gdb/Makefile.in =================================================================== --- gdb/Makefile.in.orig 2006-02-23 17:06:06.000000000 -0300 +++ gdb/Makefile.in 2006-02-23 17:07:50.000000000 -0300 @@ -2582,7 +2582,8 @@ solib-sunos.o: solib-sunos.c $(defs_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: gdb/testsuite/gdb.base/prelink-lib.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ gdb/testsuite/gdb.base/prelink-lib.c 2006-02-23 17:14:55.000000000 -0300 @@ -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; +} Index: gdb/testsuite/gdb.base/prelink.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ gdb/testsuite/gdb.base/prelink.c 2006-02-23 17:14:58.000000000 -0300 @@ -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); +} Index: gdb/testsuite/gdb.base/prelink.exp =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ gdb/testsuite/gdb.base/prelink.exp 2006-02-24 01:31:46.000000000 -0300 @@ -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 + [-- Attachment #3: Type: text/plain, Size: 250 bytes --] -- Alexandre Oliva http://www.lsd.ic.unicamp.br/~oliva/ Secretary for FSF Latin America http://www.fsfla.org/ Red Hat Compiler Engineer aoliva@{redhat.com, gcc.gnu.org} Free Software Evangelist oliva@{lsd.ic.unicamp.br, gnu.org} ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: cope with varying prelink base addresses 2006-02-24 7:42 ` Alexandre Oliva @ 2006-02-28 1:50 ` Kevin Buettner 0 siblings, 0 replies; 19+ messages in thread From: Kevin Buettner @ 2006-02-28 1:50 UTC (permalink / raw) To: gdb-patches, Alexandre Oliva On Fri, 24 Feb 2006 01:42:46 -0300 Alexandre Oliva <aoliva@redhat.com> wrote: > On Feb 23, 2006, Daniel Jacobowitz <drow@false.org> wrote: > > > On Thu, Feb 23, 2006 at 05:18:11PM -0300, Alexandre Oliva wrote: > >> On Feb 20, 2006, Daniel Jacobowitz <drow@false.org> wrote: > >> > >> > The testcase behaves on Solaris, where there's no prelink binary. I'm > >> > a little worried about it being noisy where -shared doesn't work, > >> > and with various non-GCC tools. Maybe move the gcc_compiled check > >> > further up? > >> > >> Isn't gcc_compiled only set when you actually try to compile > >> something? That was my impression when I tried the test earlier, > >> before I submitted the first version of this patch. > > > Once upon a time get_compiler_info needed $binfile. Now the argument > > is ignored, so you can move get_compiler_info up before the > > compilation. > > Aha! Ok, this should work, then (tested on GNU/Linux/x86_64) > > Ok to install? Yes, please commit this patch. Kevin ^ permalink raw reply [flat|nested] 19+ messages in thread
end of thread, other threads:[~2006-02-27 23:31 UTC | newest] Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2006-02-08 5:35 cope with varying prelink base addresses Alexandre Oliva 2006-02-08 6:25 ` Eli Zaretskii 2006-02-10 0:15 ` Alexandre Oliva 2006-02-08 21:40 ` Mark Kettenis 2006-02-10 0:09 ` Alexandre Oliva 2006-02-10 1:42 ` Daniel Jacobowitz 2006-02-13 19:03 ` Alexandre Oliva 2006-02-14 0:56 ` Kevin Buettner 2006-02-14 2:08 ` Daniel Jacobowitz 2006-02-14 18:40 ` Alexandre Oliva 2006-02-14 18:53 ` Mark Kettenis 2006-02-20 18:16 ` Alexandre Oliva 2006-02-20 21:49 ` Mark Kettenis 2006-02-20 17:37 ` Daniel Jacobowitz 2006-02-20 17:43 ` Daniel Jacobowitz 2006-02-23 20:22 ` Alexandre Oliva 2006-02-23 20:53 ` Daniel Jacobowitz 2006-02-24 7:42 ` Alexandre Oliva 2006-02-28 1:50 ` Kevin Buettner
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox