gdb/ChangeLog:

* solib-svr4.h (struct link_map_offsets): Add l_ld_offset and
l_ld_size fields.
* solib-svr4.c (struct lm_info): Add l_addr field.
(LM_ADDR_FROM_LINK_MAP): Renamed from LM_ADDR.
(HAS_LM_DYNAMIC_FROM_LINK_MAP): New.
(LM_DYNAMIC_FROM_LINK_MAP): New.
(LM_ADDR_CHECK): New.  Use it instead of LM_ADDR.
(svr4_current_sos): Initialize l_addr.  Adjust.
(svr4_relocate_section_addresses): Adjust.
(svr4_ilp32_fetch_link_map_offsets): Define new members.
(svr4_lp64_fetch_link_map_offsets): Likewise.
* solib-legacy.c (legacy_svr4_fetch_link_map_offsets): Likewise.
* mipsnbsd-tdep.c (mipsnbsd_ilp32_fetch_link_map_offsets): Likewise.
(mipsnbsd_lp64_fetch_link_map_offsets): Likewise.
* Makefile.in (solib-svr4.o): Depend on $(elf_bfd_h).
gdb/testsuite/ChangeLog:
* gdb.base/prelink.exp: New test.
* gdb.base/prelink.c, gdb.base/prelink-lib.c: New sources.
This commit is contained in:
Alexandre Oliva 2006-02-28 04:29:10 +00:00
parent 10cd14b412
commit cc10cae34a
10 changed files with 346 additions and 6 deletions

View File

@ -1,3 +1,21 @@
2006-02-28 Alexandre Oliva <aoliva@redhat.com>
* solib-svr4.h (struct link_map_offsets): Add l_ld_offset and
l_ld_size fields.
* solib-svr4.c (struct lm_info): Add l_addr field.
(LM_ADDR_FROM_LINK_MAP): Renamed from LM_ADDR.
(HAS_LM_DYNAMIC_FROM_LINK_MAP): New.
(LM_DYNAMIC_FROM_LINK_MAP): New.
(LM_ADDR_CHECK): New. Use it instead of LM_ADDR.
(svr4_current_sos): Initialize l_addr. Adjust.
(svr4_relocate_section_addresses): Adjust.
(svr4_ilp32_fetch_link_map_offsets): Define new members.
(svr4_lp64_fetch_link_map_offsets): Likewise.
* solib-legacy.c (legacy_svr4_fetch_link_map_offsets): Likewise.
* mipsnbsd-tdep.c (mipsnbsd_ilp32_fetch_link_map_offsets): Likewise.
(mipsnbsd_lp64_fetch_link_map_offsets): Likewise.
* Makefile.in (solib-svr4.o): Depend on $(elf_bfd_h).
2006-02-26 David S. Miller <davem@sunset.davemloft.net>
* config/sparc/linux.mt (TDEPFILES): Add sol2-tdep.o.

View File

@ -2582,7 +2582,8 @@ solib-sunos.o: solib-sunos.c $(defs_h) $(gdb_string_h) $(symtab_h) $(bfd_h) \
solib-svr4.o: solib-svr4.c $(defs_h) $(elf_external_h) $(elf_common_h) \
$(elf_mips_h) $(symtab_h) $(bfd_h) $(symfile_h) $(objfiles_h) \
$(gdbcore_h) $(target_h) $(inferior_h) $(gdb_assert_h) \
$(solist_h) $(solib_h) $(solib_svr4_h) $(bfd_target_h) $(exec_h)
$(solist_h) $(solib_h) $(solib_svr4_h) $(bfd_target_h) $(elf_bfd_h) \
$(exec_h)
sol-thread.o: sol-thread.c $(defs_h) $(gdbthread_h) $(target_h) \
$(inferior_h) $(gdb_stat_h) $(gdbcmd_h) $(gdbcore_h) $(regcache_h) \
$(solib_h) $(symfile_h) $(gdb_string_h) $(gregset_h)

View File

