summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ldso/include/dl-defs.h8
-rw-r--r--ldso/libdl/libdl.c12
2 files changed, 18 insertions, 2 deletions
diff --git a/ldso/include/dl-defs.h b/ldso/include/dl-defs.h
index be0a81da3..88ff81593 100644
--- a/ldso/include/dl-defs.h
+++ b/ldso/include/dl-defs.h
@@ -179,6 +179,14 @@ typedef struct {
#define DL_LOOKUP_ADDRESS(ADDRESS) (ADDRESS)
#endif
+/* On some architectures dladdr can't use st_size of all symbols this way. */
+#define DL_ADDR_SYM_MATCH(SYM_ADDR, SYM, MATCHSYM, ADDR) \
+ ((ADDR) >= (SYM_ADDR) \
+ && ((((SYM)->st_shndx == SHN_UNDEF || (SYM)->st_size == 0) \
+ && (ADDR) == (SYM_ADDR)) \
+ || (ADDR) < (SYM_ADDR) + (SYM)->st_size) \
+ && (!(MATCHSYM) || MATCHSYM < (SYM_ADDR)))
+
/* Use this macro to convert a pointer to a function's entry point to
* a pointer to function. The pointer is assumed to have already been
* relocated. LOADADDR is passed because it may contain additional
diff --git a/ldso/libdl/libdl.c b/ldso/libdl/libdl.c
index 68cd5797e..b80495e71 100644
--- a/ldso/libdl/libdl.c
+++ b/ldso/libdl/libdl.c
@@ -1067,7 +1067,11 @@ int dladdr(const void *__address, Dl_info * __info)
ElfW(Addr) symbol_addr;
symbol_addr = (ElfW(Addr)) DL_RELOC_ADDR(pelf->loadaddr, symtab[si].st_value);
- if (symbol_addr <= (ElfW(Addr))__address && (!sf || sa < symbol_addr)) {
+ if ((symtab[si].st_shndx != SHN_UNDEF
+ || symtab[si].st_value != 0)
+ && ELF_ST_TYPE(symtab[si].st_info) != STT_TLS
+ && DL_ADDR_SYM_MATCH(symbol_addr, &symtab[si], sa,
+ (ElfW(Addr)) __address)) {
sa = symbol_addr;
sn = si;
sf = 1;
@@ -1083,7 +1087,11 @@ int dladdr(const void *__address, Dl_info * __info)
ElfW(Addr) symbol_addr;
symbol_addr = (ElfW(Addr)) DL_RELOC_ADDR(pelf->loadaddr, symtab[si].st_value);
- if (symbol_addr <= (ElfW(Addr))__address && (!sf || sa < symbol_addr)) {
+ if ((symtab[si].st_shndx != SHN_UNDEF
+ || symtab[si].st_value != 0)
+ && ELF_ST_TYPE(symtab[si].st_info) != STT_TLS
+ && DL_ADDR_SYM_MATCH(symbol_addr, &symtab[si], sa,
+ (ElfW(Addr)) __address)) {
sa = symbol_addr;
sn = si;
sf = 1;