浏览代码

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>
Filippo Arcidiacono 14 年之前
父节点
当前提交
974d314057
共有 2 个文件被更改,包括 18 次插入2 次删除
  1. 8 0
      ldso/include/dl-defs.h
  2. 10 2
      ldso/libdl/libdl.c

+ 8 - 0
ldso/include/dl-defs.h

@@ -179,6 +179,14 @@ typedef struct {
 #define DL_LOOKUP_ADDRESS(ADDRESS) (ADDRESS)
 #define DL_LOOKUP_ADDRESS(ADDRESS) (ADDRESS)
 #endif
 #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
 /* 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
  * a pointer to function.  The pointer is assumed to have already been
  * relocated.  LOADADDR is passed because it may contain additional
  * relocated.  LOADADDR is passed because it may contain additional

+ 10 - 2
ldso/libdl/libdl.c

@@ -1067,7 +1067,11 @@ int dladdr(const void *__address, Dl_info * __info)
 					ElfW(Addr) symbol_addr;
 					ElfW(Addr) symbol_addr;
 
 
 					symbol_addr = (ElfW(Addr)) DL_RELOC_ADDR(pelf->loadaddr, symtab[si].st_value);
 					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;
 						sa = symbol_addr;
 						sn = si;
 						sn = si;
 						sf = 1;
 						sf = 1;
@@ -1083,7 +1087,11 @@ int dladdr(const void *__address, Dl_info * __info)
 				ElfW(Addr) symbol_addr;
 				ElfW(Addr) symbol_addr;
 
 
 				symbol_addr = (ElfW(Addr)) DL_RELOC_ADDR(pelf->loadaddr, symtab[si].st_value);
 				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;
 					sa = symbol_addr;
 					sn = si;
 					sn = si;
 					sf = 1;
 					sf = 1;