]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // Copyright 2014-2015 Renato Tegon Forti, Antony Polukhin. |
2 | // | |
3 | // Distributed under the Boost Software License, Version 1.0. | |
4 | // (See accompanying file LICENSE_1_0.txt | |
5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) | |
6 | ||
7 | #ifndef BOOST_DLL_DETAIL_POSIX_PATH_FROM_HANDLE_HPP | |
8 | #define BOOST_DLL_DETAIL_POSIX_PATH_FROM_HANDLE_HPP | |
9 | ||
10 | #include <boost/config.hpp> | |
11 | #include <boost/dll/detail/system_error.hpp> | |
12 | #include <boost/dll/detail/posix/program_location_impl.hpp> | |
13 | #include <boost/filesystem/path.hpp> | |
14 | #include <boost/predef/os.h> | |
15 | ||
16 | #ifdef BOOST_HAS_PRAGMA_ONCE | |
17 | # pragma once | |
18 | #endif | |
19 | ||
20 | #if BOOST_OS_MACOS || BOOST_OS_IOS | |
21 | ||
22 | # include <mach-o/dyld.h> | |
23 | # include <mach-o/nlist.h> | |
24 | # include <cstddef> // for std::ptrdiff_t | |
25 | ||
26 | namespace boost { namespace dll { namespace detail { | |
27 | inline void* strip_handle(void* handle) BOOST_NOEXCEPT { | |
28 | return reinterpret_cast<void*>( | |
29 | (reinterpret_cast<std::ptrdiff_t>(handle) >> 2) << 2 | |
30 | ); | |
31 | } | |
32 | ||
33 | inline boost::filesystem::path path_from_handle(void* handle, boost::system::error_code &ec) { | |
34 | handle = strip_handle(handle); | |
35 | ||
36 | // Iterate through all images currently in memory | |
37 | // https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man3/dyld.3.html | |
38 | const std::size_t count = _dyld_image_count(); // not thread safe: other thread my [un]load images | |
39 | for (std::size_t i = 0; i <= count; ++i) { | |
40 | // on last iteration `i` is equal to `count` which is out of range, so `_dyld_get_image_name` | |
41 | // will return NULL. `dlopen(NULL, RTLD_LAZY)` call will open the current executable. | |
42 | const char* image_name = _dyld_get_image_name(i); | |
43 | ||
44 | // dlopen/dlclose must not affect `_dyld_image_count()`, because libraries are already loaded and only the internal counter is affected | |
45 | void* probe_handle = dlopen(image_name, RTLD_LAZY); | |
46 | dlclose(probe_handle); | |
47 | ||
48 | // If the handle is the same as what was passed in (modulo mode bits), return this image name | |
49 | if (handle == strip_handle(probe_handle)) { | |
50 | boost::dll::detail::reset_dlerror(); | |
51 | return image_name; | |
52 | } | |
53 | } | |
54 | ||
55 | boost::dll::detail::reset_dlerror(); | |
56 | ec = boost::system::error_code( | |
57 | boost::system::errc::bad_file_descriptor, | |
58 | boost::system::generic_category() | |
59 | ); | |
60 | ||
61 | return boost::filesystem::path(); | |
62 | } | |
63 | ||
64 | }}} // namespace boost::dll::detail | |
65 | ||
66 | #elif BOOST_OS_ANDROID | |
67 | ||
68 | #include <boost/dll/runtime_symbol_info.hpp> | |
69 | ||
70 | namespace boost { namespace dll { namespace detail { | |
71 | ||
72 | struct soinfo { | |
73 | // if defined(__work_around_b_24465209__), then an array of char[128] goes here. | |
74 | // Unfortunately, __work_around_b_24465209__ is visible only during compilation of Android's linker | |
75 | const void* phdr; | |
76 | size_t phnum; | |
77 | void* entry; | |
78 | void* base; | |
79 | // ... // Ignoring remaning parts of the structure | |
80 | }; | |
81 | ||
82 | inline boost::filesystem::path path_from_handle(const void* handle, boost::system::error_code &ec) { | |
83 | static const std::size_t work_around_b_24465209__offset = 128; | |
84 | const struct soinfo* si = reinterpret_cast<const struct soinfo*>( | |
85 | static_cast<const char*>(handle) + work_around_b_24465209__offset | |
86 | ); | |
87 | boost::filesystem::path ret = boost::dll::detail::symbol_location_impl(si->base, ec); | |
88 | ||
89 | if (ec) { | |
90 | ec.clear(); | |
91 | si = static_cast<const struct soinfo*>(handle); | |
92 | return boost::dll::detail::symbol_location_impl(si->base, ec); | |
93 | } | |
94 | ||
95 | return ret; | |
96 | } | |
97 | ||
98 | }}} // namespace boost::dll::detail | |
99 | ||
100 | #else // #if BOOST_OS_MACOS || BOOST_OS_IOS || BOOST_OS_ANDROID | |
101 | ||
102 | // for dlinfo | |
103 | #include <dlfcn.h> | |
104 | ||
105 | #if BOOST_OS_QNX | |
106 | // QNX's copy of <elf.h> and <link.h> reside in sys folder | |
107 | # include <sys/link.h> | |
108 | #else | |
109 | # include <link.h> // struct link_map | |
110 | #endif | |
111 | ||
112 | namespace boost { namespace dll { namespace detail { | |
113 | ||
114 | #if BOOST_OS_QNX | |
115 | // Android and QNX miss struct link_map. QNX misses ElfW macro, so avoiding it. | |
116 | struct link_map { | |
117 | void *l_addr; // Base address shared object is loaded at | |
118 | char *l_name; // Absolute file name object was found in | |
119 | // ... // Ignoring remaning parts of the structure | |
120 | }; | |
121 | #endif // #if BOOST_OS_QNX | |
122 | ||
123 | inline boost::filesystem::path path_from_handle(void* handle, boost::system::error_code &ec) { | |
124 | // RTLD_DI_LINKMAP (RTLD_DI_ORIGIN returns only folder and is not suitable for this case) | |
125 | // Obtain the Link_map for the handle that is specified. | |
126 | // The p argument points to a Link_map pointer (Link_map | |
127 | // **p). The actual storage for the Link_map structure is | |
128 | // maintained by ld.so.1. | |
129 | // | |
130 | // Unfortunately we can not use `dlinfo(handle, RTLD_DI_LINKMAP, &link_map) < 0` | |
131 | // because it is not supported on MacOS X 10.3, NetBSD 3.0, OpenBSD 3.8, AIX 5.1, | |
132 | // HP-UX 11, IRIX 6.5, OSF/1 5.1, Cygwin, mingw, Interix 3.5, BeOS. | |
133 | // Fortunately investigating the sources of open source projects brought the understanding, that | |
134 | // `handle` is just a `struct link_map*` that contains full library name. | |
135 | ||
136 | const struct link_map* link_map = 0; | |
137 | #if BOOST_OS_BSD_FREE | |
138 | // FreeBSD has it's own logic http://code.metager.de/source/xref/freebsd/libexec/rtld-elf/rtld.c | |
139 | // Fortunately it has the dlinfo call. | |
140 | if (dlinfo(handle, RTLD_DI_LINKMAP, &link_map) < 0) { | |
141 | link_map = 0; | |
142 | } | |
143 | #else | |
144 | link_map = static_cast<const struct link_map*>(handle); | |
145 | #endif | |
146 | if (!link_map) { | |
147 | boost::dll::detail::reset_dlerror(); | |
148 | ec = boost::system::error_code( | |
149 | boost::system::errc::bad_file_descriptor, | |
150 | boost::system::generic_category() | |
151 | ); | |
152 | ||
153 | return boost::filesystem::path(); | |
154 | } | |
155 | ||
156 | if (!link_map->l_name || *link_map->l_name == '\0') { | |
157 | return program_location_impl(ec); | |
158 | } | |
159 | ||
160 | return boost::filesystem::path(link_map->l_name); | |
161 | } | |
162 | ||
163 | }}} // namespace boost::dll::detail | |
164 | ||
165 | #endif // #if BOOST_OS_MACOS || BOOST_OS_IOS | |
166 | ||
167 | #endif // BOOST_DLL_DETAIL_POSIX_PATH_FROM_HANDLE_HPP | |
168 | ||
169 |