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