1160814Ssimon/* dso_dlfcn.c -*- mode:C; c-file-style: "eay" -*- */
2296341Sdelphij/*
3296341Sdelphij * Written by Geoff Thorpe (geoff@geoffthorpe.net) for the OpenSSL project
4296341Sdelphij * 2000.
568651Skris */
668651Skris/* ====================================================================
768651Skris * Copyright (c) 2000 The OpenSSL Project.  All rights reserved.
868651Skris *
968651Skris * Redistribution and use in source and binary forms, with or without
1068651Skris * modification, are permitted provided that the following conditions
1168651Skris * are met:
1268651Skris *
1368651Skris * 1. Redistributions of source code must retain the above copyright
14296341Sdelphij *    notice, this list of conditions and the following disclaimer.
1568651Skris *
1668651Skris * 2. Redistributions in binary form must reproduce the above copyright
1768651Skris *    notice, this list of conditions and the following disclaimer in
1868651Skris *    the documentation and/or other materials provided with the
1968651Skris *    distribution.
2068651Skris *
2168651Skris * 3. All advertising materials mentioning features or use of this
2268651Skris *    software must display the following acknowledgment:
2368651Skris *    "This product includes software developed by the OpenSSL Project
2468651Skris *    for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)"
2568651Skris *
2668651Skris * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
2768651Skris *    endorse or promote products derived from this software without
2868651Skris *    prior written permission. For written permission, please contact
2968651Skris *    licensing@OpenSSL.org.
3068651Skris *
3168651Skris * 5. Products derived from this software may not be called "OpenSSL"
3268651Skris *    nor may "OpenSSL" appear in their names without prior written
3368651Skris *    permission of the OpenSSL Project.
3468651Skris *
3568651Skris * 6. Redistributions of any form whatsoever must retain the following
3668651Skris *    acknowledgment:
3768651Skris *    "This product includes software developed by the OpenSSL Project
3868651Skris *    for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)"
3968651Skris *
4068651Skris * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
4168651Skris * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
4268651Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
4368651Skris * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
4468651Skris * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
4568651Skris * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
4668651Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
4768651Skris * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
4868651Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
4968651Skris * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
5068651Skris * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
5168651Skris * OF THE POSSIBILITY OF SUCH DAMAGE.
5268651Skris * ====================================================================
5368651Skris *
5468651Skris * This product includes cryptographic software written by Eric Young
5568651Skris * (eay@cryptsoft.com).  This product includes software written by Tim
5668651Skris * Hudson (tjh@cryptsoft.com).
5768651Skris *
5868651Skris */
5968651Skris
60296341Sdelphij/*
61296341Sdelphij * We need to do this early, because stdio.h includes the header files that
62296341Sdelphij * handle _GNU_SOURCE and other similar macros.  Defining it later is simply
63296341Sdelphij * too late, because those headers are protected from re- inclusion.
64296341Sdelphij */
65279264Sdelphij#ifndef _GNU_SOURCE
66296341Sdelphij# define _GNU_SOURCE            /* make sure dladdr is declared */
67238405Sjkim#endif
68238405Sjkim
6968651Skris#include <stdio.h>
7068651Skris#include "cryptlib.h"
7168651Skris#include <openssl/dso.h>
7268651Skris
7368651Skris#ifndef DSO_DLFCN
7468651SkrisDSO_METHOD *DSO_METHOD_dlfcn(void)
75296341Sdelphij{
76296341Sdelphij    return NULL;
77296341Sdelphij}
7868651Skris#else
7968651Skris
80296341Sdelphij# ifdef HAVE_DLFCN_H
81296341Sdelphij#  ifdef __osf__
82296341Sdelphij#   define __EXTENSIONS__
83296341Sdelphij#  endif
84296341Sdelphij#  include <dlfcn.h>
85296341Sdelphij#  define HAVE_DLINFO 1
86296341Sdelphij#  if defined(_AIX) || defined(__CYGWIN__) || \
87238405Sjkim     defined(__SCO_VERSION__) || defined(_SCO_ELF) || \
88238405Sjkim     (defined(__osf__) && !defined(RTLD_NEXT))     || \
89238405Sjkim     (defined(__OpenBSD__) && !defined(RTLD_SELF)) || \
90296341Sdelphij        defined(__ANDROID__)
91296341Sdelphij#   undef HAVE_DLINFO
92296341Sdelphij#  endif
93238405Sjkim# endif
9468651Skris
9568651Skris/* Part of the hack in "dlfcn_load" ... */
96296341Sdelphij# define DSO_MAX_TRANSLATED_SIZE 256
9768651Skris
98109998Smarkmstatic int dlfcn_load(DSO *dso);
9968651Skrisstatic int dlfcn_unload(DSO *dso);
10068651Skrisstatic void *dlfcn_bind_var(DSO *dso, const char *symname);
10168651Skrisstatic DSO_FUNC_TYPE dlfcn_bind_func(DSO *dso, const char *symname);
102296341Sdelphij# if 0
10368651Skrisstatic int dlfcn_unbind(DSO *dso, char *symname, void *symptr);
10468651Skrisstatic int dlfcn_init(DSO *dso);
10568651Skrisstatic int dlfcn_finish(DSO *dso);
106109998Smarkmstatic long dlfcn_ctrl(DSO *dso, int cmd, long larg, void *parg);
107296341Sdelphij# endif
108109998Smarkmstatic char *dlfcn_name_converter(DSO *dso, const char *filename);
109160814Ssimonstatic char *dlfcn_merger(DSO *dso, const char *filespec1,
110296341Sdelphij                          const char *filespec2);
111296341Sdelphijstatic int dlfcn_pathbyaddr(void *addr, char *path, int sz);
112238405Sjkimstatic void *dlfcn_globallookup(const char *name);
11368651Skris
11468651Skrisstatic DSO_METHOD dso_meth_dlfcn = {
115296341Sdelphij    "OpenSSL 'dlfcn' shared library method",
116296341Sdelphij    dlfcn_load,
117296341Sdelphij    dlfcn_unload,
118296341Sdelphij    dlfcn_bind_var,
119296341Sdelphij    dlfcn_bind_func,
12068651Skris/* For now, "unbind" doesn't exist */
121296341Sdelphij# if 0
122296341Sdelphij    NULL,                       /* unbind_var */
123296341Sdelphij    NULL,                       /* unbind_func */
124296341Sdelphij# endif
125296341Sdelphij    NULL,                       /* ctrl */
126296341Sdelphij    dlfcn_name_converter,
127296341Sdelphij    dlfcn_merger,
128296341Sdelphij    NULL,                       /* init */
129296341Sdelphij    NULL,                       /* finish */
130296341Sdelphij    dlfcn_pathbyaddr,
131296341Sdelphij    dlfcn_globallookup
132296341Sdelphij};
13368651Skris
13468651SkrisDSO_METHOD *DSO_METHOD_dlfcn(void)
135296341Sdelphij{
136296341Sdelphij    return (&dso_meth_dlfcn);
137296341Sdelphij}
13868651Skris
139296341Sdelphij/*
140296341Sdelphij * Prior to using the dlopen() function, we should decide on the flag we
141296341Sdelphij * send. There's a few different ways of doing this and it's a messy
142296341Sdelphij * venn-diagram to match up which platforms support what. So as we don't have
143296341Sdelphij * autoconf yet, I'm implementing a hack that could be hacked further
144296341Sdelphij * relatively easily to deal with cases as we find them. Initially this is to
145296341Sdelphij * cope with OpenBSD.
146296341Sdelphij */
147296341Sdelphij# if defined(__OpenBSD__) || defined(__NetBSD__)
148296341Sdelphij#  ifdef DL_LAZY
149296341Sdelphij#   define DLOPEN_FLAG DL_LAZY
150296341Sdelphij#  else
151296341Sdelphij#   ifdef RTLD_NOW
152296341Sdelphij#    define DLOPEN_FLAG RTLD_NOW
153296341Sdelphij#   else
154296341Sdelphij#    define DLOPEN_FLAG 0
155296341Sdelphij#   endif
156296341Sdelphij#  endif
157296341Sdelphij# else
158296341Sdelphij#  ifdef OPENSSL_SYS_SUNOS
159296341Sdelphij#   define DLOPEN_FLAG 1
160296341Sdelphij#  else
161296341Sdelphij#   define DLOPEN_FLAG RTLD_NOW /* Hope this works everywhere else */
162296341Sdelphij#  endif
163296341Sdelphij# endif
16468651Skris
165296341Sdelphij/*
166296341Sdelphij * For this DSO_METHOD, our meth_data STACK will contain; (i) the handle
167296341Sdelphij * (void*) returned from dlopen().
16868651Skris */
16968651Skris
170109998Smarkmstatic int dlfcn_load(DSO *dso)
171296341Sdelphij{
172296341Sdelphij    void *ptr = NULL;
173296341Sdelphij    /* See applicable comments in dso_dl.c */
174296341Sdelphij    char *filename = DSO_convert_filename(dso, NULL);
175296341Sdelphij    int flags = DLOPEN_FLAG;
17668651Skris
177296341Sdelphij    if (filename == NULL) {
178296341Sdelphij        DSOerr(DSO_F_DLFCN_LOAD, DSO_R_NO_FILENAME);
179296341Sdelphij        goto err;
180296341Sdelphij    }
181296341Sdelphij# ifdef RTLD_GLOBAL
182296341Sdelphij    if (dso->flags & DSO_FLAG_GLOBAL_SYMBOLS)
183296341Sdelphij        flags |= RTLD_GLOBAL;
184296341Sdelphij# endif
185296341Sdelphij    ptr = dlopen(filename, flags);
186296341Sdelphij    if (ptr == NULL) {
187296341Sdelphij        DSOerr(DSO_F_DLFCN_LOAD, DSO_R_LOAD_FAILED);
188296341Sdelphij        ERR_add_error_data(4, "filename(", filename, "): ", dlerror());
189296341Sdelphij        goto err;
190296341Sdelphij    }
191296341Sdelphij    if (!sk_void_push(dso->meth_data, (char *)ptr)) {
192296341Sdelphij        DSOerr(DSO_F_DLFCN_LOAD, DSO_R_STACK_ERROR);
193296341Sdelphij        goto err;
194296341Sdelphij    }
195296341Sdelphij    /* Success */
196296341Sdelphij    dso->loaded_filename = filename;
197296341Sdelphij    return (1);
198296341Sdelphij err:
199296341Sdelphij    /* Cleanup! */
200296341Sdelphij    if (filename != NULL)
201296341Sdelphij        OPENSSL_free(filename);
202296341Sdelphij    if (ptr != NULL)
203296341Sdelphij        dlclose(ptr);
204296341Sdelphij    return (0);
205109998Smarkm}
20668651Skris
20768651Skrisstatic int dlfcn_unload(DSO *dso)
208296341Sdelphij{
209296341Sdelphij    void *ptr;
210296341Sdelphij    if (dso == NULL) {
211296341Sdelphij        DSOerr(DSO_F_DLFCN_UNLOAD, ERR_R_PASSED_NULL_PARAMETER);
212296341Sdelphij        return (0);
213296341Sdelphij    }
214296341Sdelphij    if (sk_void_num(dso->meth_data) < 1)
215296341Sdelphij        return (1);
216296341Sdelphij    ptr = sk_void_pop(dso->meth_data);
217296341Sdelphij    if (ptr == NULL) {
218296341Sdelphij        DSOerr(DSO_F_DLFCN_UNLOAD, DSO_R_NULL_HANDLE);
219296341Sdelphij        /*
220296341Sdelphij         * Should push the value back onto the stack in case of a retry.
221296341Sdelphij         */
222296341Sdelphij        sk_void_push(dso->meth_data, ptr);
223296341Sdelphij        return (0);
224296341Sdelphij    }
225296341Sdelphij    /* For now I'm not aware of any errors associated with dlclose() */
226296341Sdelphij    dlclose(ptr);
227296341Sdelphij    return (1);
228296341Sdelphij}
22968651Skris
23068651Skrisstatic void *dlfcn_bind_var(DSO *dso, const char *symname)
231296341Sdelphij{
232296341Sdelphij    void *ptr, *sym;
23368651Skris
234296341Sdelphij    if ((dso == NULL) || (symname == NULL)) {
235296341Sdelphij        DSOerr(DSO_F_DLFCN_BIND_VAR, ERR_R_PASSED_NULL_PARAMETER);
236296341Sdelphij        return (NULL);
237296341Sdelphij    }
238296341Sdelphij    if (sk_void_num(dso->meth_data) < 1) {
239296341Sdelphij        DSOerr(DSO_F_DLFCN_BIND_VAR, DSO_R_STACK_ERROR);
240296341Sdelphij        return (NULL);
241296341Sdelphij    }
242296341Sdelphij    ptr = sk_void_value(dso->meth_data, sk_void_num(dso->meth_data) - 1);
243296341Sdelphij    if (ptr == NULL) {
244296341Sdelphij        DSOerr(DSO_F_DLFCN_BIND_VAR, DSO_R_NULL_HANDLE);
245296341Sdelphij        return (NULL);
246296341Sdelphij    }
247296341Sdelphij    sym = dlsym(ptr, symname);
248296341Sdelphij    if (sym == NULL) {
249296341Sdelphij        DSOerr(DSO_F_DLFCN_BIND_VAR, DSO_R_SYM_FAILURE);
250296341Sdelphij        ERR_add_error_data(4, "symname(", symname, "): ", dlerror());
251296341Sdelphij        return (NULL);
252296341Sdelphij    }
253296341Sdelphij    return (sym);
254296341Sdelphij}
25568651Skris
25668651Skrisstatic DSO_FUNC_TYPE dlfcn_bind_func(DSO *dso, const char *symname)
257296341Sdelphij{
258296341Sdelphij    void *ptr;
259296341Sdelphij    union {
260296341Sdelphij        DSO_FUNC_TYPE sym;
261296341Sdelphij        void *dlret;
262296341Sdelphij    } u;
26368651Skris
264296341Sdelphij    if ((dso == NULL) || (symname == NULL)) {
265296341Sdelphij        DSOerr(DSO_F_DLFCN_BIND_FUNC, ERR_R_PASSED_NULL_PARAMETER);
266296341Sdelphij        return (NULL);
267296341Sdelphij    }
268296341Sdelphij    if (sk_void_num(dso->meth_data) < 1) {
269296341Sdelphij        DSOerr(DSO_F_DLFCN_BIND_FUNC, DSO_R_STACK_ERROR);
270296341Sdelphij        return (NULL);
271296341Sdelphij    }
272296341Sdelphij    ptr = sk_void_value(dso->meth_data, sk_void_num(dso->meth_data) - 1);
273296341Sdelphij    if (ptr == NULL) {
274296341Sdelphij        DSOerr(DSO_F_DLFCN_BIND_FUNC, DSO_R_NULL_HANDLE);
275296341Sdelphij        return (NULL);
276296341Sdelphij    }
277296341Sdelphij    u.dlret = dlsym(ptr, symname);
278296341Sdelphij    if (u.dlret == NULL) {
279296341Sdelphij        DSOerr(DSO_F_DLFCN_BIND_FUNC, DSO_R_SYM_FAILURE);
280296341Sdelphij        ERR_add_error_data(4, "symname(", symname, "): ", dlerror());
281296341Sdelphij        return (NULL);
282296341Sdelphij    }
283296341Sdelphij    return u.sym;
284296341Sdelphij}
28568651Skris
286160814Ssimonstatic char *dlfcn_merger(DSO *dso, const char *filespec1,
287296341Sdelphij                          const char *filespec2)
288296341Sdelphij{
289296341Sdelphij    char *merged;
290160814Ssimon
291296341Sdelphij    if (!filespec1 && !filespec2) {
292296341Sdelphij        DSOerr(DSO_F_DLFCN_MERGER, ERR_R_PASSED_NULL_PARAMETER);
293296341Sdelphij        return (NULL);
294296341Sdelphij    }
295296341Sdelphij    /*
296296341Sdelphij     * If the first file specification is a rooted path, it rules. same goes
297296341Sdelphij     * if the second file specification is missing.
298296341Sdelphij     */
299296341Sdelphij    if (!filespec2 || (filespec1 != NULL && filespec1[0] == '/')) {
300296341Sdelphij        merged = OPENSSL_malloc(strlen(filespec1) + 1);
301296341Sdelphij        if (!merged) {
302296341Sdelphij            DSOerr(DSO_F_DLFCN_MERGER, ERR_R_MALLOC_FAILURE);
303296341Sdelphij            return (NULL);
304296341Sdelphij        }
305296341Sdelphij        strcpy(merged, filespec1);
306296341Sdelphij    }
307296341Sdelphij    /*
308296341Sdelphij     * If the first file specification is missing, the second one rules.
309296341Sdelphij     */
310296341Sdelphij    else if (!filespec1) {
311296341Sdelphij        merged = OPENSSL_malloc(strlen(filespec2) + 1);
312296341Sdelphij        if (!merged) {
313296341Sdelphij            DSOerr(DSO_F_DLFCN_MERGER, ERR_R_MALLOC_FAILURE);
314296341Sdelphij            return (NULL);
315296341Sdelphij        }
316296341Sdelphij        strcpy(merged, filespec2);
317296341Sdelphij    } else {
318296341Sdelphij        /*
319296341Sdelphij         * This part isn't as trivial as it looks.  It assumes that the
320296341Sdelphij         * second file specification really is a directory, and makes no
321296341Sdelphij         * checks whatsoever.  Therefore, the result becomes the
322296341Sdelphij         * concatenation of filespec2 followed by a slash followed by
323296341Sdelphij         * filespec1.
324296341Sdelphij         */
325296341Sdelphij        int spec2len, len;
326160814Ssimon
327296341Sdelphij        spec2len = strlen(filespec2);
328296341Sdelphij        len = spec2len + strlen(filespec1);
329160814Ssimon
330296341Sdelphij        if (spec2len && filespec2[spec2len - 1] == '/') {
331296341Sdelphij            spec2len--;
332296341Sdelphij            len--;
333296341Sdelphij        }
334296341Sdelphij        merged = OPENSSL_malloc(len + 2);
335296341Sdelphij        if (!merged) {
336296341Sdelphij            DSOerr(DSO_F_DLFCN_MERGER, ERR_R_MALLOC_FAILURE);
337296341Sdelphij            return (NULL);
338296341Sdelphij        }
339296341Sdelphij        strcpy(merged, filespec2);
340296341Sdelphij        merged[spec2len] = '/';
341296341Sdelphij        strcpy(&merged[spec2len + 1], filespec1);
342296341Sdelphij    }
343296341Sdelphij    return (merged);
344296341Sdelphij}
345160814Ssimon
346296341Sdelphij# ifdef OPENSSL_SYS_MACOSX
347296341Sdelphij#  define DSO_ext ".dylib"
348296341Sdelphij#  define DSO_extlen 6
349296341Sdelphij# else
350296341Sdelphij#  define DSO_ext ".so"
351296341Sdelphij#  define DSO_extlen 3
352296341Sdelphij# endif
353205128Ssimon
354109998Smarkmstatic char *dlfcn_name_converter(DSO *dso, const char *filename)
355296341Sdelphij{
356296341Sdelphij    char *translated;
357296341Sdelphij    int len, rsize, transform;
358109998Smarkm
359296341Sdelphij    len = strlen(filename);
360296341Sdelphij    rsize = len + 1;
361296341Sdelphij    transform = (strstr(filename, "/") == NULL);
362296341Sdelphij    if (transform) {
363296341Sdelphij        /* We will convert this to "%s.so" or "lib%s.so" etc */
364296341Sdelphij        rsize += DSO_extlen;    /* The length of ".so" */
365296341Sdelphij        if ((DSO_flags(dso) & DSO_FLAG_NAME_TRANSLATION_EXT_ONLY) == 0)
366296341Sdelphij            rsize += 3;         /* The length of "lib" */
367296341Sdelphij    }
368296341Sdelphij    translated = OPENSSL_malloc(rsize);
369296341Sdelphij    if (translated == NULL) {
370296341Sdelphij        DSOerr(DSO_F_DLFCN_NAME_CONVERTER, DSO_R_NAME_TRANSLATION_FAILED);
371296341Sdelphij        return (NULL);
372296341Sdelphij    }
373296341Sdelphij    if (transform) {
374296341Sdelphij        if ((DSO_flags(dso) & DSO_FLAG_NAME_TRANSLATION_EXT_ONLY) == 0)
375296341Sdelphij            sprintf(translated, "lib%s" DSO_ext, filename);
376296341Sdelphij        else
377296341Sdelphij            sprintf(translated, "%s" DSO_ext, filename);
378296341Sdelphij    } else
379296341Sdelphij        sprintf(translated, "%s", filename);
380296341Sdelphij    return (translated);
381296341Sdelphij}
38268651Skris
383296341Sdelphij# ifdef __sgi
384296341Sdelphij/*-
385238405SjkimThis is a quote from IRIX manual for dladdr(3c):
386238405Sjkim
387238405Sjkim     <dlfcn.h> does not contain a prototype for dladdr or definition of
388238405Sjkim     Dl_info.  The #include <dlfcn.h>  in the SYNOPSIS line is traditional,
389238405Sjkim     but contains no dladdr prototype and no IRIX library contains an
390238405Sjkim     implementation.  Write your own declaration based on the code below.
391238405Sjkim
392238405Sjkim     The following code is dependent on internal interfaces that are not
393238405Sjkim     part of the IRIX compatibility guarantee; however, there is no future
394238405Sjkim     intention to change this interface, so on a practical level, the code
395238405Sjkim     below is safe to use on IRIX.
396238405Sjkim*/
397296341Sdelphij#  include <rld_interface.h>
398296341Sdelphij#  ifndef _RLD_INTERFACE_DLFCN_H_DLADDR
399296341Sdelphij#   define _RLD_INTERFACE_DLFCN_H_DLADDR
400238405Sjkimtypedef struct Dl_info {
401296341Sdelphij    const char *dli_fname;
402296341Sdelphij    void *dli_fbase;
403296341Sdelphij    const char *dli_sname;
404296341Sdelphij    void *dli_saddr;
405296341Sdelphij    int dli_version;
406296341Sdelphij    int dli_reserved1;
407296341Sdelphij    long dli_reserved[4];
408238405Sjkim} Dl_info;
409296341Sdelphij#  else
410238405Sjkimtypedef struct Dl_info Dl_info;
411296341Sdelphij#  endif
412296341Sdelphij#  define _RLD_DLADDR             14
413238405Sjkim
414238405Sjkimstatic int dladdr(void *address, Dl_info *dl)
415238405Sjkim{
416296341Sdelphij    void *v;
417296341Sdelphij    v = _rld_new_interface(_RLD_DLADDR, address, dl);
418296341Sdelphij    return (int)v;
419238405Sjkim}
420296341Sdelphij# endif                         /* __sgi */
421238405Sjkim
422296341Sdelphijstatic int dlfcn_pathbyaddr(void *addr, char *path, int sz)
423296341Sdelphij{
424296341Sdelphij# ifdef HAVE_DLINFO
425296341Sdelphij    Dl_info dli;
426296341Sdelphij    int len;
427238405Sjkim
428296341Sdelphij    if (addr == NULL) {
429296341Sdelphij        union {
430296341Sdelphij            int (*f) (void *, char *, int);
431296341Sdelphij            void *p;
432296341Sdelphij        } t = {
433296341Sdelphij            dlfcn_pathbyaddr
434296341Sdelphij        };
435296341Sdelphij        addr = t.p;
436296341Sdelphij    }
437238405Sjkim
438296341Sdelphij    if (dladdr(addr, &dli)) {
439296341Sdelphij        len = (int)strlen(dli.dli_fname);
440296341Sdelphij        if (sz <= 0)
441296341Sdelphij            return len + 1;
442296341Sdelphij        if (len >= sz)
443296341Sdelphij            len = sz - 1;
444296341Sdelphij        memcpy(path, dli.dli_fname, len);
445296341Sdelphij        path[len++] = 0;
446296341Sdelphij        return len;
447296341Sdelphij    }
448238405Sjkim
449296341Sdelphij    ERR_add_error_data(2, "dlfcn_pathbyaddr(): ", dlerror());
450296341Sdelphij# endif
451296341Sdelphij    return -1;
452296341Sdelphij}
453238405Sjkim
454238405Sjkimstatic void *dlfcn_globallookup(const char *name)
455296341Sdelphij{
456296341Sdelphij    void *ret = NULL, *handle = dlopen(NULL, RTLD_LAZY);
457238405Sjkim
458296341Sdelphij    if (handle) {
459296341Sdelphij        ret = dlsym(handle, name);
460296341Sdelphij        dlclose(handle);
461296341Sdelphij    }
462296341Sdelphij
463296341Sdelphij    return ret;
464296341Sdelphij}
465296341Sdelphij#endif                          /* DSO_DLFCN */
466