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