]>
Commit | Line | Data |
---|---|---|
7c673cae | 1 | // Copyright 2014 Renato Tegon Forti, Antony Polukhin. |
92f5a8d4 | 2 | // Copyright 2015-2019 Antony Polukhin. |
7c673cae FG |
3 | // |
4 | // Distributed under the Boost Software License, Version 1.0. | |
5 | // (See accompanying file LICENSE_1_0.txt | |
6 | // or copy at http://www.boost.org/LICENSE_1_0.txt) | |
7 | ||
8 | #ifndef BOOST_DLL_SHARED_LIBRARY_IMPL_HPP | |
9 | #define BOOST_DLL_SHARED_LIBRARY_IMPL_HPP | |
10 | ||
92f5a8d4 | 11 | #include <boost/dll/config.hpp> |
7c673cae FG |
12 | #include <boost/dll/shared_library_load_mode.hpp> |
13 | #include <boost/dll/detail/posix/path_from_handle.hpp> | |
14 | #include <boost/dll/detail/posix/program_location_impl.hpp> | |
15 | ||
16 | #include <boost/move/utility.hpp> | |
17 | #include <boost/swap.hpp> | |
7c673cae FG |
18 | #include <boost/predef/os.h> |
19 | ||
20 | #include <dlfcn.h> | |
21 | #include <cstring> // strncmp | |
22 | #if !BOOST_OS_MACOS && !BOOST_OS_IOS && !BOOST_OS_QNX | |
23 | # include <link.h> | |
24 | #elif BOOST_OS_QNX | |
25 | // QNX's copy of <elf.h> and <link.h> reside in sys folder | |
26 | # include <sys/link.h> | |
27 | #endif | |
28 | ||
29 | #ifdef BOOST_HAS_PRAGMA_ONCE | |
30 | # pragma once | |
31 | #endif | |
32 | ||
33 | namespace boost { namespace dll { namespace detail { | |
34 | ||
35 | class shared_library_impl { | |
36 | ||
37 | BOOST_MOVABLE_BUT_NOT_COPYABLE(shared_library_impl) | |
38 | ||
39 | public: | |
40 | typedef void* native_handle_t; | |
41 | ||
42 | shared_library_impl() BOOST_NOEXCEPT | |
43 | : handle_(NULL) | |
44 | {} | |
45 | ||
46 | ~shared_library_impl() BOOST_NOEXCEPT { | |
47 | unload(); | |
48 | } | |
92f5a8d4 | 49 | |
7c673cae FG |
50 | shared_library_impl(BOOST_RV_REF(shared_library_impl) sl) BOOST_NOEXCEPT |
51 | : handle_(sl.handle_) | |
52 | { | |
53 | sl.handle_ = NULL; | |
54 | } | |
55 | ||
56 | shared_library_impl & operator=(BOOST_RV_REF(shared_library_impl) sl) BOOST_NOEXCEPT { | |
57 | swap(sl); | |
58 | return *this; | |
59 | } | |
60 | ||
92f5a8d4 TL |
61 | |
62 | static boost::dll::fs::path decorate(const boost::dll::fs::path & sl) { | |
63 | boost::dll::fs::path actual_path = ( | |
64 | std::strncmp(sl.filename().string().c_str(), "lib", 3) | |
65 | ? boost::dll::fs::path((sl.has_parent_path() ? sl.parent_path() / L"lib" : L"lib").native() + sl.filename().native()) | |
66 | : sl | |
67 | ); | |
68 | actual_path += suffix(); | |
69 | return actual_path; | |
70 | } | |
71 | ||
72 | void load(boost::dll::fs::path sl, load_mode::type mode, boost::dll::fs::error_code &ec) { | |
7c673cae FG |
73 | typedef int native_mode_t; |
74 | unload(); | |
75 | ||
76 | // Do not allow opening NULL paths. User must use program_location() instead | |
77 | if (sl.empty()) { | |
78 | boost::dll::detail::reset_dlerror(); | |
92f5a8d4 TL |
79 | ec = boost::dll::fs::make_error_code( |
80 | boost::dll::fs::errc::bad_file_descriptor | |
7c673cae FG |
81 | ); |
82 | ||
83 | return; | |
84 | } | |
85 | ||
86 | // Fixing modes | |
87 | if (!(mode & load_mode::rtld_now)) { | |
88 | mode |= load_mode::rtld_lazy; | |
89 | } | |
90 | ||
91 | if (!(mode & load_mode::rtld_global)) { | |
92 | mode |= load_mode::rtld_local; | |
93 | } | |
94 | ||
95 | #if BOOST_OS_LINUX || BOOST_OS_ANDROID | |
96 | if (!sl.has_parent_path() && !(mode & load_mode::search_system_folders)) { | |
97 | sl = "." / sl; | |
98 | } | |
99 | #else | |
100 | if (!sl.is_absolute() && !(mode & load_mode::search_system_folders)) { | |
92f5a8d4 TL |
101 | boost::dll::fs::error_code current_path_ec; |
102 | boost::dll::fs::path prog_loc = boost::dll::fs::current_path(current_path_ec); | |
7c673cae FG |
103 | if (!current_path_ec) { |
104 | prog_loc /= sl; | |
105 | sl.swap(prog_loc); | |
106 | } | |
107 | } | |
108 | #endif | |
109 | ||
110 | mode &= ~load_mode::search_system_folders; | |
111 | ||
112 | // Trying to open with appended decorations | |
113 | if (!!(mode & load_mode::append_decorations)) { | |
114 | mode &= ~load_mode::append_decorations; | |
115 | ||
92f5a8d4 | 116 | boost::dll::fs::path actual_path = decorate(sl); |
7c673cae FG |
117 | handle_ = dlopen(actual_path.c_str(), static_cast<native_mode_t>(mode)); |
118 | if (handle_) { | |
119 | boost::dll::detail::reset_dlerror(); | |
120 | return; | |
121 | } | |
92f5a8d4 TL |
122 | boost::dll::fs::error_code prog_loc_err; |
123 | boost::dll::fs::path loc = boost::dll::detail::program_location_impl(prog_loc_err); | |
124 | if (boost::dll::fs::exists(actual_path) && !boost::dll::fs::equivalent(sl, loc, prog_loc_err)) { | |
125 | // decorated path exists : current error is not a bad file descriptor and we are not trying to load the executable itself | |
126 | ec = boost::dll::fs::make_error_code( | |
127 | boost::dll::fs::errc::executable_format_error | |
128 | ); | |
129 | return; | |
130 | } | |
7c673cae FG |
131 | } |
132 | ||
133 | // Opening by exactly specified path | |
134 | handle_ = dlopen(sl.c_str(), static_cast<native_mode_t>(mode)); | |
135 | if (handle_) { | |
136 | boost::dll::detail::reset_dlerror(); | |
137 | return; | |
138 | } | |
139 | ||
92f5a8d4 TL |
140 | ec = boost::dll::fs::make_error_code( |
141 | boost::dll::fs::errc::bad_file_descriptor | |
7c673cae FG |
142 | ); |
143 | ||
144 | // Maybe user wanted to load the executable itself? Checking... | |
145 | // We assume that usually user wants to load a dynamic library not the executable itself, that's why | |
146 | // we try this only after traditional load fails. | |
92f5a8d4 TL |
147 | boost::dll::fs::error_code prog_loc_err; |
148 | boost::dll::fs::path loc = boost::dll::detail::program_location_impl(prog_loc_err); | |
149 | if (!prog_loc_err && boost::dll::fs::equivalent(sl, loc, prog_loc_err) && !prog_loc_err) { | |
150 | // As is known the function dlopen() loads the dynamic library file | |
151 | // named by the null-terminated string filename and returns an opaque | |
152 | // "handle" for the dynamic library. If filename is NULL, then the | |
7c673cae FG |
153 | // returned handle is for the main program. |
154 | ec.clear(); | |
155 | boost::dll::detail::reset_dlerror(); | |
156 | handle_ = dlopen(NULL, static_cast<native_mode_t>(mode)); | |
157 | if (!handle_) { | |
92f5a8d4 TL |
158 | ec = boost::dll::fs::make_error_code( |
159 | boost::dll::fs::errc::bad_file_descriptor | |
7c673cae FG |
160 | ); |
161 | } | |
162 | } | |
163 | } | |
164 | ||
165 | bool is_loaded() const BOOST_NOEXCEPT { | |
166 | return (handle_ != 0); | |
167 | } | |
168 | ||
169 | void unload() BOOST_NOEXCEPT { | |
170 | if (!is_loaded()) { | |
171 | return; | |
172 | } | |
173 | ||
174 | dlclose(handle_); | |
175 | handle_ = 0; | |
176 | } | |
177 | ||
178 | void swap(shared_library_impl& rhs) BOOST_NOEXCEPT { | |
179 | boost::swap(handle_, rhs.handle_); | |
180 | } | |
181 | ||
92f5a8d4 | 182 | boost::dll::fs::path full_module_path(boost::dll::fs::error_code &ec) const { |
7c673cae FG |
183 | return boost::dll::detail::path_from_handle(handle_, ec); |
184 | } | |
185 | ||
92f5a8d4 | 186 | static boost::dll::fs::path suffix() { |
7c673cae FG |
187 | // https://sourceforge.net/p/predef/wiki/OperatingSystems/ |
188 | #if BOOST_OS_MACOS || BOOST_OS_IOS | |
189 | return ".dylib"; | |
190 | #else | |
191 | return ".so"; | |
192 | #endif | |
193 | } | |
194 | ||
92f5a8d4 | 195 | void* symbol_addr(const char* sb, boost::dll::fs::error_code &ec) const BOOST_NOEXCEPT { |
7c673cae FG |
196 | // dlsym - obtain the address of a symbol from a dlopen object |
197 | void* const symbol = dlsym(handle_, sb); | |
198 | if (symbol == NULL) { | |
92f5a8d4 TL |
199 | ec = boost::dll::fs::make_error_code( |
200 | boost::dll::fs::errc::invalid_seek | |
7c673cae FG |
201 | ); |
202 | } | |
203 | ||
204 | // If handle does not refer to a valid object opened by dlopen(), | |
205 | // or if the named symbol cannot be found within any of the objects | |
206 | // associated with handle, dlsym() shall return NULL. | |
207 | // More detailed diagnostic information shall be available through dlerror(). | |
208 | ||
209 | return symbol; | |
210 | } | |
211 | ||
212 | native_handle_t native() const BOOST_NOEXCEPT { | |
213 | return handle_; | |
214 | } | |
215 | ||
216 | private: | |
217 | native_handle_t handle_; | |
218 | }; | |
219 | ||
220 | }}} // boost::dll::detail | |
221 | ||
222 | #endif // BOOST_DLL_SHARED_LIBRARY_IMPL_HPP |