[git commit] ldso: Add support for LD_WARN and LD_TRACE_PRELINKING

Filippo Arcidiacono filippo.arcidiacono at st.com
Fri Jul 1 07:49:47 UTC 2011


commit: http://git.uclibc.org/uClibc/commit/?id=4136ca46e391faf1a6ce58b9a1a709b248213fb4
branch: http://git.uclibc.org/uClibc/commit/?id=refs/heads/master

Added support for the following tracing capabilities:
- LD_WARN to warn about undefined symbols during the lookup stage.
- LD_TRACE_PRELINKING to trace the needed libraries of the object
  that we are prelinking.

Signed-off-by: Filippo Arcidiacono <filippo.arcidiacono at st.com>
Signed-off-by: Carmelo Amoroso <carmelo.amoroso at st.com>
---
 ldso/include/dl-hash.h   |   12 ++++--
 ldso/include/ldso.h      |    6 +++
 ldso/ldso/dl-debug.c     |   57 ++++++++++++++++++++++++++
 ldso/ldso/dl-hash.c      |    6 ++-
 ldso/ldso/ldso.c         |   98 ++++++++++++++++++++++++++++++++++++++--------
 ldso/ldso/sh/elfinterp.c |    8 +++-
 ldso/libdl/libdl.c       |    2 +-
 7 files changed, 164 insertions(+), 25 deletions(-)

diff --git a/ldso/include/dl-hash.h b/ldso/include/dl-hash.h
index f47384c..e138e1d 100644
--- a/ldso/include/dl-hash.h
+++ b/ldso/include/dl-hash.h
@@ -25,6 +25,10 @@ struct dyn_elf {
   struct dyn_elf * prev;
 };
 
+struct sym_val {
+  const ElfW(Sym) *s;
+  struct elf_resolve *m;
+};
 
 /* Structure to describe a single list of scope elements.  The lookup
    functions get passed an array of pointers to such structures.  */
