summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFilippo Arcidiacono <filippo.arcidiacono@st.com>2010-07-30 09:17:58 +0200
committerCarmelo Amoroso <carmelo.amoroso@st.com>2010-09-17 16:11:27 +0200
commit4136ca46e391faf1a6ce58b9a1a709b248213fb4 (patch)
tree2c36d609ff2110027d637f68db8c4af47bd38333
parent94cc6edb78a12655c0602a246fa1cbdc8c6d0ad9 (diff)
ldso: Add support for LD_WARN and LD_TRACE_PRELINKING
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@st.com> Signed-off-by: Carmelo Amoroso <carmelo.amoroso@st.com>
-rw-r--r--ldso/include/dl-hash.h12
-rw-r--r--ldso/include/ldso.h6
-rw-r--r--ldso/ldso/dl-debug.c57
-rw-r--r--ldso/ldso/dl-hash.c6
-rw-r--r--ldso/ldso/ldso.c98
-rw-r--r--ldso/ldso/sh/elfinterp.c8
-rw-r--r--ldso/libdl/libdl.c2
7 files changed, 164 insertions, 25 deletions
diff --git a/ldso/include/dl-hash.h b/ldso/include/dl-hash.h
index f47384c31..e138e1d4b 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 536f7d266..9aa610e7b 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 7ce8bfbce..47b32316e 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 2c4571f20..2e2111fa9 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 ff3519f7c..8c6e4d185 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 d3465bcd5..e94c44dad 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 b641fe366..3b49216d4 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) {