@ -339,6 +339,8 @@ mipsnbsd_ilp32_fetch_link_map_offsets (void)
lmo.l_addr_size = 4;
lmo.l_name_offset = 8;
lmo.l_name_size = 4;
lmo.l_ld_offset = 12;
lmo.l_ld_size = 4;
lmo.l_next_offset = 16;
lmo.l_next_size = 4;
lmo.l_prev_offset = 20;
@ -369,6 +371,8 @@ mipsnbsd_lp64_fetch_link_map_offsets (void)
lmo.l_addr_size = 8;
lmo.l_name_offset = 16;
lmo.l_name_size = 8;
lmo.l_ld_offset = 24;
lmo.l_ld_size = 8;
lmo.l_next_offset = 32;
lmo.l_next_size = 8;
lmo.l_prev_offset = 40;

View File

@ -69,6 +69,9 @@ legacy_svr4_fetch_link_map_offsets (void)
lmo.l_next_offset = offsetof (struct link_map, l_next);
lmo.l_next_size = fieldsize (struct link_map, l_next);
lmo.l_ld_offset = offsetof (struct link_map, l_ld);
lmo.l_ld_size = fieldsize (struct link_map, l_ld);
lmo.l_prev_offset = offsetof (struct link_map, l_prev);
lmo.l_prev_size = fieldsize (struct link_map, l_prev);
@ -84,6 +87,10 @@ legacy_svr4_fetch_link_map_offsets (void)
lmo.l_next_offset = offsetof (struct link_map, lm_next);
lmo.l_next_size = fieldsize (struct link_map, lm_next);
/* FIXME: Is this the right field name, or is it available at all? */
lmo.l_ld_offset = offsetof (struct link_map, lm_ld);
lmo.l_ld_size = fieldsize (struct link_map, lm_ld);
lmo.l_name_offset = offsetof (struct link_map, lm_name);
lmo.l_name_size = fieldsize (struct link_map, lm_name);
#else /* !defined(HAVE_STRUCT_LINK_MAP_WITH_LM_MEMBERS) */
@ -98,6 +105,10 @@ legacy_svr4_fetch_link_map_offsets (void)
lmo.l_name_offset = offsetof (struct so_map, som_path);
lmo.l_name_size = fieldsize (struct so_map, som_path);
/* FIXME: Is the address of the dynamic table available? */
lmo.l_ld_offset = 0;
lmo.l_ld_size = 0;
#endif /* HAVE_STRUCT_SO_MAP_WITH_SOM_MEMBERS */
#endif /* HAVE_STRUCT_LINK_MAP_WITH_LM_MEMBERS */
#endif /* HAVE_STRUCT_LINK_MAP_WITH_L_MEMBERS */

View File

