1e1051a39Sopenharmony_ci/*
2e1051a39Sopenharmony_ci * Copyright 2000-2021 The OpenSSL Project Authors. All Rights Reserved.
3e1051a39Sopenharmony_ci *
4e1051a39Sopenharmony_ci * Licensed under the Apache License 2.0 (the "License").  You may not use
5e1051a39Sopenharmony_ci * this file except in compliance with the License.  You can obtain a copy
6e1051a39Sopenharmony_ci * in the file LICENSE in the source distribution or at
7e1051a39Sopenharmony_ci * https://www.openssl.org/source/license.html
8e1051a39Sopenharmony_ci */
9e1051a39Sopenharmony_ci
10e1051a39Sopenharmony_ci/*
11e1051a39Sopenharmony_ci * We need to do this early, because stdio.h includes the header files that
12e1051a39Sopenharmony_ci * handle _GNU_SOURCE and other similar macros.  Defining it later is simply
13e1051a39Sopenharmony_ci * too late, because those headers are protected from re- inclusion.
14e1051a39Sopenharmony_ci */
15e1051a39Sopenharmony_ci#ifndef _GNU_SOURCE
16e1051a39Sopenharmony_ci# define _GNU_SOURCE            /* make sure dladdr is declared */
17e1051a39Sopenharmony_ci#endif
18e1051a39Sopenharmony_ci
19e1051a39Sopenharmony_ci#include "dso_local.h"
20e1051a39Sopenharmony_ci#include "e_os.h"
21e1051a39Sopenharmony_ci
22e1051a39Sopenharmony_ci#ifdef DSO_DLFCN
23e1051a39Sopenharmony_ci
24e1051a39Sopenharmony_ci# ifdef HAVE_DLFCN_H
25e1051a39Sopenharmony_ci#  ifdef __osf__
26e1051a39Sopenharmony_ci#   define __EXTENSIONS__
27e1051a39Sopenharmony_ci#  endif
28e1051a39Sopenharmony_ci#  include <dlfcn.h>
29e1051a39Sopenharmony_ci#  define HAVE_DLINFO 1
30e1051a39Sopenharmony_ci#  if defined(__SCO_VERSION__) || defined(_SCO_ELF) || \
31e1051a39Sopenharmony_ci     (defined(__osf__) && !defined(RTLD_NEXT))     || \
32e1051a39Sopenharmony_ci     (defined(__OpenBSD__) && !defined(RTLD_SELF)) || \
33e1051a39Sopenharmony_ci     defined(__ANDROID__) || defined(__TANDEM)
34e1051a39Sopenharmony_ci#   undef HAVE_DLINFO
35e1051a39Sopenharmony_ci#  endif
36e1051a39Sopenharmony_ci# endif
37e1051a39Sopenharmony_ci
38e1051a39Sopenharmony_ci/* Part of the hack in "dlfcn_load" ... */
39e1051a39Sopenharmony_ci# define DSO_MAX_TRANSLATED_SIZE 256
40e1051a39Sopenharmony_ci
41e1051a39Sopenharmony_cistatic int dlfcn_load(DSO *dso);
42e1051a39Sopenharmony_cistatic int dlfcn_unload(DSO *dso);
43e1051a39Sopenharmony_cistatic DSO_FUNC_TYPE dlfcn_bind_func(DSO *dso, const char *symname);
44e1051a39Sopenharmony_cistatic char *dlfcn_name_converter(DSO *dso, const char *filename);
45e1051a39Sopenharmony_cistatic char *dlfcn_merger(DSO *dso, const char *filespec1,
46e1051a39Sopenharmony_ci                          const char *filespec2);
47e1051a39Sopenharmony_cistatic int dlfcn_pathbyaddr(void *addr, char *path, int sz);
48e1051a39Sopenharmony_cistatic void *dlfcn_globallookup(const char *name);
49e1051a39Sopenharmony_ci
50e1051a39Sopenharmony_cistatic DSO_METHOD dso_meth_dlfcn = {
51e1051a39Sopenharmony_ci    "OpenSSL 'dlfcn' shared library method",
52e1051a39Sopenharmony_ci    dlfcn_load,
53e1051a39Sopenharmony_ci    dlfcn_unload,
54e1051a39Sopenharmony_ci    dlfcn_bind_func,
55e1051a39Sopenharmony_ci    NULL,                       /* ctrl */
56e1051a39Sopenharmony_ci    dlfcn_name_converter,
57e1051a39Sopenharmony_ci    dlfcn_merger,
58e1051a39Sopenharmony_ci    NULL,                       /* init */
59e1051a39Sopenharmony_ci    NULL,                       /* finish */
60e1051a39Sopenharmony_ci    dlfcn_pathbyaddr,
61e1051a39Sopenharmony_ci    dlfcn_globallookup
62e1051a39Sopenharmony_ci};
63e1051a39Sopenharmony_ci
64e1051a39Sopenharmony_ciDSO_METHOD *DSO_METHOD_openssl(void)
65e1051a39Sopenharmony_ci{
66e1051a39Sopenharmony_ci    return &dso_meth_dlfcn;
67e1051a39Sopenharmony_ci}
68e1051a39Sopenharmony_ci
69e1051a39Sopenharmony_ci/*
70e1051a39Sopenharmony_ci * Prior to using the dlopen() function, we should decide on the flag we
71e1051a39Sopenharmony_ci * send. There's a few different ways of doing this and it's a messy
72e1051a39Sopenharmony_ci * venn-diagram to match up which platforms support what. So as we don't have
73e1051a39Sopenharmony_ci * autoconf yet, I'm implementing a hack that could be hacked further
74e1051a39Sopenharmony_ci * relatively easily to deal with cases as we find them. Initially this is to
75e1051a39Sopenharmony_ci * cope with OpenBSD.
76e1051a39Sopenharmony_ci */
77e1051a39Sopenharmony_ci# if defined(__OpenBSD__) || defined(__NetBSD__)
78e1051a39Sopenharmony_ci#  ifdef DL_LAZY
79e1051a39Sopenharmony_ci#   define DLOPEN_FLAG DL_LAZY
80e1051a39Sopenharmony_ci#  else
81e1051a39Sopenharmony_ci#   ifdef RTLD_NOW
82e1051a39Sopenharmony_ci#    define DLOPEN_FLAG RTLD_NOW
83e1051a39Sopenharmony_ci#   else
84e1051a39Sopenharmony_ci#    define DLOPEN_FLAG 0
85e1051a39Sopenharmony_ci#   endif
86e1051a39Sopenharmony_ci#  endif
87e1051a39Sopenharmony_ci# else
88e1051a39Sopenharmony_ci#  define DLOPEN_FLAG RTLD_NOW  /* Hope this works everywhere else */
89e1051a39Sopenharmony_ci# endif
90e1051a39Sopenharmony_ci
91e1051a39Sopenharmony_ci/*
92e1051a39Sopenharmony_ci * For this DSO_METHOD, our meth_data STACK will contain; (i) the handle
93e1051a39Sopenharmony_ci * (void*) returned from dlopen().
94e1051a39Sopenharmony_ci */
95e1051a39Sopenharmony_ci
96e1051a39Sopenharmony_cistatic int dlfcn_load(DSO *dso)
97e1051a39Sopenharmony_ci{
98e1051a39Sopenharmony_ci    void *ptr = NULL;
99e1051a39Sopenharmony_ci    /* See applicable comments in dso_dl.c */
100e1051a39Sopenharmony_ci    char *filename = DSO_convert_filename(dso, NULL);
101e1051a39Sopenharmony_ci    int flags = DLOPEN_FLAG;
102e1051a39Sopenharmony_ci    int saveerrno = get_last_sys_error();
103e1051a39Sopenharmony_ci
104e1051a39Sopenharmony_ci    if (filename == NULL) {
105e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_DSO, DSO_R_NO_FILENAME);
106e1051a39Sopenharmony_ci        goto err;
107e1051a39Sopenharmony_ci    }
108e1051a39Sopenharmony_ci# ifdef RTLD_GLOBAL
109e1051a39Sopenharmony_ci    if (dso->flags & DSO_FLAG_GLOBAL_SYMBOLS)
110e1051a39Sopenharmony_ci        flags |= RTLD_GLOBAL;
111e1051a39Sopenharmony_ci# endif
112e1051a39Sopenharmony_ci# ifdef _AIX
113e1051a39Sopenharmony_ci    if (filename[strlen(filename) - 1] == ')')
114e1051a39Sopenharmony_ci        flags |= RTLD_MEMBER;
115e1051a39Sopenharmony_ci# endif
116e1051a39Sopenharmony_ci    ptr = dlopen(filename, flags);
117e1051a39Sopenharmony_ci    if (ptr == NULL) {
118e1051a39Sopenharmony_ci        ERR_raise_data(ERR_LIB_DSO, DSO_R_LOAD_FAILED,
119e1051a39Sopenharmony_ci                       "filename(%s): %s", filename, dlerror());
120e1051a39Sopenharmony_ci        goto err;
121e1051a39Sopenharmony_ci    }
122e1051a39Sopenharmony_ci    /*
123e1051a39Sopenharmony_ci     * Some dlopen() implementations (e.g. solaris) do no preserve errno, even
124e1051a39Sopenharmony_ci     * on a successful call.
125e1051a39Sopenharmony_ci     */
126e1051a39Sopenharmony_ci    set_sys_error(saveerrno);
127e1051a39Sopenharmony_ci    if (!sk_void_push(dso->meth_data, (char *)ptr)) {
128e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_DSO, DSO_R_STACK_ERROR);
129e1051a39Sopenharmony_ci        goto err;
130e1051a39Sopenharmony_ci    }
131e1051a39Sopenharmony_ci    /* Success */
132e1051a39Sopenharmony_ci    dso->loaded_filename = filename;
133e1051a39Sopenharmony_ci    return 1;
134e1051a39Sopenharmony_ci err:
135e1051a39Sopenharmony_ci    /* Cleanup! */
136e1051a39Sopenharmony_ci    OPENSSL_free(filename);
137e1051a39Sopenharmony_ci    if (ptr != NULL)
138e1051a39Sopenharmony_ci        dlclose(ptr);
139e1051a39Sopenharmony_ci    return 0;
140e1051a39Sopenharmony_ci}
141e1051a39Sopenharmony_ci
142e1051a39Sopenharmony_cistatic int dlfcn_unload(DSO *dso)
143e1051a39Sopenharmony_ci{
144e1051a39Sopenharmony_ci    void *ptr;
145e1051a39Sopenharmony_ci    if (dso == NULL) {
146e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_DSO, ERR_R_PASSED_NULL_PARAMETER);
147e1051a39Sopenharmony_ci        return 0;
148e1051a39Sopenharmony_ci    }
149e1051a39Sopenharmony_ci    if (sk_void_num(dso->meth_data) < 1)
150e1051a39Sopenharmony_ci        return 1;
151e1051a39Sopenharmony_ci    ptr = sk_void_pop(dso->meth_data);
152e1051a39Sopenharmony_ci    if (ptr == NULL) {
153e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_DSO, DSO_R_NULL_HANDLE);
154e1051a39Sopenharmony_ci        /*
155e1051a39Sopenharmony_ci         * Should push the value back onto the stack in case of a retry.
156e1051a39Sopenharmony_ci         */
157e1051a39Sopenharmony_ci        sk_void_push(dso->meth_data, ptr);
158e1051a39Sopenharmony_ci        return 0;
159e1051a39Sopenharmony_ci    }
160e1051a39Sopenharmony_ci    /* For now I'm not aware of any errors associated with dlclose() */
161e1051a39Sopenharmony_ci    dlclose(ptr);
162e1051a39Sopenharmony_ci    return 1;
163e1051a39Sopenharmony_ci}
164e1051a39Sopenharmony_ci
165e1051a39Sopenharmony_cistatic DSO_FUNC_TYPE dlfcn_bind_func(DSO *dso, const char *symname)
166e1051a39Sopenharmony_ci{
167e1051a39Sopenharmony_ci    void *ptr;
168e1051a39Sopenharmony_ci    union {
169e1051a39Sopenharmony_ci        DSO_FUNC_TYPE sym;
170e1051a39Sopenharmony_ci        void *dlret;
171e1051a39Sopenharmony_ci    } u;
172e1051a39Sopenharmony_ci
173e1051a39Sopenharmony_ci    if ((dso == NULL) || (symname == NULL)) {
174e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_DSO, ERR_R_PASSED_NULL_PARAMETER);
175e1051a39Sopenharmony_ci        return NULL;
176e1051a39Sopenharmony_ci    }
177e1051a39Sopenharmony_ci    if (sk_void_num(dso->meth_data) < 1) {
178e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_DSO, DSO_R_STACK_ERROR);
179e1051a39Sopenharmony_ci        return NULL;
180e1051a39Sopenharmony_ci    }
181e1051a39Sopenharmony_ci    ptr = sk_void_value(dso->meth_data, sk_void_num(dso->meth_data) - 1);
182e1051a39Sopenharmony_ci    if (ptr == NULL) {
183e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_DSO, DSO_R_NULL_HANDLE);
184e1051a39Sopenharmony_ci        return NULL;
185e1051a39Sopenharmony_ci    }
186e1051a39Sopenharmony_ci    u.dlret = dlsym(ptr, symname);
187e1051a39Sopenharmony_ci    if (u.dlret == NULL) {
188e1051a39Sopenharmony_ci        ERR_raise_data(ERR_LIB_DSO, DSO_R_SYM_FAILURE,
189e1051a39Sopenharmony_ci                       "symname(%s): %s", symname, dlerror());
190e1051a39Sopenharmony_ci        return NULL;
191e1051a39Sopenharmony_ci    }
192e1051a39Sopenharmony_ci    return u.sym;
193e1051a39Sopenharmony_ci}
194e1051a39Sopenharmony_ci
195e1051a39Sopenharmony_cistatic char *dlfcn_merger(DSO *dso, const char *filespec1,
196e1051a39Sopenharmony_ci                          const char *filespec2)
197e1051a39Sopenharmony_ci{
198e1051a39Sopenharmony_ci    char *merged;
199e1051a39Sopenharmony_ci
200e1051a39Sopenharmony_ci    if (!filespec1 && !filespec2) {
201e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_DSO, ERR_R_PASSED_NULL_PARAMETER);
202e1051a39Sopenharmony_ci        return NULL;
203e1051a39Sopenharmony_ci    }
204e1051a39Sopenharmony_ci    /*
205e1051a39Sopenharmony_ci     * If the first file specification is a rooted path, it rules. same goes
206e1051a39Sopenharmony_ci     * if the second file specification is missing.
207e1051a39Sopenharmony_ci     */
208e1051a39Sopenharmony_ci    if (!filespec2 || (filespec1 != NULL && filespec1[0] == '/')) {
209e1051a39Sopenharmony_ci        merged = OPENSSL_strdup(filespec1);
210e1051a39Sopenharmony_ci        if (merged == NULL) {
211e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_DSO, ERR_R_MALLOC_FAILURE);
212e1051a39Sopenharmony_ci            return NULL;
213e1051a39Sopenharmony_ci        }
214e1051a39Sopenharmony_ci    }
215e1051a39Sopenharmony_ci    /*
216e1051a39Sopenharmony_ci     * If the first file specification is missing, the second one rules.
217e1051a39Sopenharmony_ci     */
218e1051a39Sopenharmony_ci    else if (!filespec1) {
219e1051a39Sopenharmony_ci        merged = OPENSSL_strdup(filespec2);
220e1051a39Sopenharmony_ci        if (merged == NULL) {
221e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_DSO, ERR_R_MALLOC_FAILURE);
222e1051a39Sopenharmony_ci            return NULL;
223e1051a39Sopenharmony_ci        }
224e1051a39Sopenharmony_ci    } else {
225e1051a39Sopenharmony_ci        /*
226e1051a39Sopenharmony_ci         * This part isn't as trivial as it looks.  It assumes that the
227e1051a39Sopenharmony_ci         * second file specification really is a directory, and makes no
228e1051a39Sopenharmony_ci         * checks whatsoever.  Therefore, the result becomes the
229e1051a39Sopenharmony_ci         * concatenation of filespec2 followed by a slash followed by
230e1051a39Sopenharmony_ci         * filespec1.
231e1051a39Sopenharmony_ci         */
232e1051a39Sopenharmony_ci        int spec2len, len;
233e1051a39Sopenharmony_ci
234e1051a39Sopenharmony_ci        spec2len = strlen(filespec2);
235e1051a39Sopenharmony_ci        len = spec2len + strlen(filespec1);
236e1051a39Sopenharmony_ci
237e1051a39Sopenharmony_ci        if (spec2len && filespec2[spec2len - 1] == '/') {
238e1051a39Sopenharmony_ci            spec2len--;
239e1051a39Sopenharmony_ci            len--;
240e1051a39Sopenharmony_ci        }
241e1051a39Sopenharmony_ci        merged = OPENSSL_malloc(len + 2);
242e1051a39Sopenharmony_ci        if (merged == NULL) {
243e1051a39Sopenharmony_ci            ERR_raise(ERR_LIB_DSO, ERR_R_MALLOC_FAILURE);
244e1051a39Sopenharmony_ci            return NULL;
245e1051a39Sopenharmony_ci        }
246e1051a39Sopenharmony_ci        strcpy(merged, filespec2);
247e1051a39Sopenharmony_ci        merged[spec2len] = '/';
248e1051a39Sopenharmony_ci        strcpy(&merged[spec2len + 1], filespec1);
249e1051a39Sopenharmony_ci    }
250e1051a39Sopenharmony_ci    return merged;
251e1051a39Sopenharmony_ci}
252e1051a39Sopenharmony_ci
253e1051a39Sopenharmony_cistatic char *dlfcn_name_converter(DSO *dso, const char *filename)
254e1051a39Sopenharmony_ci{
255e1051a39Sopenharmony_ci    char *translated;
256e1051a39Sopenharmony_ci    int len, rsize, transform;
257e1051a39Sopenharmony_ci
258e1051a39Sopenharmony_ci    len = strlen(filename);
259e1051a39Sopenharmony_ci    rsize = len + 1;
260e1051a39Sopenharmony_ci    transform = (strstr(filename, "/") == NULL);
261e1051a39Sopenharmony_ci    if (transform) {
262e1051a39Sopenharmony_ci        /* We will convert this to "%s.so" or "lib%s.so" etc */
263e1051a39Sopenharmony_ci        rsize += strlen(DSO_EXTENSION);    /* The length of ".so" */
264e1051a39Sopenharmony_ci        if ((DSO_flags(dso) & DSO_FLAG_NAME_TRANSLATION_EXT_ONLY) == 0)
265e1051a39Sopenharmony_ci            rsize += 3;         /* The length of "lib" */
266e1051a39Sopenharmony_ci    }
267e1051a39Sopenharmony_ci    translated = OPENSSL_malloc(rsize);
268e1051a39Sopenharmony_ci    if (translated == NULL) {
269e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_DSO, DSO_R_NAME_TRANSLATION_FAILED);
270e1051a39Sopenharmony_ci        return NULL;
271e1051a39Sopenharmony_ci    }
272e1051a39Sopenharmony_ci    if (transform) {
273e1051a39Sopenharmony_ci        if ((DSO_flags(dso) & DSO_FLAG_NAME_TRANSLATION_EXT_ONLY) == 0)
274e1051a39Sopenharmony_ci            sprintf(translated, "lib%s" DSO_EXTENSION, filename);
275e1051a39Sopenharmony_ci        else
276e1051a39Sopenharmony_ci            sprintf(translated, "%s" DSO_EXTENSION, filename);
277e1051a39Sopenharmony_ci    } else
278e1051a39Sopenharmony_ci        sprintf(translated, "%s", filename);
279e1051a39Sopenharmony_ci    return translated;
280e1051a39Sopenharmony_ci}
281e1051a39Sopenharmony_ci
282e1051a39Sopenharmony_ci# ifdef __sgi
283e1051a39Sopenharmony_ci/*-
284e1051a39Sopenharmony_ciThis is a quote from IRIX manual for dladdr(3c):
285e1051a39Sopenharmony_ci
286e1051a39Sopenharmony_ci     <dlfcn.h> does not contain a prototype for dladdr or definition of
287e1051a39Sopenharmony_ci     Dl_info.  The #include <dlfcn.h>  in the SYNOPSIS line is traditional,
288e1051a39Sopenharmony_ci     but contains no dladdr prototype and no IRIX library contains an
289e1051a39Sopenharmony_ci     implementation.  Write your own declaration based on the code below.
290e1051a39Sopenharmony_ci
291e1051a39Sopenharmony_ci     The following code is dependent on internal interfaces that are not
292e1051a39Sopenharmony_ci     part of the IRIX compatibility guarantee; however, there is no future
293e1051a39Sopenharmony_ci     intention to change this interface, so on a practical level, the code
294e1051a39Sopenharmony_ci     below is safe to use on IRIX.
295e1051a39Sopenharmony_ci*/
296e1051a39Sopenharmony_ci#  include <rld_interface.h>
297e1051a39Sopenharmony_ci#  ifndef _RLD_INTERFACE_DLFCN_H_DLADDR
298e1051a39Sopenharmony_ci#   define _RLD_INTERFACE_DLFCN_H_DLADDR
299e1051a39Sopenharmony_citypedef struct Dl_info {
300e1051a39Sopenharmony_ci    const char *dli_fname;
301e1051a39Sopenharmony_ci    void *dli_fbase;
302e1051a39Sopenharmony_ci    const char *dli_sname;
303e1051a39Sopenharmony_ci    void *dli_saddr;
304e1051a39Sopenharmony_ci    int dli_version;
305e1051a39Sopenharmony_ci    int dli_reserved1;
306e1051a39Sopenharmony_ci    long dli_reserved[4];
307e1051a39Sopenharmony_ci} Dl_info;
308e1051a39Sopenharmony_ci#  else
309e1051a39Sopenharmony_citypedef struct Dl_info Dl_info;
310e1051a39Sopenharmony_ci#  endif
311e1051a39Sopenharmony_ci#  define _RLD_DLADDR             14
312e1051a39Sopenharmony_ci
313e1051a39Sopenharmony_cistatic int dladdr(void *address, Dl_info *dl)
314e1051a39Sopenharmony_ci{
315e1051a39Sopenharmony_ci    void *v;
316e1051a39Sopenharmony_ci    v = _rld_new_interface(_RLD_DLADDR, address, dl);
317e1051a39Sopenharmony_ci    return (int)v;
318e1051a39Sopenharmony_ci}
319e1051a39Sopenharmony_ci# endif                         /* __sgi */
320e1051a39Sopenharmony_ci
321e1051a39Sopenharmony_ci# ifdef _AIX
322e1051a39Sopenharmony_ci/*-
323e1051a39Sopenharmony_ci * See IBM's AIX Version 7.2, Technical Reference:
324e1051a39Sopenharmony_ci *  Base Operating System and Extensions, Volume 1 and 2
325e1051a39Sopenharmony_ci *  https://www.ibm.com/support/knowledgecenter/ssw_aix_72/com.ibm.aix.base/technicalreferences.htm
326e1051a39Sopenharmony_ci */
327e1051a39Sopenharmony_ci#  include <sys/ldr.h>
328e1051a39Sopenharmony_ci#  include <errno.h>
329e1051a39Sopenharmony_ci/* ~ 64 * (sizeof(struct ld_info) + _XOPEN_PATH_MAX + _XOPEN_NAME_MAX) */
330e1051a39Sopenharmony_ci#  define DLFCN_LDINFO_SIZE 86976
331e1051a39Sopenharmony_citypedef struct Dl_info {
332e1051a39Sopenharmony_ci    const char *dli_fname;
333e1051a39Sopenharmony_ci} Dl_info;
334e1051a39Sopenharmony_ci/*
335e1051a39Sopenharmony_ci * This dladdr()-implementation will also find the ptrgl (Pointer Glue) virtual
336e1051a39Sopenharmony_ci * address of a function, which is just located in the DATA segment instead of
337e1051a39Sopenharmony_ci * the TEXT segment.
338e1051a39Sopenharmony_ci */
339e1051a39Sopenharmony_cistatic int dladdr(void *ptr, Dl_info *dl)
340e1051a39Sopenharmony_ci{
341e1051a39Sopenharmony_ci    uintptr_t addr = (uintptr_t)ptr;
342e1051a39Sopenharmony_ci    unsigned int found = 0;
343e1051a39Sopenharmony_ci    struct ld_info *ldinfos, *next_ldi, *this_ldi;
344e1051a39Sopenharmony_ci
345e1051a39Sopenharmony_ci    if ((ldinfos = OPENSSL_malloc(DLFCN_LDINFO_SIZE)) == NULL) {
346e1051a39Sopenharmony_ci        errno = ENOMEM;
347e1051a39Sopenharmony_ci        dl->dli_fname = NULL;
348e1051a39Sopenharmony_ci        return 0;
349e1051a39Sopenharmony_ci    }
350e1051a39Sopenharmony_ci
351e1051a39Sopenharmony_ci    if ((loadquery(L_GETINFO, (void *)ldinfos, DLFCN_LDINFO_SIZE)) < 0) {
352e1051a39Sopenharmony_ci        /*-
353e1051a39Sopenharmony_ci         * Error handling is done through errno and dlerror() reading errno:
354e1051a39Sopenharmony_ci         *  ENOMEM (ldinfos buffer is too small),
355e1051a39Sopenharmony_ci         *  EINVAL (invalid flags),
356e1051a39Sopenharmony_ci         *  EFAULT (invalid ldinfos ptr)
357e1051a39Sopenharmony_ci         */
358e1051a39Sopenharmony_ci        OPENSSL_free((void *)ldinfos);
359e1051a39Sopenharmony_ci        dl->dli_fname = NULL;
360e1051a39Sopenharmony_ci        return 0;
361e1051a39Sopenharmony_ci    }
362e1051a39Sopenharmony_ci    next_ldi = ldinfos;
363e1051a39Sopenharmony_ci
364e1051a39Sopenharmony_ci    do {
365e1051a39Sopenharmony_ci        this_ldi = next_ldi;
366e1051a39Sopenharmony_ci        if (((addr >= (uintptr_t)this_ldi->ldinfo_textorg)
367e1051a39Sopenharmony_ci             && (addr < ((uintptr_t)this_ldi->ldinfo_textorg +
368e1051a39Sopenharmony_ci                         this_ldi->ldinfo_textsize)))
369e1051a39Sopenharmony_ci            || ((addr >= (uintptr_t)this_ldi->ldinfo_dataorg)
370e1051a39Sopenharmony_ci                && (addr < ((uintptr_t)this_ldi->ldinfo_dataorg +
371e1051a39Sopenharmony_ci                            this_ldi->ldinfo_datasize)))) {
372e1051a39Sopenharmony_ci            char *buffer, *member;
373e1051a39Sopenharmony_ci            size_t buffer_sz, member_len;
374e1051a39Sopenharmony_ci
375e1051a39Sopenharmony_ci            buffer_sz = strlen(this_ldi->ldinfo_filename) + 1;
376e1051a39Sopenharmony_ci            member = this_ldi->ldinfo_filename + buffer_sz;
377e1051a39Sopenharmony_ci            if ((member_len = strlen(member)) > 0)
378e1051a39Sopenharmony_ci                buffer_sz += 1 + member_len + 1;
379e1051a39Sopenharmony_ci            found = 1;
380e1051a39Sopenharmony_ci            if ((buffer = OPENSSL_malloc(buffer_sz)) != NULL) {
381e1051a39Sopenharmony_ci                OPENSSL_strlcpy(buffer, this_ldi->ldinfo_filename, buffer_sz);
382e1051a39Sopenharmony_ci                if (member_len > 0) {
383e1051a39Sopenharmony_ci                    /*
384e1051a39Sopenharmony_ci                     * Need to respect a possible member name and not just
385e1051a39Sopenharmony_ci                     * returning the path name in this case. See docs:
386e1051a39Sopenharmony_ci                     * sys/ldr.h, loadquery() and dlopen()/RTLD_MEMBER.
387e1051a39Sopenharmony_ci                     */
388e1051a39Sopenharmony_ci                    OPENSSL_strlcat(buffer, "(", buffer_sz);
389e1051a39Sopenharmony_ci                    OPENSSL_strlcat(buffer, member, buffer_sz);
390e1051a39Sopenharmony_ci                    OPENSSL_strlcat(buffer, ")", buffer_sz);
391e1051a39Sopenharmony_ci                }
392e1051a39Sopenharmony_ci                dl->dli_fname = buffer;
393e1051a39Sopenharmony_ci            } else {
394e1051a39Sopenharmony_ci                errno = ENOMEM;
395e1051a39Sopenharmony_ci            }
396e1051a39Sopenharmony_ci        } else {
397e1051a39Sopenharmony_ci            next_ldi = (struct ld_info *)((uintptr_t)this_ldi +
398e1051a39Sopenharmony_ci                                          this_ldi->ldinfo_next);
399e1051a39Sopenharmony_ci        }
400e1051a39Sopenharmony_ci    } while (this_ldi->ldinfo_next && !found);
401e1051a39Sopenharmony_ci    OPENSSL_free((void *)ldinfos);
402e1051a39Sopenharmony_ci    return (found && dl->dli_fname != NULL);
403e1051a39Sopenharmony_ci}
404e1051a39Sopenharmony_ci# endif                         /* _AIX */
405e1051a39Sopenharmony_ci
406e1051a39Sopenharmony_cistatic int dlfcn_pathbyaddr(void *addr, char *path, int sz)
407e1051a39Sopenharmony_ci{
408e1051a39Sopenharmony_ci# ifdef HAVE_DLINFO
409e1051a39Sopenharmony_ci    Dl_info dli;
410e1051a39Sopenharmony_ci    int len;
411e1051a39Sopenharmony_ci
412e1051a39Sopenharmony_ci    if (addr == NULL) {
413e1051a39Sopenharmony_ci        union {
414e1051a39Sopenharmony_ci            int (*f) (void *, char *, int);
415e1051a39Sopenharmony_ci            void *p;
416e1051a39Sopenharmony_ci        } t = {
417e1051a39Sopenharmony_ci            dlfcn_pathbyaddr
418e1051a39Sopenharmony_ci        };
419e1051a39Sopenharmony_ci        addr = t.p;
420e1051a39Sopenharmony_ci    }
421e1051a39Sopenharmony_ci
422e1051a39Sopenharmony_ci    if (dladdr(addr, &dli)) {
423e1051a39Sopenharmony_ci        len = (int)strlen(dli.dli_fname);
424e1051a39Sopenharmony_ci        if (sz <= 0) {
425e1051a39Sopenharmony_ci#  ifdef _AIX
426e1051a39Sopenharmony_ci            OPENSSL_free((void *)dli.dli_fname);
427e1051a39Sopenharmony_ci#  endif
428e1051a39Sopenharmony_ci            return len + 1;
429e1051a39Sopenharmony_ci        }
430e1051a39Sopenharmony_ci        if (len >= sz)
431e1051a39Sopenharmony_ci            len = sz - 1;
432e1051a39Sopenharmony_ci        memcpy(path, dli.dli_fname, len);
433e1051a39Sopenharmony_ci        path[len++] = 0;
434e1051a39Sopenharmony_ci#  ifdef _AIX
435e1051a39Sopenharmony_ci        OPENSSL_free((void *)dli.dli_fname);
436e1051a39Sopenharmony_ci#  endif
437e1051a39Sopenharmony_ci        return len;
438e1051a39Sopenharmony_ci    }
439e1051a39Sopenharmony_ci
440e1051a39Sopenharmony_ci    ERR_add_error_data(2, "dlfcn_pathbyaddr(): ", dlerror());
441e1051a39Sopenharmony_ci# endif
442e1051a39Sopenharmony_ci    return -1;
443e1051a39Sopenharmony_ci}
444e1051a39Sopenharmony_ci
445e1051a39Sopenharmony_cistatic void *dlfcn_globallookup(const char *name)
446e1051a39Sopenharmony_ci{
447e1051a39Sopenharmony_ci    void *ret = NULL, *handle = dlopen(NULL, RTLD_LAZY);
448e1051a39Sopenharmony_ci
449e1051a39Sopenharmony_ci    if (handle) {
450e1051a39Sopenharmony_ci        ret = dlsym(handle, name);
451e1051a39Sopenharmony_ci        dlclose(handle);
452e1051a39Sopenharmony_ci    }
453e1051a39Sopenharmony_ci
454e1051a39Sopenharmony_ci    return ret;
455e1051a39Sopenharmony_ci}
456e1051a39Sopenharmony_ci#endif                          /* DSO_DLFCN */
457