annotate dynload/dynload_unix.c @ 357:d982a00c2177

- PPC64 asm syntax fix, specifying explicitly comparison mode for cmpi (newer toolchains complain, older ones took optional field of instruction which happened to be same value)
author Tassilo Philipp
date Tue, 25 Feb 2020 18:16:13 +0100
parents 2f64957d6a46
children 1d03a3a4220d
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
1 /*
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
2
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
3 Package: dyncall
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
4 Library: dynload
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
5 File: dynload/dynload_unix.c
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
6 Description:
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
7 License:
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
8
281
f5577f6bf97a - file header cleanups for release
Tassilo Philipp
parents: 254
diff changeset
9 Copyright (c) 2007-2018 Daniel Adler <dadler@uni-goettingen.de>,
0
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
10 Tassilo Philipp <tphilipp@potion-studios.com>
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
11
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
12 Permission to use, copy, modify, and distribute this software for any
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
13 purpose with or without fee is hereby granted, provided that the above
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
14 copyright notice and this permission notice appear in all copies.
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
15
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
16 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
17 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
18 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
19 ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
20 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
21 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
22 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
23
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
24 */
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
25
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
26
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
27 /*
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
28
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
29 dynload_unix.c
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
30
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
31 dynload module for .so (unix) and .dylib (mach-o darwin/OS X) files
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
32
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
33 */
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
34
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
35
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
36 #include "dynload.h"
242
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
37 #include "../autovar/autovar_OS.h"
0
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
38
242
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
39 #include <string.h>
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
40
314
b2e4e23d9953 - stop using dlinfo() on glibc platforms but use dl_iterate_phdr() instead, as former's implementation is nothing more than a fancy cast and thus dangerously assuming that every provided handle is valid
Tassilo Philipp
parents: 312
diff changeset
41 #if defined(__GLIBC__)
315
3840e0188520 - allowing lookup of running executable's path by passing NULL to dynload's dlGetLibraryPath()
Tassilo Philipp
parents: 314
diff changeset
42 /* @@@ version check glibc more precisely... dl_iterate_phdr(): glibc ver >= 2.2.4*/
356
2f64957d6a46 - fix to dynload to build with musl libc (latter has dlinfo but not RTLD_SELF, so fallback to dl_iterate_phdr if on ELF targets)
Tassilo Philipp
parents: 320
diff changeset
43 # if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 3)
2f64957d6a46 - fix to dynload to build with musl libc (latter has dlinfo but not RTLD_SELF, so fallback to dl_iterate_phdr if on ELF targets)
Tassilo Philipp
parents: 320
diff changeset
44 # define DL_USE_GLIBC_ITER_PHDR
2f64957d6a46 - fix to dynload to build with musl libc (latter has dlinfo but not RTLD_SELF, so fallback to dl_iterate_phdr if on ELF targets)
Tassilo Philipp
parents: 320
diff changeset
45 # endif
314
b2e4e23d9953 - stop using dlinfo() on glibc platforms but use dl_iterate_phdr() instead, as former's implementation is nothing more than a fancy cast and thus dangerously assuming that every provided handle is valid
Tassilo Philipp
parents: 312
diff changeset
46 /* to access dl_iterate_phdr(), and related w/ glibc */
242
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
47 # define _GNU_SOURCE
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
48 # define __USE_GNU
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
49 #endif
356
2f64957d6a46 - fix to dynload to build with musl libc (latter has dlinfo but not RTLD_SELF, so fallback to dl_iterate_phdr if on ELF targets)
Tassilo Philipp
parents: 320
diff changeset
50
0
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
51 #include <dlfcn.h>
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
52
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
53
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
54 DLLib* dlLoadLibrary(const char* libPath)
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
55 {
232
76ed51a690a6 - todo comment
Tassilo Philipp
parents: 171
diff changeset
56 return (DLLib*)dlopen(libPath, RTLD_NOW|RTLD_GLOBAL); //@@@ should use RTLD_LAZY, maybe?
0
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
57 }
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
58
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
59
242
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
60 void* dlFindSymbol(DLLib* pLib, const char* pSymbolName)
0
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
61 {
242
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
62 return dlsym((void*)pLib, pSymbolName);
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
63 }
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
64
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
65
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
66 void dlFreeLibrary(DLLib* pLib)
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
67 {
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
68 /* Check for NULL for cross-platform consistency. *BSD seems to do that in
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
69 dlclose, Linux does not. POSIX states "if handle does not refer to an open
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
70 object, dlclose() returns a non-zero value", which unfortunately sounds
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
71 like it's not explicitly specified. */
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
72 if(pLib)
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
73 dlclose((void*)pLib);
0
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
74 }
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
75
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
76
253
5cfe4322c500 - improved support for older OS versions for dynloads dlGetLibraryPath
Tassilo Philipp
parents: 248
diff changeset
77
314
b2e4e23d9953 - stop using dlinfo() on glibc platforms but use dl_iterate_phdr() instead, as former's implementation is nothing more than a fancy cast and thus dangerously assuming that every provided handle is valid
Tassilo Philipp
parents: 312
diff changeset
78 /* for dlopen-based dlGetLibraryPath impls below, prefer RTLD_NOLOAD that
b2e4e23d9953 - stop using dlinfo() on glibc platforms but use dl_iterate_phdr() instead, as former's implementation is nothing more than a fancy cast and thus dangerously assuming that every provided handle is valid
Tassilo Philipp
parents: 312
diff changeset
79 * merely checks lib names */
246
06a354b2e120 changes for dynload for macOS and OpenBSD:
Tassilo Philipp
parents: 245
diff changeset
80 #if defined(RTLD_NOLOAD)
314
b2e4e23d9953 - stop using dlinfo() on glibc platforms but use dl_iterate_phdr() instead, as former's implementation is nothing more than a fancy cast and thus dangerously assuming that every provided handle is valid
Tassilo Philipp
parents: 312
diff changeset
81 # define RTLD_LIGHTEST RTLD_LAZY|RTLD_NOLOAD
246
06a354b2e120 changes for dynload for macOS and OpenBSD:
Tassilo Philipp
parents: 245
diff changeset
82 #else
06a354b2e120 changes for dynload for macOS and OpenBSD:
Tassilo Philipp
parents: 245
diff changeset
83 # define RTLD_LIGHTEST RTLD_LAZY
06a354b2e120 changes for dynload for macOS and OpenBSD:
Tassilo Philipp
parents: 245
diff changeset
84 #endif
06a354b2e120 changes for dynload for macOS and OpenBSD:
Tassilo Philipp
parents: 245
diff changeset
85
06a354b2e120 changes for dynload for macOS and OpenBSD:
Tassilo Philipp
parents: 245
diff changeset
86
315
3840e0188520 - allowing lookup of running executable's path by passing NULL to dynload's dlGetLibraryPath()
Tassilo Philipp
parents: 314
diff changeset
87 /* helper copying string if buffer big enough, returning length (without \0) */
3840e0188520 - allowing lookup of running executable's path by passing NULL to dynload's dlGetLibraryPath()
Tassilo Philipp
parents: 314
diff changeset
88 static int dl_strlen_strcpy(char* dst, const char* src, int dstSize)
3840e0188520 - allowing lookup of running executable's path by passing NULL to dynload's dlGetLibraryPath()
Tassilo Philipp
parents: 314
diff changeset
89 {
3840e0188520 - allowing lookup of running executable's path by passing NULL to dynload's dlGetLibraryPath()
Tassilo Philipp
parents: 314
diff changeset
90 int l = strlen(src);
3840e0188520 - allowing lookup of running executable's path by passing NULL to dynload's dlGetLibraryPath()
Tassilo Philipp
parents: 314
diff changeset
91 if(l < dstSize) /* l+'\0' <= bufSize */
3840e0188520 - allowing lookup of running executable's path by passing NULL to dynload's dlGetLibraryPath()
Tassilo Philipp
parents: 314
diff changeset
92 strcpy(dst, src);
3840e0188520 - allowing lookup of running executable's path by passing NULL to dynload's dlGetLibraryPath()
Tassilo Philipp
parents: 314
diff changeset
93 return l;
3840e0188520 - allowing lookup of running executable's path by passing NULL to dynload's dlGetLibraryPath()
Tassilo Philipp
parents: 314
diff changeset
94 }
3840e0188520 - allowing lookup of running executable's path by passing NULL to dynload's dlGetLibraryPath()
Tassilo Philipp
parents: 314
diff changeset
95
314
b2e4e23d9953 - stop using dlinfo() on glibc platforms but use dl_iterate_phdr() instead, as former's implementation is nothing more than a fancy cast and thus dangerously assuming that every provided handle is valid
Tassilo Philipp
parents: 312
diff changeset
96 /* code for dlGetLibraryPath() is platform specific */
b2e4e23d9953 - stop using dlinfo() on glibc platforms but use dl_iterate_phdr() instead, as former's implementation is nothing more than a fancy cast and thus dangerously assuming that every provided handle is valid
Tassilo Philipp
parents: 312
diff changeset
97
b2e4e23d9953 - stop using dlinfo() on glibc platforms but use dl_iterate_phdr() instead, as former's implementation is nothing more than a fancy cast and thus dangerously assuming that every provided handle is valid
Tassilo Philipp
parents: 312
diff changeset
98 /* if dlinfo() exists use it (except on glibc, where it exists since version
b2e4e23d9953 - stop using dlinfo() on glibc platforms but use dl_iterate_phdr() instead, as former's implementation is nothing more than a fancy cast and thus dangerously assuming that every provided handle is valid
Tassilo Philipp
parents: 312
diff changeset
99 * 2.3.3, but its implementation is dangerous, as no checks are done whether
315
3840e0188520 - allowing lookup of running executable's path by passing NULL to dynload's dlGetLibraryPath()
Tassilo Philipp
parents: 314
diff changeset
100 * the handle is valid, thus rendering the returned values useless) check for
356
2f64957d6a46 - fix to dynload to build with musl libc (latter has dlinfo but not RTLD_SELF, so fallback to dl_iterate_phdr if on ELF targets)
Tassilo Philipp
parents: 320
diff changeset
101 * RTLD_DI_LINKMAP and RTLD_SELF, which are #defines used by dlinfo() on most
2f64957d6a46 - fix to dynload to build with musl libc (latter has dlinfo but not RTLD_SELF, so fallback to dl_iterate_phdr if on ELF targets)
Tassilo Philipp
parents: 320
diff changeset
102 * supported targets, or specifically check the OS (e.g. dlinfo() is originally
2f64957d6a46 - fix to dynload to build with musl libc (latter has dlinfo but not RTLD_SELF, so fallback to dl_iterate_phdr if on ELF targets)
Tassilo Philipp
parents: 320
diff changeset
103 * from Solaris) */
2f64957d6a46 - fix to dynload to build with musl libc (latter has dlinfo but not RTLD_SELF, so fallback to dl_iterate_phdr if on ELF targets)
Tassilo Philipp
parents: 320
diff changeset
104 #if ((defined(RTLD_DI_LINKMAP) && defined(RTLD_SELF)) || defined(OS_SunOS)) && !defined(DL_USE_GLIBC_ITER_PHDR)
253
5cfe4322c500 - improved support for older OS versions for dynloads dlGetLibraryPath
Tassilo Philipp
parents: 248
diff changeset
105
5cfe4322c500 - improved support for older OS versions for dynloads dlGetLibraryPath
Tassilo Philipp
parents: 248
diff changeset
106 #include <link.h>
5cfe4322c500 - improved support for older OS versions for dynloads dlGetLibraryPath
Tassilo Philipp
parents: 248
diff changeset
107
5cfe4322c500 - improved support for older OS versions for dynloads dlGetLibraryPath
Tassilo Philipp
parents: 248
diff changeset
108 int dlGetLibraryPath(DLLib* pLib, char* sOut, int bufSize)
5cfe4322c500 - improved support for older OS versions for dynloads dlGetLibraryPath
Tassilo Philipp
parents: 248
diff changeset
109 {
312
18de5758980e - stability fix: avoid sigsegv in dynload's dlGetLibraryPath() in some cases (e.g. wrong handle given or OS specific quirk)
Tassilo Philipp
parents: 281
diff changeset
110 struct link_map* p = NULL;
253
5cfe4322c500 - improved support for older OS versions for dynloads dlGetLibraryPath
Tassilo Philipp
parents: 248
diff changeset
111 int l = -1;
315
3840e0188520 - allowing lookup of running executable's path by passing NULL to dynload's dlGetLibraryPath()
Tassilo Philipp
parents: 314
diff changeset
112 if(dlinfo(pLib ? pLib : RTLD_SELF, RTLD_DI_LINKMAP, &p) == 0)
3840e0188520 - allowing lookup of running executable's path by passing NULL to dynload's dlGetLibraryPath()
Tassilo Philipp
parents: 314
diff changeset
113 l = dl_strlen_strcpy(sOut, p->l_name, bufSize);
3840e0188520 - allowing lookup of running executable's path by passing NULL to dynload's dlGetLibraryPath()
Tassilo Philipp
parents: 314
diff changeset
114
253
5cfe4322c500 - improved support for older OS versions for dynloads dlGetLibraryPath
Tassilo Philipp
parents: 248
diff changeset
115 return l+1; /* strlen + '\0' */
5cfe4322c500 - improved support for older OS versions for dynloads dlGetLibraryPath
Tassilo Philipp
parents: 248
diff changeset
116 }
5cfe4322c500 - improved support for older OS versions for dynloads dlGetLibraryPath
Tassilo Philipp
parents: 248
diff changeset
117
5cfe4322c500 - improved support for older OS versions for dynloads dlGetLibraryPath
Tassilo Philipp
parents: 248
diff changeset
118
5cfe4322c500 - improved support for older OS versions for dynloads dlGetLibraryPath
Tassilo Philipp
parents: 248
diff changeset
119 /* specific implementation needed on Darwin -----> */
5cfe4322c500 - improved support for older OS versions for dynloads dlGetLibraryPath
Tassilo Philipp
parents: 248
diff changeset
120 #elif defined(OS_Darwin)
242
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
121
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
122 #include <stdint.h>
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
123 #include <mach-o/dyld.h>
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
124
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
125 int dlGetLibraryPath(DLLib* pLib, char* sOut, int bufSize)
0
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
126 {
242
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
127 uint32_t i;
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
128 int l = -1;
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
129
315
3840e0188520 - allowing lookup of running executable's path by passing NULL to dynload's dlGetLibraryPath()
Tassilo Philipp
parents: 314
diff changeset
130 /* request info about own process? lookup first loaded image */
3840e0188520 - allowing lookup of running executable's path by passing NULL to dynload's dlGetLibraryPath()
Tassilo Philipp
parents: 314
diff changeset
131 if(pLib == NULL) {
3840e0188520 - allowing lookup of running executable's path by passing NULL to dynload's dlGetLibraryPath()
Tassilo Philipp
parents: 314
diff changeset
132 const char* libPath = _dyld_get_image_name(0); //@@@ consider using _NSGetExecutablePath()
3840e0188520 - allowing lookup of running executable's path by passing NULL to dynload's dlGetLibraryPath()
Tassilo Philipp
parents: 314
diff changeset
133 if(libPath)
3840e0188520 - allowing lookup of running executable's path by passing NULL to dynload's dlGetLibraryPath()
Tassilo Philipp
parents: 314
diff changeset
134 l = dl_strlen_strcpy(sOut, libPath, bufSize);
3840e0188520 - allowing lookup of running executable's path by passing NULL to dynload's dlGetLibraryPath()
Tassilo Philipp
parents: 314
diff changeset
135 }
3840e0188520 - allowing lookup of running executable's path by passing NULL to dynload's dlGetLibraryPath()
Tassilo Philipp
parents: 314
diff changeset
136 else {
3840e0188520 - allowing lookup of running executable's path by passing NULL to dynload's dlGetLibraryPath()
Tassilo Philipp
parents: 314
diff changeset
137 /* Darwin's code doesn't come with (non-standard) dlinfo(), so use dyld(1)
3840e0188520 - allowing lookup of running executable's path by passing NULL to dynload's dlGetLibraryPath()
Tassilo Philipp
parents: 314
diff changeset
138 * code. There doesn't seem to be a direct way to query the library path,
3840e0188520 - allowing lookup of running executable's path by passing NULL to dynload's dlGetLibraryPath()
Tassilo Philipp
parents: 314
diff changeset
139 * so "double-load" temporarily all already loaded images (just increases
3840e0188520 - allowing lookup of running executable's path by passing NULL to dynload's dlGetLibraryPath()
Tassilo Philipp
parents: 314
diff changeset
140 * ref count) and compare handles until we found ours. Return the name. */
3840e0188520 - allowing lookup of running executable's path by passing NULL to dynload's dlGetLibraryPath()
Tassilo Philipp
parents: 314
diff changeset
141 for(i=_dyld_image_count(); i>0;) /* backwards, ours is more likely at end */
3840e0188520 - allowing lookup of running executable's path by passing NULL to dynload's dlGetLibraryPath()
Tassilo Philipp
parents: 314
diff changeset
142 {
3840e0188520 - allowing lookup of running executable's path by passing NULL to dynload's dlGetLibraryPath()
Tassilo Philipp
parents: 314
diff changeset
143 const char* libPath = _dyld_get_image_name(--i);
3840e0188520 - allowing lookup of running executable's path by passing NULL to dynload's dlGetLibraryPath()
Tassilo Philipp
parents: 314
diff changeset
144 void* lib = dlopen(libPath, RTLD_LIGHTEST);
3840e0188520 - allowing lookup of running executable's path by passing NULL to dynload's dlGetLibraryPath()
Tassilo Philipp
parents: 314
diff changeset
145 if(lib) {
3840e0188520 - allowing lookup of running executable's path by passing NULL to dynload's dlGetLibraryPath()
Tassilo Philipp
parents: 314
diff changeset
146 dlclose(lib);
0
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
147
315
3840e0188520 - allowing lookup of running executable's path by passing NULL to dynload's dlGetLibraryPath()
Tassilo Philipp
parents: 314
diff changeset
148 /* compare handle pointers' high bits (in low 2 bits some flags might */
3840e0188520 - allowing lookup of running executable's path by passing NULL to dynload's dlGetLibraryPath()
Tassilo Philipp
parents: 314
diff changeset
149 /* be stored - should be safe b/c address needs alignment, anyways) */
320
85c80b0c021c - Darwin/macos fix for dlGetLibraryPath() to correctly fail on bogus handles
Tassilo Philipp
parents: 317
diff changeset
150 if(((uintptr_t)pLib ^ (uintptr_t)lib) < 4) {
315
3840e0188520 - allowing lookup of running executable's path by passing NULL to dynload's dlGetLibraryPath()
Tassilo Philipp
parents: 314
diff changeset
151 l = dl_strlen_strcpy(sOut, libPath, bufSize);
3840e0188520 - allowing lookup of running executable's path by passing NULL to dynload's dlGetLibraryPath()
Tassilo Philipp
parents: 314
diff changeset
152 break;
3840e0188520 - allowing lookup of running executable's path by passing NULL to dynload's dlGetLibraryPath()
Tassilo Philipp
parents: 314
diff changeset
153 }
242
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
154 }
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
155 }
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
156 }
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
157
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
158 return l+1; /* strlen + '\0' */
0
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
159 }
3e629dc19168 initial from svn dyncall-1745
Daniel Adler
parents:
diff changeset
160
242
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
161
356
2f64957d6a46 - fix to dynload to build with musl libc (latter has dlinfo but not RTLD_SELF, so fallback to dl_iterate_phdr if on ELF targets)
Tassilo Philipp
parents: 320
diff changeset
162 /* - OpenBSD >= 3.7 has dl_iterate_phdr(), as well as glibc >= 2.2.4
2f64957d6a46 - fix to dynload to build with musl libc (latter has dlinfo but not RTLD_SELF, so fallback to dl_iterate_phdr if on ELF targets)
Tassilo Philipp
parents: 320
diff changeset
163 - also some libc impls (like musl) provide dlinfo(), but not RTLD_SELF (see above), however they might come
2f64957d6a46 - fix to dynload to build with musl libc (latter has dlinfo but not RTLD_SELF, so fallback to dl_iterate_phdr if on ELF targets)
Tassilo Philipp
parents: 320
diff changeset
164 with dl_iterate_phdr (which comes from ELF program header iteration), so base it on that
2f64957d6a46 - fix to dynload to build with musl libc (latter has dlinfo but not RTLD_SELF, so fallback to dl_iterate_phdr if on ELF targets)
Tassilo Philipp
parents: 320
diff changeset
165 - skip and use dladdr()-based guessing (see below) if explicitly requested, e.g. by ./configure */
2f64957d6a46 - fix to dynload to build with musl libc (latter has dlinfo but not RTLD_SELF, so fallback to dl_iterate_phdr if on ELF targets)
Tassilo Philipp
parents: 320
diff changeset
166 #elif !defined(DL_DLADDR_TO_LIBPATH) && (defined(OS_OpenBSD) || defined(DL_USE_GLIBC_ITER_PHDR) || (!defined(RTLD_SELF) && defined(__ELF__)))
242
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
167
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
168 #include <sys/types.h>
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
169 #include <link.h>
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
170
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
171 typedef struct {
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
172 DLLib* pLib;
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
173 char* sOut;
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
174 int bufSize;
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
175 } iter_phdr_data;
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
176
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
177 static int iter_phdr_cb(struct dl_phdr_info* info, size_t size, void* data)
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
178 {
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
179 int l = -1;
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
180 iter_phdr_data* d = (iter_phdr_data*)data;
315
3840e0188520 - allowing lookup of running executable's path by passing NULL to dynload's dlGetLibraryPath()
Tassilo Philipp
parents: 314
diff changeset
181 void* lib = NULL;
3840e0188520 - allowing lookup of running executable's path by passing NULL to dynload's dlGetLibraryPath()
Tassilo Philipp
parents: 314
diff changeset
182
3840e0188520 - allowing lookup of running executable's path by passing NULL to dynload's dlGetLibraryPath()
Tassilo Philipp
parents: 314
diff changeset
183 /* get loaded object's handle if not requesting info about process itself */
3840e0188520 - allowing lookup of running executable's path by passing NULL to dynload's dlGetLibraryPath()
Tassilo Philipp
parents: 314
diff changeset
184 if(d->pLib != NULL) {
3840e0188520 - allowing lookup of running executable's path by passing NULL to dynload's dlGetLibraryPath()
Tassilo Philipp
parents: 314
diff changeset
185 /* unable to relate info->dlpi_addr directly to our dlopen handle, let's
3840e0188520 - allowing lookup of running executable's path by passing NULL to dynload's dlGetLibraryPath()
Tassilo Philipp
parents: 314
diff changeset
186 * do what we do on macOS above, re-dlopen the already loaded lib (just
3840e0188520 - allowing lookup of running executable's path by passing NULL to dynload's dlGetLibraryPath()
Tassilo Philipp
parents: 314
diff changeset
187 * increases ref count) and compare handles */
356
2f64957d6a46 - fix to dynload to build with musl libc (latter has dlinfo but not RTLD_SELF, so fallback to dl_iterate_phdr if on ELF targets)
Tassilo Philipp
parents: 320
diff changeset
188 /* @@@ might be b/c it's the reloc addr... see below */
315
3840e0188520 - allowing lookup of running executable's path by passing NULL to dynload's dlGetLibraryPath()
Tassilo Philipp
parents: 314
diff changeset
189 lib = dlopen(info->dlpi_name, RTLD_LIGHTEST);
3840e0188520 - allowing lookup of running executable's path by passing NULL to dynload's dlGetLibraryPath()
Tassilo Philipp
parents: 314
diff changeset
190 if(lib)
3840e0188520 - allowing lookup of running executable's path by passing NULL to dynload's dlGetLibraryPath()
Tassilo Philipp
parents: 314
diff changeset
191 dlclose(lib);
3840e0188520 - allowing lookup of running executable's path by passing NULL to dynload's dlGetLibraryPath()
Tassilo Philipp
parents: 314
diff changeset
192 }
3840e0188520 - allowing lookup of running executable's path by passing NULL to dynload's dlGetLibraryPath()
Tassilo Philipp
parents: 314
diff changeset
193
3840e0188520 - allowing lookup of running executable's path by passing NULL to dynload's dlGetLibraryPath()
Tassilo Philipp
parents: 314
diff changeset
194 /* compare handles and get name if found; if d->pLib == NULL this will
3840e0188520 - allowing lookup of running executable's path by passing NULL to dynload's dlGetLibraryPath()
Tassilo Philipp
parents: 314
diff changeset
195 enter info on first iterated object, which is the process itself */
3840e0188520 - allowing lookup of running executable's path by passing NULL to dynload's dlGetLibraryPath()
Tassilo Philipp
parents: 314
diff changeset
196 if(lib == (void*)d->pLib) {
3840e0188520 - allowing lookup of running executable's path by passing NULL to dynload's dlGetLibraryPath()
Tassilo Philipp
parents: 314
diff changeset
197 l = dl_strlen_strcpy(d->sOut, info->dlpi_name, d->bufSize);
3840e0188520 - allowing lookup of running executable's path by passing NULL to dynload's dlGetLibraryPath()
Tassilo Philipp
parents: 314
diff changeset
198
317
3df50603afa9 - dynload fix to get proc name when elf relocation is in use
Tassilo Philipp
parents: 315
diff changeset
199 /* if dlpi_name is empty, lookup name via dladdr(proc_load_addr, ...) */
3df50603afa9 - dynload fix to get proc name when elf relocation is in use
Tassilo Philipp
parents: 315
diff changeset
200 if(l == 0 && d->pLib == NULL) {
3df50603afa9 - dynload fix to get proc name when elf relocation is in use
Tassilo Philipp
parents: 315
diff changeset
201 /* dlpi_addr is the reloc base (0 if PIE), find real virtual load addr */
3df50603afa9 - dynload fix to get proc name when elf relocation is in use
Tassilo Philipp
parents: 315
diff changeset
202 void* vladdr = (void*)info->dlpi_addr;
3df50603afa9 - dynload fix to get proc name when elf relocation is in use
Tassilo Philipp
parents: 315
diff changeset
203 int i = 0;
3df50603afa9 - dynload fix to get proc name when elf relocation is in use
Tassilo Philipp
parents: 315
diff changeset
204 for(; i < info->dlpi_phnum; ++i) {
3df50603afa9 - dynload fix to get proc name when elf relocation is in use
Tassilo Philipp
parents: 315
diff changeset
205 if(info->dlpi_phdr[i].p_type == PT_LOAD) {
3df50603afa9 - dynload fix to get proc name when elf relocation is in use
Tassilo Philipp
parents: 315
diff changeset
206 vladdr = (void*)(info->dlpi_addr + info->dlpi_phdr[i].p_vaddr);
3df50603afa9 - dynload fix to get proc name when elf relocation is in use
Tassilo Philipp
parents: 315
diff changeset
207 break;
3df50603afa9 - dynload fix to get proc name when elf relocation is in use
Tassilo Philipp
parents: 315
diff changeset
208 }
3df50603afa9 - dynload fix to get proc name when elf relocation is in use
Tassilo Philipp
parents: 315
diff changeset
209 }
3df50603afa9 - dynload fix to get proc name when elf relocation is in use
Tassilo Philipp
parents: 315
diff changeset
210 Dl_info di;
3df50603afa9 - dynload fix to get proc name when elf relocation is in use
Tassilo Philipp
parents: 315
diff changeset
211 if(dladdr(vladdr, &di) != 0)
3df50603afa9 - dynload fix to get proc name when elf relocation is in use
Tassilo Philipp
parents: 315
diff changeset
212 l = dl_strlen_strcpy(d->sOut, di.dli_fname, d->bufSize);
242
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
213 }
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
214 }
315
3840e0188520 - allowing lookup of running executable's path by passing NULL to dynload's dlGetLibraryPath()
Tassilo Philipp
parents: 314
diff changeset
215
242
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
216 return l+1; /* strlen + '\0'; is 0 if lib not found, which continues iter */
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
217 }
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
218
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
219 int dlGetLibraryPath(DLLib* pLib, char* sOut, int bufSize)
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
220 {
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
221 iter_phdr_data d = { pLib, sOut, bufSize };
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
222 return dl_iterate_phdr(iter_phdr_cb, &d);
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
223 }
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
224
248
ab23f9f2934a - BeOS impl for dlGetLibraryPath
Tassilo Philipp
parents: 246
diff changeset
225
314
b2e4e23d9953 - stop using dlinfo() on glibc platforms but use dl_iterate_phdr() instead, as former's implementation is nothing more than a fancy cast and thus dangerously assuming that every provided handle is valid
Tassilo Philipp
parents: 312
diff changeset
226 /* glibc with neither dl_iterate_phdr() nor dlinfo() (latter introduced after former) @@@
b2e4e23d9953 - stop using dlinfo() on glibc platforms but use dl_iterate_phdr() instead, as former's implementation is nothing more than a fancy cast and thus dangerously assuming that every provided handle is valid
Tassilo Philipp
parents: 312
diff changeset
227 #elif defined(__GLIBC__) && !defined(DL_USE_GLIBC_ITER_PHDR)
b2e4e23d9953 - stop using dlinfo() on glibc platforms but use dl_iterate_phdr() instead, as former's implementation is nothing more than a fancy cast and thus dangerously assuming that every provided handle is valid
Tassilo Philipp
parents: 312
diff changeset
228
b2e4e23d9953 - stop using dlinfo() on glibc platforms but use dl_iterate_phdr() instead, as former's implementation is nothing more than a fancy cast and thus dangerously assuming that every provided handle is valid
Tassilo Philipp
parents: 312
diff changeset
229 @@@impl */
b2e4e23d9953 - stop using dlinfo() on glibc platforms but use dl_iterate_phdr() instead, as former's implementation is nothing more than a fancy cast and thus dangerously assuming that every provided handle is valid
Tassilo Philipp
parents: 312
diff changeset
230
253
5cfe4322c500 - improved support for older OS versions for dynloads dlGetLibraryPath
Tassilo Philipp
parents: 248
diff changeset
231 /* fallback to dladdr() hack */
5cfe4322c500 - improved support for older OS versions for dynloads dlGetLibraryPath
Tassilo Philipp
parents: 248
diff changeset
232 #else
248
ab23f9f2934a - BeOS impl for dlGetLibraryPath
Tassilo Philipp
parents: 246
diff changeset
233
314
b2e4e23d9953 - stop using dlinfo() on glibc platforms but use dl_iterate_phdr() instead, as former's implementation is nothing more than a fancy cast and thus dangerously assuming that every provided handle is valid
Tassilo Philipp
parents: 312
diff changeset
234 #warning "Using non-optimal code for dlGetLibraryPath() b/c of platform limitations."
b2e4e23d9953 - stop using dlinfo() on glibc platforms but use dl_iterate_phdr() instead, as former's implementation is nothing more than a fancy cast and thus dangerously assuming that every provided handle is valid
Tassilo Philipp
parents: 312
diff changeset
235
253
5cfe4322c500 - improved support for older OS versions for dynloads dlGetLibraryPath
Tassilo Philipp
parents: 248
diff changeset
236 /* if nothing else is available, fall back to guessing using dladdr() - this */
5cfe4322c500 - improved support for older OS versions for dynloads dlGetLibraryPath
Tassilo Philipp
parents: 248
diff changeset
237 /* might not always work, as it's trying to getit via the _fini() symbol, */
5cfe4322c500 - improved support for older OS versions for dynloads dlGetLibraryPath
Tassilo Philipp
parents: 248
diff changeset
238 /* which is usually defined in ELF files, but not guaranteed */
5cfe4322c500 - improved support for older OS versions for dynloads dlGetLibraryPath
Tassilo Philipp
parents: 248
diff changeset
239
5cfe4322c500 - improved support for older OS versions for dynloads dlGetLibraryPath
Tassilo Philipp
parents: 248
diff changeset
240 /* @@@Note: On some platforms this might be improved, e.g. on BeOS we have */
5cfe4322c500 - improved support for older OS versions for dynloads dlGetLibraryPath
Tassilo Philipp
parents: 248
diff changeset
241 /* lt_dlgetinfo, which requires iterating over ltdl stuff, but was unable */
5cfe4322c500 - improved support for older OS versions for dynloads dlGetLibraryPath
Tassilo Philipp
parents: 248
diff changeset
242 /* to get that to work (would also introduce a link dependency on libltdl) */
248
ab23f9f2934a - BeOS impl for dlGetLibraryPath
Tassilo Philipp
parents: 246
diff changeset
243
ab23f9f2934a - BeOS impl for dlGetLibraryPath
Tassilo Philipp
parents: 246
diff changeset
244 int dlGetLibraryPath(DLLib* pLib, char* sOut, int bufSize)
ab23f9f2934a - BeOS impl for dlGetLibraryPath
Tassilo Philipp
parents: 246
diff changeset
245 {
315
3840e0188520 - allowing lookup of running executable's path by passing NULL to dynload's dlGetLibraryPath()
Tassilo Philipp
parents: 314
diff changeset
246 /*@@@ missing handler for pLib == NULL*/
253
5cfe4322c500 - improved support for older OS versions for dynloads dlGetLibraryPath
Tassilo Philipp
parents: 248
diff changeset
247 /* cross fingers that shared object is standard ELF and look for _fini */
248
ab23f9f2934a - BeOS impl for dlGetLibraryPath
Tassilo Philipp
parents: 246
diff changeset
248 int l = -1;
ab23f9f2934a - BeOS impl for dlGetLibraryPath
Tassilo Philipp
parents: 246
diff changeset
249 void* s = dlsym((void*)pLib, "_fini");
ab23f9f2934a - BeOS impl for dlGetLibraryPath
Tassilo Philipp
parents: 246
diff changeset
250 if(s) {
ab23f9f2934a - BeOS impl for dlGetLibraryPath
Tassilo Philipp
parents: 246
diff changeset
251 Dl_info i;
315
3840e0188520 - allowing lookup of running executable's path by passing NULL to dynload's dlGetLibraryPath()
Tassilo Philipp
parents: 314
diff changeset
252 if(dladdr(s, &i) != 0)
3840e0188520 - allowing lookup of running executable's path by passing NULL to dynload's dlGetLibraryPath()
Tassilo Philipp
parents: 314
diff changeset
253 l = dl_strlen_strcpy(sOut, i.dli_fname, bufSize);
248
ab23f9f2934a - BeOS impl for dlGetLibraryPath
Tassilo Philipp
parents: 246
diff changeset
254 }
ab23f9f2934a - BeOS impl for dlGetLibraryPath
Tassilo Philipp
parents: 246
diff changeset
255 return l+1; /* strlen + '\0' */
ab23f9f2934a - BeOS impl for dlGetLibraryPath
Tassilo Philipp
parents: 246
diff changeset
256 }
ab23f9f2934a - BeOS impl for dlGetLibraryPath
Tassilo Philipp
parents: 246
diff changeset
257
242
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
258 #endif
85b61e8facfe dynload:
Tassilo Philipp
parents: 232
diff changeset
259