diff options
author | Alexandre Oliva <aoliva@redhat.com> | 2006-02-28 04:29:10 +0000 |
---|---|---|
committer | Alexandre Oliva <aoliva@redhat.com> | 2006-02-28 04:29:10 +0000 |
commit | cc10cae34af928d41c47ed1014abafde99165c28 (patch) | |
tree | 2c3f3ca2a60ceff5fbdffd0b28c62617b35ca585 /gdb/solib-svr4.c | |
parent | 10cd14b412f60d6d99ab6ce6c40b1c56c2a8195c (diff) | |
download | gdb-cc10cae34af928d41c47ed1014abafde99165c28.zip gdb-cc10cae34af928d41c47ed1014abafde99165c28.tar.gz gdb-cc10cae34af928d41c47ed1014abafde99165c28.tar.bz2 |
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.c | 113 |
1 files changed, 108 insertions, 5 deletions
diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c index caadb4a..7d740a3 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; |