dllnext.c revision 7c2fbfb345896881c631598ee3852ce9ce33fb07
/***********************************************************************
* *
* This software is part of the ast package *
* Copyright (c) 1997-2008 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 <gsf@research.att.com> *
* *
***********************************************************************/
#pragma prototyped
/*
* Glenn Fowler
* AT&T Research
*/
#ifndef _GNU_SOURCE
#define _GNU_SOURCE 1
#endif
#ifndef __EXTENSIONS__
#define __EXTENSIONS__ 1
#endif
#include <ast.h>
#include <dlldefs.h>
#if _hdr_rld_interface
#include <rld_interface.h>
#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 = dlopen(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 = dlopen(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 <link.h>
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 = dlopen(path, flags)))
{
do
{
if (ver <= path)
return 0;
} while (*--ver != '.');
if (*(ver + 1) <= '0' || *(ver + 1) >= '9')
return 0;
*ver = 0;
}
#endif
return dll;
}