summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFilippo Arcidiacono <filippo.arcidiacono@st.com>2011-05-06 16:49:28 +0200
committerCarmelo Amoroso <carmelo.amoroso@st.com>2011-05-10 11:53:41 +0200
commit974d3140577ac740c8db2f1ad9635c4ba591361e (patch)
tree0bf1224803cd5d7e87bd03dabdb3694885e49871
parent3e68c52b941636714d2599ea8adda9520ec2de23 (diff)
libdl: fix local symbol's address handling in dladdr
Fix dladdr to correctly handle local function's address so backtrace_symbols print only the function address for these function, instead of showing the name of nearest one. Indeed the dladdr walk through the hash table to find the nearest symbol, that doesn't contain local symbols. Signed-off-by: Filippo Arcidiacono <filippo.arcidiacono@st.com> Signed-off-by: Carmelo Amoroso <carmelo.amoroso@st.com>
-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;