/*********************************************************************** * * * This software is part of the ast package * * Copyright (c) 1997-2009 AT&T Intellectual Property * * and is licensed under the * * Common Public License, Version 1.0 * * by AT&T Intellectual Property * * * * A copy of the License is available at * * http://www.opensource.org/licenses/cpl1.0.txt * * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * * * * Information and Software Systems Research * * AT&T Research * * Florham Park NJ * * * * Glenn Fowler * * * ***********************************************************************/ #pragma prototyped /* * Glenn Fowler * AT&T Research */ #ifndef _GNU_SOURCE #define _GNU_SOURCE 1 #endif #ifndef __EXTENSIONS__ #define __EXTENSIONS__ 1 #endif #include #include #if _hdr_rld_interface #include #endif /* * return a handle for the next layer down, * i.e., the next layer that has symbols covered * by the main prog and dll's loaded so far * * intentionally light on external lib calls * so this routine can be used early in process * startup */ #ifdef _DLL_RLD_SYM #define DEBUG 1 #if DEBUG typedef ssize_t (*Write_f)(int, const void*, size_t); #endif #undef dllnext void* _dll_next(int flags, _DLL_RLD_SYM_TYPE* here) { register char* vp; register void* lp; register int found = 0; char* s; char* b; char* e; char dummy[256]; #if DEBUG Write_f wr = 0; Write_f xr; char buf[1024]; #endif #if DEBUG if (getenv("DLL_DEBUG") && (vp = (char*)_rld_new_interface(_RLD_FIRST_PATHNAME))) { do { if (strcmp(vp, "MAIN") && (lp = dllopen(vp, flags))) { if (xr = (Write_f)dlsym(lp, "write")) wr = xr; } } while (vp = (char*)_rld_new_interface(_RLD_NEXT_PATHNAME)); } #endif if (vp = (char*)_rld_new_interface(_RLD_FIRST_PATHNAME)) { do { if (lp = dllopen(strcmp(vp, "MAIN") ? vp : (char*)0, flags)) { if (found) { b = e = 0; s = vp; for (;;) { switch (*s++) { case 0: break; case '/': b = s; e = 0; continue; case '.': if (!e) e = s - 1; continue; default: continue; } break; } if (b && e) { s = dummy; *s++ = '_'; *s++ = '_'; while (b < e) *s++ = *b++; b = "_dummy"; while (*s++ = *b++); if (dlsym(lp, dummy)) { dlclose(lp); lp = 0; } } if (lp) { #if DEBUG if (wr) (*wr)(2, buf, sfsprintf(buf, sizeof(buf), "dll: next %s\n", vp)); #endif return lp; } #if DEBUG else if (wr) (*wr)(2, buf, sfsprintf(buf, sizeof(buf), "dll: skip %s\n", vp)); #endif } else if ((_DLL_RLD_SYM_TYPE*)dlsym(lp, _DLL_RLD_SYM_STR) == here) { #if DEBUG if (wr) (*wr)(2, buf, sfsprintf(buf, sizeof(buf), "dll: this %s\n", vp)); #endif found = 1; } } } while (vp = (char*)_rld_new_interface(_RLD_NEXT_PATHNAME)); } return dllnext(flags); } #endif #ifndef RTLD_NEXT #if _dll_DYNAMIC #include extern struct link_dynamic _DYNAMIC; #endif #endif void* dllnext(int flags) { register void* dll; #ifndef RTLD_NEXT #if _dll_DYNAMIC register struct link_map* map; register char* s; register char* b; #endif register char* ver; char* path; static char next[] = { _DLL_NEXT_PATH }; #endif #ifdef RTLD_NEXT dll = RTLD_NEXT; #else path = next; #if _dll_DYNAMIC for (map = _DYNAMIC.ld_un.ld_1->ld_loaded; map; map = map->lm_next) { b = 0; s = map->lm_name; while (*s) if (*s++ == '/') b = s; if (b && b[0] == 'l' && b[1] == 'i' && b[2] == 'b' && b[3] == 'c' && b[4] == '.') { path = map->lm_name; break; } } #endif ver = path + strlen(path); while (!(dll = dllopen(path, flags))) { do { if (ver <= path) return 0; } while (*--ver != '.'); if (*(ver + 1) <= '0' || *(ver + 1) >= '9') return 0; *ver = 0; } #endif return dll; }