diff options
author | Filippo Arcidiacono <filippo.arcidiacono@st.com> | 2010-07-30 09:17:58 +0200 |
---|---|---|
committer | Carmelo Amoroso <carmelo.amoroso@st.com> | 2010-09-17 16:11:27 +0200 |
commit | 4136ca46e391faf1a6ce58b9a1a709b248213fb4 (patch) | |
tree | 2c36d609ff2110027d637f68db8c4af47bd38333 /ldso | |
parent | 94cc6edb78a12655c0602a246fa1cbdc8c6d0ad9 (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>
Diffstat (limited to 'ldso')
-rw-r--r-- | ldso/include/dl-hash.h | 12 | ||||
-rw-r--r-- | ldso/include/ldso.h | 6 | ||||
-rw-r--r-- | ldso/ldso/dl-debug.c | 57 | ||||
-rw-r--r-- | ldso/ldso/dl-hash.c | 6 | ||||
-rw-r--r-- | ldso/ldso/ldso.c | 98 | ||||
-rw-r--r-- | ldso/ldso/sh/elfinterp.c | 8 | ||||
-rw-r--r-- | 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 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, ¤t_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], + ¤t_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) { |