@@ -154,17 +158,17 @@ extern struct elf_resolve * _dl_add_elf_hash_table(const char * libname,
 
 /* Only need extra arg with some configurations */
 #if !((defined(USE_TLS) && USE_TLS) || defined __FDPIC__)
-# define _dl_lookup_hash(n, r, m, c, t) _dl_lookup_hash(n, r, m, c)
+# define _dl_lookup_hash(n, r, m, s, c, t) _dl_lookup_hash(n, r, m, s, c)
 #endif
 extern char *_dl_lookup_hash(const char *name, struct r_scope_elem *scope,
-	struct elf_resolve *mytpnt, int type_class,
+	struct elf_resolve *mytpnt, struct sym_val *symbol, int type_class,
 	struct elf_resolve **tpntp);
 
 static __always_inline char *_dl_find_hash(const char *name, struct r_scope_elem *scope,
-					struct elf_resolve *mytpnt, int type_class,
+					struct elf_resolve *mytpnt, struct sym_val *symbol, int type_class,
 					struct elf_resolve **tpntp)
 {
-	return _dl_lookup_hash(name, scope, mytpnt, type_class, tpntp);
+	return _dl_lookup_hash(name, scope, mytpnt, symbol, type_class, tpntp);
 }
 
 extern int _dl_linux_dynamic_link(void);
diff --git a/ldso/include/ldso.h b/ldso/include/ldso.h
index 536f7d2..9aa610e 100644
--- a/ldso/include/ldso.h
+++ b/ldso/include/ldso.h
@@ -73,6 +73,12 @@ extern char *_dl_preload;              /* Things to be loaded before the libs */
 extern char *_dl_ldsopath;             /* Where the shared lib loader was found */
 extern const char *_dl_progname;       /* The name of the executable being run */
 extern size_t _dl_pagesize;            /* Store the page size for use later */
+#ifdef __LDSO_PRELINK_SUPPORT__
+extern char *_dl_trace_prelink;        /* Library for prelinking trace */
+extern struct elf_resolve *_dl_trace_prelink_map;	/* Library map for prelinking trace */
+#else
+#define _dl_trace_prelink		0
+#endif
 
 #if defined(USE_TLS) && USE_TLS
 extern void _dl_add_to_slotinfo (struct link_map  *l);
diff --git a/ldso/ldso/dl-debug.c b/ldso/ldso/dl-debug.c
index 7ce8bfb..47b3231 100644
--- a/ldso/ldso/dl-debug.c
+++ b/ldso/ldso/dl-debug.c
@@ -104,3 +104,60 @@ static void debug_reloc(ElfW(Sym) *symtab, char *strtab, ELF_RELOC *rpnt)
 #define debug_reloc(symtab, strtab, rpnt)
 
 #endif /* __SUPPORT_LD_DEBUG__ */
+
+#ifdef __LDSO_PRELINK_SUPPORT__
+static void
+internal_function
+_dl_debug_lookup (const char *undef_name, struct elf_resolve *undef_map,
+					const ElfW(Sym) *ref, struct sym_val *value, int type_class)
+{
+#ifdef SHARED
+  unsigned long symbol_addr;
+
+  if (_dl_trace_prelink)
+    {
+      int conflict = 0;
+	  struct elf_resolve *tls_tpnt = NULL;
+      struct sym_val val = { NULL, NULL };
+
+      if ((_dl_trace_prelink_map == NULL
+	   || _dl_trace_prelink_map == _dl_loaded_modules)
+	  && undef_map != _dl_loaded_modules)
+	{
+		symbol_addr = (unsigned long)
+					  _dl_find_hash(undef_name, &undef_map->symbol_scope,
+									undef_map, &val, type_class, &tls_tpnt);
+
+	  if (val.s != value->s || val.m != value->m)
+	    conflict = 1;
+	}
+
+      if (value->s
+	  && (__builtin_expect (ELF_ST_TYPE(value->s->st_info)
+				== STT_TLS, 0)))
+	type_class = 4;
+
+      if (conflict
+	  || _dl_trace_prelink_map == undef_map
+	  || _dl_trace_prelink_map == NULL
+	  || type_class == 4)
+	{
+	  _dl_dprintf (1, "%s %x %x -> %x %x ",
+		      conflict ? "conflict" : "lookup",
+		      (size_t) undef_map->mapaddr,
+		      (size_t) (((ElfW(Addr)) ref) - undef_map->mapaddr),
+		      (size_t) (value->m ? value->m->mapaddr : 0),
+		      (size_t) (value->s ? value->s->st_value : 0));
+	  if (conflict)
+	    _dl_dprintf (1, "x %x %x ",
+			(size_t) (val.m ? val.m->mapaddr : 0),
+			(size_t) (val.s ? val.s->st_value : 0));
+	  _dl_dprintf (1, "/%x %s\n", type_class, undef_name);
+	}
+}
+#endif
+}
+
+#else
+#define _dl_debug_lookup(undef_name, undef_map, ref, value, type_class)
+#endif
diff --git a/ldso/ldso/dl-hash.c b/ldso/ldso/dl-hash.c
index 2c4571f..2e2111f 100644
--- a/ldso/ldso/dl-hash.c
+++ b/ldso/ldso/dl-hash.c
@@ -269,7 +269,7 @@ _dl_lookup_sysv_hash(struct elf_resolve *tpnt, ElfW(Sym) *symtab, unsigned long
  * relocations or when we call an entry in the PLT table for the first time.
  */
 char *_dl_lookup_hash(const char *name, struct r_scope_elem *scope, struct elf_resolve *mytpnt,
-	int type_class, struct elf_resolve **tpntp)
+	struct sym_val *symbol, int type_class, struct elf_resolve **tpntp)
 {
 	struct elf_resolve *tpnt = NULL;
 	ElfW(Sym) *symtab;
@@ -339,6 +339,10 @@ char *_dl_lookup_hash(const char *name, struct r_scope_elem *scope, struct elf_r
 	}
 
 	if (sym) {
+		if (symbol) {
+			symbol->s = sym;
+			symbol->m = tpnt;
+		}
 		/* At this point we have found the requested symbol, do binding */
 #if defined(USE_TLS) && USE_TLS
 		if (ELF_ST_TYPE(sym->st_info) == STT_TLS) {
diff --git a/ldso/ldso/ldso.c b/ldso/ldso/ldso.c
index ff3519f..8c6e4d1 100644
--- a/ldso/ldso/ldso.c
+++ b/ldso/ldso/ldso.c
@@ -57,6 +57,11 @@ struct r_debug *_dl_debug_addr = NULL;	/* Used to communicate with the gdb debug
 void *(*_dl_malloc_function) (size_t size) = NULL;
 void (*_dl_free_function) (void *p) = NULL;
 
+#ifdef __LDSO_PRELINK_SUPPORT__
+char *_dl_trace_prelink                      = NULL;	/* Library for prelinking trace */
+struct elf_resolve *_dl_trace_prelink_map    = NULL;	/* Library module for prelinking trace */
+bool _dl_verbose				= true;					/* On by default */
+#endif
 static int _dl_secure = 1; /* Are we dealing with setuid stuff? */
 
 #ifdef __SUPPORT_LD_DEBUG__
@@ -285,6 +290,31 @@ static void __attribute__ ((destructor)) __attribute_used__ _dl_fini(void)
 	}
 }
 
+#ifdef __LDSO_PRELINK_SUPPORT__
+
+static void trace_objects(struct elf_resolve *tpnt, char *str_name)
+{
+	if (_dl_strcmp(_dl_trace_prelink, tpnt->libname) == 0)
+		_dl_trace_prelink_map = tpnt;
+	if (tpnt->libtype == elf_executable) {
+/* Main executeble */
+		_dl_dprintf(1, "\t%s => %s (%x, %x)", tpnt->libname, tpnt->libname,
+					tpnt->mapaddr, DL_LOADADDR_BASE(tpnt->loadaddr));
+	} else {
+/* Preloaded, Needed or interpreter */
+		_dl_dprintf(1, "\t%s => %s (%x, %x)", str_name, tpnt->libname,
+					tpnt->mapaddr, DL_LOADADDR_BASE(tpnt->loadaddr));
+	}
+
+	if ((tpnt->libtype != program_interpreter) && (tpnt->l_tls_modid))
+		_dl_dprintf (1, " TLS(%x, %x)\n", tpnt->l_tls_modid,
+					(size_t) tpnt->l_tls_offset);
+	else
+		_dl_dprintf (1, "\n");
+}
+
+#endif
+
 static ptrdiff_t _dl_build_local_scope (struct elf_resolve **list,
 										struct elf_resolve *map)
 {
@@ -715,6 +745,16 @@ of this helper program; chances are you did not intend to run this program.\n\
 	}
 #endif
 
+#ifdef __LDSO_PRELINK_SUPPORT__
+{
+	char *ld_warn = _dl_getenv ("LD_WARN", envp);
+
+	if (ld_warn && *ld_warn == '\0')
+		_dl_verbose = false;
+}
+	_dl_trace_prelink = _dl_getenv("LD_TRACE_PRELINKING", envp);
+#endif
+
 	if (_dl_getenv("LD_TRACE_LOADED_OBJECTS", envp) != NULL) {
 		trace_loaded_objects++;
 	}
@@ -768,7 +808,7 @@ of this helper program; chances are you did not intend to run this program.\n\
 				tpnt1 = _dl_load_shared_library(_dl_secure, &rpnt, NULL, str, trace_loaded_objects);
 				if (!tpnt1) {
 #ifdef __LDSO_LDD_SUPPORT__
-					if (trace_loaded_objects)
+					if (trace_loaded_objects || _dl_trace_prelink)
 						_dl_dprintf(1, "\t%s => not found\n", str);
 					else
 #endif
@@ -782,7 +822,7 @@ of this helper program; chances are you did not intend to run this program.\n\
 					_dl_debug_early("Loading: (%x) %s\n", DL_LOADADDR_BASE(tpnt1->loadaddr), tpnt1->libname);
 
 #ifdef __LDSO_LDD_SUPPORT__
-					if (trace_loaded_objects &&
+					if (trace_loaded_objects && !_dl_trace_prelink &&
 					    tpnt1->usage_count == 1) {
 						/* This is a real hack to make
 						 * ldd not print the library
@@ -859,7 +899,7 @@ of this helper program; chances are you did not intend to run this program.\n\
 			tpnt1 = _dl_load_shared_library(0, &rpnt, NULL, cp2, trace_loaded_objects);
 			if (!tpnt1) {
 # ifdef __LDSO_LDD_SUPPORT__
-				if (trace_loaded_objects)
+				if (trace_loaded_objects || _dl_trace_prelink)
 					_dl_dprintf(1, "\t%s => not found\n", cp2);
 				else
 # endif
@@ -873,7 +913,7 @@ of this helper program; chances are you did not intend to run this program.\n\
 				_dl_debug_early("Loading: (%x) %s\n", DL_LOADADDR_BASE(tpnt1->loadaddr), tpnt1->libname);
 
 # ifdef __LDSO_LDD_SUPPORT__
-				if (trace_loaded_objects &&
+				if (trace_loaded_objects && !_dl_trace_prelink &&
 				    tpnt1->usage_count == 1) {
 					_dl_dprintf(1, "\t%s => %s (%x)\n",
 						    cp2, tpnt1->libname,
@@ -911,7 +951,7 @@ of this helper program; chances are you did not intend to run this program.\n\
 
 				if (!(tpnt1 = _dl_load_shared_library(0, &rpnt, tcurr, lpntstr, trace_loaded_objects)))	{
 #ifdef __LDSO_LDD_SUPPORT__
-					if (trace_loaded_objects) {
+					if (trace_loaded_objects || _dl_trace_prelink) {
 						_dl_dprintf(1, "\t%s => not found\n", lpntstr);
 						continue;
 					} else
@@ -932,7 +972,7 @@ of this helper program; chances are you did not intend to run this program.\n\
 				_dl_debug_early("Loading: (%x) %s\n", DL_LOADADDR_BASE(tpnt1->loadaddr), tpnt1->libname);
 
 #ifdef __LDSO_LDD_SUPPORT__
-				if (trace_loaded_objects &&
+				if (trace_loaded_objects && !_dl_trace_prelink &&
 				    tpnt1->usage_count == 1) {
 					_dl_dprintf(1, "\t%s => %s (%x)\n",
 						    lpntstr, tpnt1->libname,
@@ -947,12 +987,15 @@ of this helper program; chances are you did not intend to run this program.\n\
 	/* Keep track of the number of elements in the global scope */
 	nscope_elem = nlist;
 
-	--nlist; /* Exclude the application. */
+	if (_dl_loaded_modules->libtype == elf_executable) {
+		--nlist; /* Exclude the application. */
+		tcurr = _dl_loaded_modules->next;
+	} else
+		tcurr = _dl_loaded_modules;
 	init_fini_list = _dl_malloc(nlist * sizeof(struct elf_resolve *));
 	i = 0;
-	for (tcurr = _dl_loaded_modules->next; tcurr; tcurr = tcurr->next) {
+	for (; tcurr; tcurr = tcurr->next)
 		init_fini_list[i++] = tcurr;
-	}
 
 	/* Sort the INIT/FINI list in dependency order. */
 	for (tcurr = _dl_loaded_modules->next; tcurr; tcurr = tcurr->next) {
@@ -1065,7 +1108,7 @@ of this helper program; chances are you did not intend to run this program.\n\
 	 */
 	global_scope = &_dl_loaded_modules->symbol_scope;
 
-	/* Build the local scope for the each loaded modules. */
+	/* Build the local scope for each loaded modules. */
 	local_scope = _dl_malloc(nscope_elem * sizeof(struct elf_resolve *));
 	i = 1;
 	for (tcurr = _dl_loaded_modules->next; tcurr; tcurr = tcurr->next) {
@@ -1082,7 +1125,7 @@ of this helper program; chances are you did not intend to run this program.\n\
 
 #ifdef __LDSO_LDD_SUPPORT__
 	/* End of the line for ldd.... */
-	if (trace_loaded_objects) {
+	if (trace_loaded_objects && !_dl_trace_prelink) {
 		_dl_dprintf(1, "\t%s => %s (%x)\n",
 			    rpnt->dyn->libname + _dl_strlen(_dl_ldsopath) + 1,
 			    rpnt->dyn->libname, DL_LOADADDR_BASE(rpnt->dyn->loadaddr));
@@ -1118,6 +1161,27 @@ of this helper program; chances are you did not intend to run this program.\n\
 #endif
 
 
+	/* FIXME: The glibc code doesn't trace the ldso when LD_TRACE_OBJECT is set,
+	 *        here has been trace to mantain the original one.
+	 *        Another difference Vs Glibc is the check to verify if an object is
+	 *        "statically linked" (only if LD_TRACE_OBJECT is on).
+	 */
+
+#ifdef __LDSO_PRELINK_SUPPORT__
+	if (_dl_trace_prelink) {
+		for (i = 0; i < nscope_elem; i++)
+			trace_objects(scope_elem_list[i],
+				_dl_get_last_path_component(scope_elem_list[i]->libname));
+
+		if (_dl_verbose)
+			/* Warn about undefined symbols. */
+			if (_dl_symbol_tables)
+				if (_dl_fixup(_dl_symbol_tables, global_scope, unlazy))
+					_dl_exit(-1);
+		_dl_exit(0);
+	}
+#endif
+
 	_dl_debug_early("Beginning relocation fixups\n");
 
 #ifdef __mips__
@@ -1172,7 +1236,7 @@ of this helper program; chances are you did not intend to run this program.\n\
 	 * ld.so.1, so we have to look up each symbol individually.
 	 */
 
-	_dl_envp = (unsigned long *) (intptr_t) _dl_find_hash(__C_SYMBOL_PREFIX__ "__environ", global_scope, NULL, 0, NULL);
+	_dl_envp = (unsigned long *) (intptr_t) _dl_find_hash(__C_SYMBOL_PREFIX__ "__environ", global_scope, NULL, NULL, 0, NULL);
 	if (_dl_envp)
 		*_dl_envp = (unsigned long) envp;
 
@@ -1228,21 +1292,21 @@ of this helper program; chances are you did not intend to run this program.\n\
 
 	/* Find the real malloc function and make ldso functions use that from now on */
 	_dl_malloc_function = (void* (*)(size_t)) (intptr_t) _dl_find_hash(__C_SYMBOL_PREFIX__ "malloc",
-			global_scope, NULL, ELF_RTYPE_CLASS_PLT, NULL);
+			global_scope, NULL, NULL, ELF_RTYPE_CLASS_PLT, NULL);
 
 #if defined(USE_TLS) && USE_TLS
 	/* Find the real functions and make ldso functions use them from now on */
 	_dl_calloc_function = (void* (*)(size_t, size_t)) (intptr_t)
-		_dl_find_hash(__C_SYMBOL_PREFIX__ "calloc", global_scope, NULL, ELF_RTYPE_CLASS_PLT, NULL);
+		_dl_find_hash(__C_SYMBOL_PREFIX__ "calloc", global_scope, NULL, NULL, ELF_RTYPE_CLASS_PLT, NULL);
 
 	_dl_realloc_function = (void* (*)(void *, size_t)) (intptr_t)
-		_dl_find_hash(__C_SYMBOL_PREFIX__ "realloc", global_scope, NULL, ELF_RTYPE_CLASS_PLT, NULL);
+		_dl_find_hash(__C_SYMBOL_PREFIX__ "realloc", global_scope, NULL, NULL, ELF_RTYPE_CLASS_PLT, NULL);
 
 	_dl_free_function = (void (*)(void *)) (intptr_t)
-		_dl_find_hash(__C_SYMBOL_PREFIX__ "free", global_scope, NULL, ELF_RTYPE_CLASS_PLT, NULL);
+		_dl_find_hash(__C_SYMBOL_PREFIX__ "free", global_scope, NULL, NULL, ELF_RTYPE_CLASS_PLT, NULL);
 
 	_dl_memalign_function = (void* (*)(size_t, size_t)) (intptr_t)
-		_dl_find_hash(__C_SYMBOL_PREFIX__ "memalign", global_scope, NULL, ELF_RTYPE_CLASS_PLT, NULL);
+		_dl_find_hash(__C_SYMBOL_PREFIX__ "memalign", global_scope, NULL, NULL, ELF_RTYPE_CLASS_PLT, NULL);
 
 #endif
 
diff --git a/ldso/ldso/sh/elfinterp.c b/ldso/ldso/sh/elfinterp.c
index d3465bc..e94c44d 100644
--- a/ldso/ldso/sh/elfinterp.c
+++ b/ldso/ldso/sh/elfinterp.c
@@ -69,7 +69,7 @@ unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
 	got_addr = (char **) instr_addr;
 
 	/* Get the address of the GOT entry */
-	new_addr = _dl_find_hash(symname, &_dl_loaded_modules->symbol_scope, tpnt, ELF_RTYPE_CLASS_PLT, NULL);
+	new_addr = _dl_find_hash(symname, &_dl_loaded_modules->symbol_scope, tpnt, NULL, ELF_RTYPE_CLASS_PLT, NULL);
 
 	if (unlikely(!new_addr)) {
 		_dl_dprintf(2, "%s: can't resolve symbol '%s'\n", _dl_progname, symname);
@@ -161,6 +161,7 @@ _dl_do_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope,
 #endif
 
 	struct elf_resolve *tls_tpnt = NULL;
+	struct sym_val current_value = { NULL, NULL };
 
 	reloc_addr = (unsigned long *)(intptr_t) (tpnt->loadaddr + (unsigned long) rpnt->r_offset);
 	reloc_type = ELF32_R_TYPE(rpnt->r_info);
@@ -169,7 +170,7 @@ _dl_do_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope,
 	symname = strtab + symtab[symtab_index].st_name;
 
 	if (symtab_index) {
-		symbol_addr = (unsigned long) _dl_find_hash(symname, scope, tpnt,
+		symbol_addr = (unsigned long) _dl_find_hash(symname, scope, tpnt, &current_value,
 							    elf_machine_type_class(reloc_type), &tls_tpnt);
 		/*
 		 * We want to allow undefined references to weak symbols - this might
@@ -186,6 +187,9 @@ _dl_do_reloc (struct elf_resolve *tpnt, struct r_scope_elem *scope,
 			/* Let the caller to handle the error: it may be non fatal if called from dlopen */
 			return 1;
 		}
+		if (_dl_trace_prelink)
+			_dl_debug_lookup (symname, tpnt, &symtab[symtab_index],
+							&current_value, elf_machine_type_class(reloc_type));
 	}
 
 #if defined (__SUPPORT_LD_DEBUG__)
diff --git a/ldso/libdl/libdl.c b/ldso/libdl/libdl.c
index b641fe3..3b49216 100644
--- a/ldso/libdl/libdl.c
+++ b/ldso/libdl/libdl.c
@@ -706,7 +706,7 @@ void *dlsym(void *vhandle, const char *name)
 	tpnt = NULL;
 	if (handle == _dl_symbol_tables)
 		tpnt = handle->dyn; /* Only search RTLD_GLOBAL objs if global object */
-	ret = _dl_find_hash(name2, &handle->dyn->symbol_scope, NULL, 0, &tls_tpnt);
+	ret = _dl_find_hash(name2, &handle->dyn->symbol_scope, NULL, NULL, 0, &tls_tpnt);
 
 #if defined(USE_TLS) && USE_TLS && defined SHARED
 	if (tls_tpnt) {
-- 
1.7.3.4



More information about the uClibc-cvs mailing list