1 | // Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file |
2 | // for details. All rights reserved. Use of this source code is governed by a |
3 | // BSD-style license that can be found in the LICENSE file. |
4 | |
5 | #include "include/dart_api.h" |
6 | #include "vm/bootstrap_natives.h" |
7 | #include "vm/exceptions.h" |
8 | #include "vm/globals.h" |
9 | #include "vm/native_entry.h" |
10 | |
11 | #if !defined(HOST_OS_LINUX) && !defined(HOST_OS_MACOS) && \ |
12 | !defined(HOST_OS_ANDROID) |
13 | // TODO(dacoharkes): Implement dynamic libraries for other targets & merge the |
14 | // implementation with: |
15 | // - runtime/bin/extensions.h |
16 | // - runtime/bin/extensions_linux.cc |
17 | // TODO(dacoharkes): Make the code from bin available in a manner similar to |
18 | // runtime/vm/dart.h Dart_FileReadCallback. |
19 | #else |
20 | #include <dlfcn.h> |
21 | #endif |
22 | |
23 | namespace dart { |
24 | |
25 | static void* LoadExtensionLibrary(const char* library_file) { |
26 | #if defined(HOST_OS_LINUX) || defined(HOST_OS_MACOS) || defined(HOST_OS_ANDROID) |
27 | void* handle = dlopen(library_file, RTLD_LAZY); |
28 | if (handle == nullptr) { |
29 | char* error = dlerror(); |
30 | const String& msg = String::Handle( |
31 | String::NewFormatted("Failed to load dynamic library (%s)" , error)); |
32 | Exceptions::ThrowArgumentError(msg); |
33 | } |
34 | |
35 | return handle; |
36 | #elif defined(HOST_OS_WINDOWS) |
37 | SetLastError(0); // Clear any errors. |
38 | |
39 | void* ext; |
40 | |
41 | if (library_file == nullptr) { |
42 | ext = GetModuleHandle(nullptr); |
43 | } else { |
44 | // Convert to wchar_t string. |
45 | const int name_len = |
46 | MultiByteToWideChar(CP_UTF8, 0, library_file, -1, NULL, 0); |
47 | wchar_t* name = new wchar_t[name_len]; |
48 | MultiByteToWideChar(CP_UTF8, 0, library_file, -1, name, name_len); |
49 | |
50 | ext = LoadLibraryW(name); |
51 | delete[] name; |
52 | } |
53 | |
54 | if (ext == nullptr) { |
55 | const int error = GetLastError(); |
56 | const String& msg = String::Handle( |
57 | String::NewFormatted("Failed to load dynamic library (%i)" , error)); |
58 | Exceptions::ThrowArgumentError(msg); |
59 | } |
60 | |
61 | return ext; |
62 | #else |
63 | const Array& args = Array::Handle(Array::New(1)); |
64 | args.SetAt(0, |
65 | String::Handle(String::New( |
66 | "The dart:ffi library is not available on this platform." ))); |
67 | Exceptions::ThrowByType(Exceptions::kUnsupported, args); |
68 | #endif |
69 | } |
70 | |
71 | DEFINE_NATIVE_ENTRY(Ffi_dl_open, 0, 1) { |
72 | GET_NON_NULL_NATIVE_ARGUMENT(String, lib_path, arguments->NativeArgAt(0)); |
73 | |
74 | void* handle = LoadExtensionLibrary(lib_path.ToCString()); |
75 | |
76 | return DynamicLibrary::New(handle); |
77 | } |
78 | |
79 | DEFINE_NATIVE_ENTRY(Ffi_dl_processLibrary, 0, 0) { |
80 | #if defined(HOST_OS_LINUX) || defined(HOST_OS_MACOS) || defined(HOST_OS_ANDROID) |
81 | return DynamicLibrary::New(RTLD_DEFAULT); |
82 | #else |
83 | const Array& args = Array::Handle(Array::New(1)); |
84 | args.SetAt(0, |
85 | String::Handle(String::New( |
86 | "DynamicLibrary.process is not available on this platform." ))); |
87 | Exceptions::ThrowByType(Exceptions::kUnsupported, args); |
88 | #endif |
89 | } |
90 | |
91 | DEFINE_NATIVE_ENTRY(Ffi_dl_executableLibrary, 0, 0) { |
92 | return DynamicLibrary::New(LoadExtensionLibrary(nullptr)); |
93 | } |
94 | |
95 | static void* ResolveSymbol(void* handle, const char* symbol) { |
96 | #if defined(HOST_OS_LINUX) || defined(HOST_OS_MACOS) || defined(HOST_OS_ANDROID) |
97 | dlerror(); // Clear any errors. |
98 | void* pointer = dlsym(handle, symbol); |
99 | if (pointer == nullptr) { |
100 | char* error = dlerror(); |
101 | const String& msg = String::Handle( |
102 | String::NewFormatted("Failed to lookup symbol (%s)" , error)); |
103 | Exceptions::ThrowArgumentError(msg); |
104 | } |
105 | return pointer; |
106 | #elif defined(HOST_OS_WINDOWS) |
107 | SetLastError(0); |
108 | void* pointer = reinterpret_cast<void*>( |
109 | GetProcAddress(reinterpret_cast<HMODULE>(handle), symbol)); |
110 | if (pointer == nullptr) { |
111 | const int error = GetLastError(); |
112 | const String& msg = String::Handle( |
113 | String::NewFormatted("Failed to lookup symbol (%i)" , error)); |
114 | Exceptions::ThrowArgumentError(msg); |
115 | } |
116 | return pointer; |
117 | #else |
118 | const Array& args = Array::Handle(Array::New(1)); |
119 | args.SetAt(0, |
120 | String::Handle(String::New( |
121 | "The dart:ffi library is not available on this platform." ))); |
122 | Exceptions::ThrowByType(Exceptions::kUnsupported, args); |
123 | #endif |
124 | } |
125 | |
126 | DEFINE_NATIVE_ENTRY(Ffi_dl_lookup, 1, 2) { |
127 | GET_NATIVE_TYPE_ARGUMENT(type_arg, arguments->NativeTypeArgAt(0)); |
128 | |
129 | GET_NON_NULL_NATIVE_ARGUMENT(DynamicLibrary, dlib, arguments->NativeArgAt(0)); |
130 | GET_NON_NULL_NATIVE_ARGUMENT(String, argSymbolName, |
131 | arguments->NativeArgAt(1)); |
132 | |
133 | void* handle = dlib.GetHandle(); |
134 | |
135 | const uword pointer = |
136 | reinterpret_cast<uword>(ResolveSymbol(handle, argSymbolName.ToCString())); |
137 | return Pointer::New(type_arg, pointer); |
138 | } |
139 | |
140 | DEFINE_NATIVE_ENTRY(Ffi_dl_getHandle, 0, 1) { |
141 | GET_NON_NULL_NATIVE_ARGUMENT(DynamicLibrary, dlib, arguments->NativeArgAt(0)); |
142 | |
143 | intptr_t handle = reinterpret_cast<intptr_t>(dlib.GetHandle()); |
144 | return Integer::NewFromUint64(handle); |
145 | } |
146 | |
147 | } // namespace dart |
148 | |