aboutsummaryrefslogtreecommitdiff
path: root/elf
diff options
context:
space:
mode:
Diffstat (limited to 'elf')
-rw-r--r--elf/dl-addr.c36
-rw-r--r--elf/dl-iteratephdr.c8
-rw-r--r--elf/dl-load.c5
-rw-r--r--elf/dl-open.c24
-rw-r--r--elf/dl-sym.c5
5 files changed, 52 insertions, 26 deletions
diff --git a/elf/dl-addr.c b/elf/dl-addr.c
index e13105572e..17745b55b0 100644
--- a/elf/dl-addr.c
+++ b/elf/dl-addr.c
@@ -134,22 +134,12 @@ _dl_addr (const void *address, Dl_info *info,
/* Find the highest-addressed object that ADDRESS is not below. */
for (Lmid_t ns = 0; ns < DL_NNS; ++ns)
for (struct link_map *l = GL(dl_ns)[ns]._ns_loaded; l; l = l->l_next)
- if (addr >= l->l_map_start && addr < l->l_map_end)
+ if (addr >= l->l_map_start && addr < l->l_map_end
+ && (l->l_contiguous || _dl_addr_inside_object (l, addr)))
{
- /* Make sure it lies within one of L's segments. */
- int n = l->l_phnum;
- const ElfW(Addr) reladdr = addr - l->l_addr;
- while (--n >= 0)
- if (l->l_phdr[n].p_type == PT_LOAD)
- {
- if (reladdr - l->l_phdr[n].p_vaddr >= 0
- && reladdr - l->l_phdr[n].p_vaddr < l->l_phdr[n].p_memsz)
- {
- determine_info (addr, l, info, mapp, symbolp);
- result = 1;
- goto out;
- }
- }
+ determine_info (addr, l, info, mapp, symbolp);
+ result = 1;
+ goto out;
}
out:
@@ -158,3 +148,19 @@ _dl_addr (const void *address, Dl_info *info,
return result;
}
libc_hidden_def (_dl_addr)
+
+/* Return non-zero if ADDR lies within one of L's segments. */
+int
+internal_function
+_dl_addr_inside_object (struct link_map *l, const ElfW(Addr) addr)
+{
+ int n = l->l_phnum;
+ const ElfW(Addr) reladdr = addr - l->l_addr;
+
+ while (--n >= 0)
+ if (l->l_phdr[n].p_type == PT_LOAD
+ && reladdr - l->l_phdr[n].p_vaddr >= 0
+ && reladdr - l->l_phdr[n].p_vaddr < l->l_phdr[n].p_memsz)
+ return 1;
+ return 0;
+}
diff --git a/elf/dl-iteratephdr.c b/elf/dl-iteratephdr.c
index d03d8b6daf..55cf10852e 100644
--- a/elf/dl-iteratephdr.c
+++ b/elf/dl-iteratephdr.c
@@ -1,5 +1,5 @@
/* Get loaded objects program headers.
- Copyright (C) 2001,2002,2003,2004,2006 Free Software Foundation, Inc.
+ Copyright (C) 2001,2002,2003,2004,2006,2007 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Jakub Jelinek <jakub@redhat.com>, 2001.
@@ -54,9 +54,9 @@ __dl_iterate_phdr (int (*callback) (struct dl_phdr_info *info,
nloaded += GL(dl_ns)[cnt]._ns_nloaded;
if (caller >= (const void *) l->l_map_start
- && caller < (const void *) l->l_map_end)
- /* There must be exactly one DSO for the range of the virtual
- memory. Otherwise something is really broken. */
+ && caller < (const void *) l->l_map_end
+ && (l->l_contiguous
+ || _dl_addr_inside_object (l, (ElfW(Addr)) caller)))
ns = cnt;
}
diff --git a/elf/dl-load.c b/elf/dl-load.c
index 1650ef953a..025b9fd86b 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -1,5 +1,5 @@
/* Map in a shared object's segments from the file.
- Copyright (C) 1995-2005, 2006 Free Software Foundation, Inc.
+ Copyright (C) 1995-2005, 2006, 2007 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
@@ -1223,6 +1223,8 @@ cannot allocate TLS data structures for initial thread");
loadcmds[nloadcmds - 1].mapstart - c->mapend,
PROT_NONE);
+ l->l_contiguous = 1;
+
goto postmap;
}
@@ -1242,6 +1244,7 @@ cannot allocate TLS data structures for initial thread");
/* Remember which part of the address space this object uses. */
l->l_map_start = c->mapstart + l->l_addr;
l->l_map_end = l->l_map_start + maplength;
+ l->l_contiguous = !has_holes;
while (c < &loadcmds[nloadcmds])
{
diff --git a/elf/dl-open.c b/elf/dl-open.c
index a043cf61b6..2000f580c3 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -201,10 +201,10 @@ dl_open_worker (void *a)
for (Lmid_t ns = 0; ns < DL_NNS; ++ns)
for (l = GL(dl_ns)[ns]._ns_loaded; l != NULL; l = l->l_next)
if (caller_dlopen >= (const void *) l->l_map_start
- && caller_dlopen < (const void *) l->l_map_end)
+ && caller_dlopen < (const void *) l->l_map_end
+ && (l->l_contiguous
+ || _dl_addr_inside_object (l, (ElfW(Addr)) caller_dlopen)))
{
- /* There must be exactly one DSO for the range of the virtual
- memory. Otherwise something is really broken. */
assert (ns == l->l_ns);
call_map = l;
goto found_caller;
@@ -662,3 +662,21 @@ show_scope (struct link_map *new)
}
}
#endif
+
+#ifdef IS_IN_rtld
+/* Return non-zero if ADDR lies within one of L's segments. */
+int
+internal_function
+_dl_addr_inside_object (struct link_map *l, const ElfW(Addr) addr)
+{
+ int n = l->l_phnum;
+ const ElfW(Addr) reladdr = addr - l->l_addr;
+
+ while (--n >= 0)
+ if (l->l_phdr[n].p_type == PT_LOAD
+ && reladdr - l->l_phdr[n].p_vaddr >= 0
+ && reladdr - l->l_phdr[n].p_vaddr < l->l_phdr[n].p_memsz)
+ return 1;
+ return 0;
+}
+#endif
diff --git a/elf/dl-sym.c b/elf/dl-sym.c
index 1c3ab5c877..0e1b258b5a 100644
--- a/elf/dl-sym.c
+++ b/elf/dl-sym.c
@@ -98,10 +98,9 @@ do_sym (void *handle, const char *name, void *who,
for (Lmid_t ns = 0; ns < DL_NNS; ++ns)
for (struct link_map *l = GL(dl_ns)[ns]._ns_loaded; l != NULL;
l = l->l_next)
- if (caller >= l->l_map_start && caller < l->l_map_end)
+ if (caller >= l->l_map_start && caller < l->l_map_end
+ && (l->l_contiguous || _dl_addr_inside_object (l, caller)))
{
- /* There must be exactly one DSO for the range of the virtual
- memory. Otherwise something is really broken. */
match = l;
break;
}