DynamicLoader.cxx 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495
  1. /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
  2. file Copyright.txt or https://cmake.org/licensing#kwsys for details. */
  3. #if defined(_WIN32)
  4. # define NOMINMAX // hide min,max to not conflict with <limits>
  5. #endif
  6. #include "kwsysPrivate.h"
  7. #include KWSYS_HEADER(DynamicLoader.hxx)
  8. #include KWSYS_HEADER(Configure.hxx)
  9. #include KWSYS_HEADER(Encoding.hxx)
  10. // Work-around CMake dependency scanning limitation. This must
  11. // duplicate the above list of headers.
  12. #if 0
  13. # include "Configure.hxx.in"
  14. # include "DynamicLoader.hxx.in"
  15. #endif
  16. // This file actually contains several different implementations:
  17. // * NOOP for environments without dynamic libs
  18. // * HP machines which uses shl_load
  19. // * Mac OS X 10.2.x and earlier which uses NSLinkModule
  20. // * Windows which uses LoadLibrary
  21. // * BeOS / Haiku
  22. // * FreeMiNT for Atari
  23. // * Default implementation for *NIX systems (including Mac OS X 10.3 and
  24. // later) which use dlopen
  25. //
  26. // Each part of the ifdef contains a complete implementation for
  27. // the static methods of DynamicLoader.
  28. #define CHECK_OPEN_FLAGS(var, supported, ret) \
  29. do { \
  30. /* Check for unknown flags. */ \
  31. if ((var & AllOpenFlags) != var) { \
  32. return ret; \
  33. } \
  34. \
  35. /* Check for unsupported flags. */ \
  36. if ((var & (supported)) != var) { \
  37. return ret; \
  38. } \
  39. } while (0)
  40. namespace KWSYS_NAMESPACE {
  41. DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
  42. const std::string& libname)
  43. {
  44. return DynamicLoader::OpenLibrary(libname, 0);
  45. }
  46. }
  47. #if !KWSYS_SUPPORTS_SHARED_LIBS
  48. // Implementation for environments without dynamic libs
  49. # include <string.h> // for strerror()
  50. namespace KWSYS_NAMESPACE {
  51. DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
  52. const std::string& libname, int flags)
  53. {
  54. return 0;
  55. }
  56. int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
  57. {
  58. if (!lib) {
  59. return 0;
  60. }
  61. return 1;
  62. }
  63. DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
  64. DynamicLoader::LibraryHandle lib, const std::string& sym)
  65. {
  66. return 0;
  67. }
  68. const char* DynamicLoader::LastError()
  69. {
  70. return "General error";
  71. }
  72. } // namespace KWSYS_NAMESPACE
  73. #elif defined(__hpux)
  74. // Implementation for HPUX machines
  75. # include <dl.h>
  76. # include <errno.h>
  77. namespace KWSYS_NAMESPACE {
  78. DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
  79. const std::string& libname, int flags)
  80. {
  81. CHECK_OPEN_FLAGS(flags, 0, 0);
  82. return shl_load(libname.c_str(), BIND_DEFERRED | DYNAMIC_PATH, 0L);
  83. }
  84. int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
  85. {
  86. if (!lib) {
  87. return 0;
  88. }
  89. return !shl_unload(lib);
  90. }
  91. DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
  92. DynamicLoader::LibraryHandle lib, const std::string& sym)
  93. {
  94. void* addr;
  95. int status;
  96. /* TYPE_PROCEDURE Look for a function or procedure. (This used to be default)
  97. * TYPE_DATA Look for a symbol in the data segment (for example,
  98. * variables).
  99. * TYPE_UNDEFINED Look for any symbol.
  100. */
  101. status = shl_findsym(&lib, sym.c_str(), TYPE_UNDEFINED, &addr);
  102. void* result = (status < 0) ? (void*)0 : addr;
  103. // Hack to cast pointer-to-data to pointer-to-function.
  104. return *reinterpret_cast<DynamicLoader::SymbolPointer*>(&result);
  105. }
  106. const char* DynamicLoader::LastError()
  107. {
  108. // TODO: Need implementation with errno/strerror
  109. /* If successful, shl_findsym returns an integer (int) value zero. If
  110. * shl_findsym cannot find sym, it returns -1 and sets errno to zero.
  111. * If any other errors occur, shl_findsym returns -1 and sets errno to one
  112. * of these values (defined in <errno.h>):
  113. * ENOEXEC
  114. * A format error was detected in the specified library.
  115. * ENOSYM
  116. * A symbol on which sym depends could not be found.
  117. * EINVAL
  118. * The specified handle is invalid.
  119. */
  120. if (errno == ENOEXEC || errno == ENOSYM || errno == EINVAL) {
  121. return strerror(errno);
  122. }
  123. // else
  124. return 0;
  125. }
  126. } // namespace KWSYS_NAMESPACE
  127. #elif defined(__APPLE__) && (MAC_OS_X_VERSION_MAX_ALLOWED < 1030)
  128. // Implementation for Mac OS X 10.2.x and earlier
  129. # include <mach-o/dyld.h>
  130. # include <string.h> // for strlen
  131. namespace KWSYS_NAMESPACE {
  132. DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
  133. const std::string& libname, int flags)
  134. {
  135. CHECK_OPEN_FLAGS(flags, 0, 0);
  136. NSObjectFileImageReturnCode rc;
  137. NSObjectFileImage image = 0;
  138. rc = NSCreateObjectFileImageFromFile(libname.c_str(), &image);
  139. // rc == NSObjectFileImageInappropriateFile when trying to load a dylib file
  140. if (rc != NSObjectFileImageSuccess) {
  141. return 0;
  142. }
  143. NSModule handle = NSLinkModule(image, libname.c_str(),
  144. NSLINKMODULE_OPTION_BINDNOW |
  145. NSLINKMODULE_OPTION_RETURN_ON_ERROR);
  146. NSDestroyObjectFileImage(image);
  147. return handle;
  148. }
  149. int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
  150. {
  151. // NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED
  152. // With this option the memory for the module is not deallocated
  153. // allowing pointers into the module to still be valid.
  154. // You should use this option instead if your code experience some problems
  155. // reported against Panther 10.3.9 (fixed in Tiger 10.4.2 and up)
  156. bool success = NSUnLinkModule(lib, NSUNLINKMODULE_OPTION_NONE);
  157. return success;
  158. }
  159. DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
  160. DynamicLoader::LibraryHandle lib, const std::string& sym)
  161. {
  162. void* result = 0;
  163. // Need to prepend symbols with '_' on Apple-gcc compilers
  164. std::string rsym = '_' + sym;
  165. NSSymbol symbol = NSLookupSymbolInModule(lib, rsym.c_str());
  166. if (symbol) {
  167. result = NSAddressOfSymbol(symbol);
  168. }
  169. // Hack to cast pointer-to-data to pointer-to-function.
  170. return *reinterpret_cast<DynamicLoader::SymbolPointer*>(&result);
  171. }
  172. const char* DynamicLoader::LastError()
  173. {
  174. return 0;
  175. }
  176. } // namespace KWSYS_NAMESPACE
  177. #elif defined(_WIN32) && !defined(__CYGWIN__)
  178. // Implementation for Windows win32 code but not cygwin
  179. # include <windows.h>
  180. # include <stdio.h>
  181. namespace KWSYS_NAMESPACE {
  182. DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
  183. const std::string& libname, int flags)
  184. {
  185. CHECK_OPEN_FLAGS(flags, SearchBesideLibrary, NULL);
  186. DWORD llFlags = 0;
  187. if (flags & SearchBesideLibrary) {
  188. llFlags |= LOAD_WITH_ALTERED_SEARCH_PATH;
  189. }
  190. return LoadLibraryExW(Encoding::ToWindowsExtendedPath(libname).c_str(), NULL,
  191. llFlags);
  192. }
  193. int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
  194. {
  195. return (int)FreeLibrary(lib);
  196. }
  197. DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
  198. DynamicLoader::LibraryHandle lib, const std::string& sym)
  199. {
  200. // TODO: The calling convention affects the name of the symbol. We
  201. // should have a tool to help get the symbol with the desired
  202. // calling convention. Currently we assume cdecl.
  203. //
  204. // Borland:
  205. // __cdecl = "_func" (default)
  206. // __fastcall = "@_func"
  207. // __stdcall = "func"
  208. //
  209. // Watcom:
  210. // __cdecl = "_func"
  211. // __fastcall = "@_func@X"
  212. // __stdcall = "_func@X"
  213. // __watcall = "func_" (default)
  214. //
  215. // MSVC:
  216. // __cdecl = "func" (default)
  217. // __fastcall = "@_func@X"
  218. // __stdcall = "_func@X"
  219. //
  220. // Note that the "@X" part of the name above is the total size (in
  221. // bytes) of the arguments on the stack.
  222. void* result;
  223. # if defined(__BORLANDC__) || defined(__WATCOMC__)
  224. // Need to prepend symbols with '_'
  225. std::string ssym = '_' + sym;
  226. const char* rsym = ssym.c_str();
  227. # else
  228. const char* rsym = sym.c_str();
  229. # endif
  230. result = (void*)GetProcAddress(lib, rsym);
  231. // Hack to cast pointer-to-data to pointer-to-function.
  232. # ifdef __WATCOMC__
  233. return *(DynamicLoader::SymbolPointer*)(&result);
  234. # else
  235. return *reinterpret_cast<DynamicLoader::SymbolPointer*>(&result);
  236. # endif
  237. }
  238. # define DYNLOAD_ERROR_BUFFER_SIZE 1024
  239. const char* DynamicLoader::LastError()
  240. {
  241. wchar_t lpMsgBuf[DYNLOAD_ERROR_BUFFER_SIZE + 1];
  242. DWORD error = GetLastError();
  243. DWORD length = FormatMessageW(
  244. FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, error,
  245. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  246. lpMsgBuf, DYNLOAD_ERROR_BUFFER_SIZE, NULL);
  247. static char str[DYNLOAD_ERROR_BUFFER_SIZE + 1];
  248. if (length < 1) {
  249. /* FormatMessage failed. Use a default message. */
  250. _snprintf(str, DYNLOAD_ERROR_BUFFER_SIZE,
  251. "DynamicLoader encountered error 0x%X. "
  252. "FormatMessage failed with error 0x%X",
  253. error, GetLastError());
  254. return str;
  255. }
  256. if (!WideCharToMultiByte(CP_UTF8, 0, lpMsgBuf, -1, str,
  257. DYNLOAD_ERROR_BUFFER_SIZE, NULL, NULL)) {
  258. /* WideCharToMultiByte failed. Use a default message. */
  259. _snprintf(str, DYNLOAD_ERROR_BUFFER_SIZE,
  260. "DynamicLoader encountered error 0x%X. "
  261. "WideCharToMultiByte failed with error 0x%X",
  262. error, GetLastError());
  263. }
  264. return str;
  265. }
  266. } // namespace KWSYS_NAMESPACE
  267. #elif defined(__BEOS__)
  268. // Implementation for BeOS / Haiku
  269. # include <string.h> // for strerror()
  270. # include <be/kernel/image.h>
  271. # include <be/support/Errors.h>
  272. namespace KWSYS_NAMESPACE {
  273. static image_id last_dynamic_err = B_OK;
  274. DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
  275. const std::string& libname, int flags)
  276. {
  277. CHECK_OPEN_FLAGS(flags, 0, 0);
  278. // image_id's are integers, errors are negative. Add one just in case we
  279. // get a valid image_id of zero (is that even possible?).
  280. image_id rc = load_add_on(libname.c_str());
  281. if (rc < 0) {
  282. last_dynamic_err = rc;
  283. return 0;
  284. }
  285. return rc + 1;
  286. }
  287. int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
  288. {
  289. if (!lib) {
  290. last_dynamic_err = B_BAD_VALUE;
  291. return 0;
  292. } else {
  293. // The function dlclose() returns 0 on success, and non-zero on error.
  294. status_t rc = unload_add_on(lib - 1);
  295. if (rc != B_OK) {
  296. last_dynamic_err = rc;
  297. return 0;
  298. }
  299. }
  300. return 1;
  301. }
  302. DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
  303. DynamicLoader::LibraryHandle lib, const std::string& sym)
  304. {
  305. // Hack to cast pointer-to-data to pointer-to-function.
  306. union
  307. {
  308. void* pvoid;
  309. DynamicLoader::SymbolPointer psym;
  310. } result;
  311. result.psym = NULL;
  312. if (!lib) {
  313. last_dynamic_err = B_BAD_VALUE;
  314. } else {
  315. // !!! FIXME: BeOS can do function-only lookups...does this ever
  316. // !!! FIXME: actually _want_ a data symbol lookup, or was this union
  317. // !!! FIXME: a leftover of dlsym()? (s/ANY/TEXT for functions only).
  318. status_t rc =
  319. get_image_symbol(lib - 1, sym.c_str(), B_SYMBOL_TYPE_ANY, &result.pvoid);
  320. if (rc != B_OK) {
  321. last_dynamic_err = rc;
  322. result.psym = NULL;
  323. }
  324. }
  325. return result.psym;
  326. }
  327. const char* DynamicLoader::LastError()
  328. {
  329. const char* retval = strerror(last_dynamic_err);
  330. last_dynamic_err = B_OK;
  331. return retval;
  332. }
  333. } // namespace KWSYS_NAMESPACE
  334. #elif defined(__MINT__)
  335. // Implementation for FreeMiNT on Atari
  336. # define _GNU_SOURCE /* for program_invocation_name */
  337. # include <dld.h>
  338. # include <errno.h>
  339. # include <malloc.h>
  340. # include <string.h>
  341. namespace KWSYS_NAMESPACE {
  342. DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
  343. const std::string& libname, int flags)
  344. {
  345. CHECK_OPEN_FLAGS(flags, 0, NULL);
  346. char* name = (char*)calloc(1, libname.size() + 1);
  347. dld_init(program_invocation_name);
  348. strncpy(name, libname.c_str(), libname.size());
  349. dld_link(libname.c_str());
  350. return (void*)name;
  351. }
  352. int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
  353. {
  354. dld_unlink_by_file((char*)lib, 0);
  355. free(lib);
  356. return 0;
  357. }
  358. DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
  359. DynamicLoader::LibraryHandle lib, const std::string& sym)
  360. {
  361. // Hack to cast pointer-to-data to pointer-to-function.
  362. union
  363. {
  364. void* pvoid;
  365. DynamicLoader::SymbolPointer psym;
  366. } result;
  367. result.pvoid = dld_get_symbol(sym.c_str());
  368. return result.psym;
  369. }
  370. const char* DynamicLoader::LastError()
  371. {
  372. return dld_strerror(dld_errno);
  373. }
  374. } // namespace KWSYS_NAMESPACE
  375. #else
  376. // Default implementation for *NIX systems (including Mac OS X 10.3 and
  377. // later) which use dlopen
  378. # include <dlfcn.h>
  379. namespace KWSYS_NAMESPACE {
  380. DynamicLoader::LibraryHandle DynamicLoader::OpenLibrary(
  381. const std::string& libname, int flags)
  382. {
  383. CHECK_OPEN_FLAGS(flags, 0, NULL);
  384. return dlopen(libname.c_str(), RTLD_LAZY);
  385. }
  386. int DynamicLoader::CloseLibrary(DynamicLoader::LibraryHandle lib)
  387. {
  388. if (lib) {
  389. // The function dlclose() returns 0 on success, and non-zero on error.
  390. return !dlclose(lib);
  391. }
  392. // else
  393. return 0;
  394. }
  395. DynamicLoader::SymbolPointer DynamicLoader::GetSymbolAddress(
  396. DynamicLoader::LibraryHandle lib, const std::string& sym)
  397. {
  398. // Hack to cast pointer-to-data to pointer-to-function.
  399. union
  400. {
  401. void* pvoid;
  402. DynamicLoader::SymbolPointer psym;
  403. } result;
  404. result.pvoid = dlsym(lib, sym.c_str());
  405. return result.psym;
  406. }
  407. const char* DynamicLoader::LastError()
  408. {
  409. return dlerror();
  410. }
  411. } // namespace KWSYS_NAMESPACE
  412. #endif