@ -42,6 +42,7 @@
#include "solib-svr4.h"
#include "bfd-target.h"
#include "elf-bfd.h"
#include "exec.h"
static struct link_map_offsets *svr4_fetch_link_map_offsets (void);
@ -59,6 +60,13 @@ struct lm_info
rather than void *, so that we may use byte offsets to find the
various fields without the need for a cast. */
gdb_byte *lm;
/* Amount by which addresses in the binary should be relocated to
match the inferior. This could most often be taken directly
from lm, but when prelinking is involved and the prelink base
address changes, we may need a different offset, we want to
warn about the difference and compute it only once. */
CORE_ADDR l_addr;
};
/* On SVR4 systems, a list of symbols in the dynamic linker where
@ -127,14 +135,101 @@ static char *main_name_list[] =
/* link map access functions */
static CORE_ADDR
LM_ADDR (struct so_list *so)
LM_ADDR_FROM_LINK_MAP (struct so_list *so)
{
struct link_map_offsets *lmo = svr4_fetch_link_map_offsets ();
return (CORE_ADDR) extract_signed_integer (so->lm_info->lm + lmo->l_addr_offset,
return (CORE_ADDR) extract_signed_integer (so->lm_info->lm
+ lmo->l_addr_offset,
lmo->l_addr_size);
}
static int
HAS_LM_DYNAMIC_FROM_LINK_MAP ()
{
struct link_map_offsets *lmo = svr4_fetch_link_map_offsets ();
return (lmo->l_ld_size != 0);
}
static CORE_ADDR
LM_DYNAMIC_FROM_LINK_MAP (struct so_list *so)
{
struct link_map_offsets *lmo = svr4_fetch_link_map_offsets ();
gdb_assert (lmo->l_ld_size != 0);
return (CORE_ADDR) extract_signed_integer (so->lm_info->lm
+ lmo->l_ld_offset,
lmo->l_ld_size);
}
static CORE_ADDR
LM_ADDR_CHECK (struct so_list *so, bfd *abfd)
{
if (so->lm_info->l_addr == (CORE_ADDR)-1)
{
struct bfd_section *dyninfo_sect;
CORE_ADDR l_addr, l_dynaddr, dynaddr, align = 0x1000;
l_addr = LM_ADDR_FROM_LINK_MAP (so);
if (! abfd || ! HAS_LM_DYNAMIC_FROM_LINK_MAP ())
goto set_addr;
l_dynaddr = LM_DYNAMIC_FROM_LINK_MAP (so);
dyninfo_sect = bfd_get_section_by_name (abfd, ".dynamic");
if (dyninfo_sect == NULL)
goto set_addr;
dynaddr = bfd_section_vma (abfd, dyninfo_sect);
if (dynaddr + l_addr != l_dynaddr)
{
warning (_(".dynamic section for \"%s\" "
"is not at the expected address"), so->so_name);
if (bfd_get_flavour (abfd) == bfd_target_elf_flavour)
{
Elf_Internal_Ehdr *ehdr = elf_tdata (abfd)->elf_header;
Elf_Internal_Phdr *phdr = elf_tdata (abfd)->phdr;
int i;
align = 1;
for (i = 0; i < ehdr->e_phnum; i++)
if (phdr[i].p_type == PT_LOAD && phdr[i].p_align > align)
align = phdr[i].p_align;
}
/* Turn it into a mask. */
align--;
/* If the changes match the alignment requirements, we
assume we're using a core file that was generated by the
same binary, just prelinked with a different base offset.
If it doesn't match, we may have a different binary, the
same binary with the dynamic table loaded at an unrelated
location, or anything, really. To avoid regressions,
don't adjust the base offset in the latter case, although
odds are that, if things really changed, debugging won't
quite work. */
if ((l_addr & align) == 0 && ((dynaddr - l_dynaddr) & align) == 0)
{
l_addr = l_dynaddr - dynaddr;
warning (_("difference appears to be caused by prelink, "
"adjusting expectations"));
}
}
set_addr:
so->lm_info->l_addr = l_addr;
}
return so->lm_info->l_addr;
}
static CORE_ADDR
LM_NEXT (struct so_list *so)
{
@ -649,6 +744,8 @@ svr4_current_sos (void)
free_so (new);
else
{
new->lm_info->l_addr = (CORE_ADDR)-1;
new->next = 0;
*link_ptr = new;
link_ptr = &new->next;
@ -912,7 +1009,7 @@ enable_break (void)
if (strcmp (buf, so->so_original_name) == 0)
{
load_addr_found = 1;
load_addr = LM_ADDR (so);
load_addr = LM_ADDR_CHECK (so, tmp_bfd);
break;
}
so = so->next;
@ -1272,8 +1369,10 @@ static void
svr4_relocate_section_addresses (struct so_list *so,
struct section_table *sec)
{
sec->addr = svr4_truncate_ptr (sec->addr + LM_ADDR (so));
sec->endaddr = svr4_truncate_ptr (sec->endaddr + LM_ADDR (so));
sec->addr = svr4_truncate_ptr (sec->addr + LM_ADDR_CHECK (so,
sec->bfd));
sec->endaddr = svr4_truncate_ptr (sec->endaddr + LM_ADDR_CHECK (so,
sec->bfd));
}
@ -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;

View File

@ -50,6 +50,12 @@ struct link_map_offsets
/* Size of l_addr field in struct link_map. */
int l_addr_size;
/* Offset to l_ld field in struct link_map. */
int l_ld_offset;
/* Size of l_ld field in struct link_map. */
int l_ld_size;
/* Offset to l_next field in struct link_map. */
int l_next_offset;

View File

@ -1,3 +1,8 @@
2006-02-28 Alexandre Oliva <aoliva@redhat.com>
* gdb.base/prelink.exp: New test.
* gdb.base/prelink.c, gdb.base/prelink-lib.c: New sources.
2006-02-24 Wu Zhou <woodzltc@cn.ibm.com>
* gdb.fortran/derived-type.f90: New file.

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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