| // Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| #include "include/dart_api.h" |
| #include "vm/bootstrap_natives.h" |
| #include "vm/exceptions.h" |
| #include "vm/globals.h" |
| #include "vm/native_entry.h" |
| |
| #if !defined(DART_HOST_OS_LINUX) && !defined(DART_HOST_OS_MACOS) && \ |
| !defined(DART_HOST_OS_ANDROID) && !defined(DART_HOST_OS_FUCHSIA) |
| // TODO(dacoharkes): Implement dynamic libraries for other targets & merge the |
| // implementation with: |
| // - runtime/bin/extensions.h |
| // - runtime/bin/extensions_linux.cc |
| // TODO(dacoharkes): Make the code from bin available in a manner similar to |
| // runtime/vm/dart.h Dart_FileReadCallback. |
| #else |
| #include <dlfcn.h> |
| #endif |
| |
| namespace dart { |
| |
| static void* LoadExtensionLibrary(const char* library_file) { |
| #if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_MACOS) || \ |
| defined(DART_HOST_OS_ANDROID) || defined(DART_HOST_OS_FUCHSIA) |
| void* handle = dlopen(library_file, RTLD_LAZY); |
| if (handle == nullptr) { |
| char* error = dlerror(); |
| const String& msg = String::Handle(String::NewFormatted( |
| "Failed to load dynamic library '%s': %s", library_file, error)); |
| Exceptions::ThrowArgumentError(msg); |
| } |
| |
| return handle; |
| #elif defined(DART_HOST_OS_WINDOWS) |
| SetLastError(0); // Clear any errors. |
| |
| void* ext; |
| |
| if (library_file == nullptr) { |
| ext = GetModuleHandle(nullptr); |
| } else { |
| // Convert to wchar_t string. |
| const int name_len = |
| MultiByteToWideChar(CP_UTF8, 0, library_file, -1, NULL, 0); |
| wchar_t* name = new wchar_t[name_len]; |
| MultiByteToWideChar(CP_UTF8, 0, library_file, -1, name, name_len); |
| |
| ext = LoadLibraryW(name); |
| delete[] name; |
| } |
| |
| if (ext == nullptr) { |
| const int error = GetLastError(); |
| const String& msg = String::Handle(String::NewFormatted( |
| "Failed to load dynamic library '%s': %i", library_file, error)); |
| Exceptions::ThrowArgumentError(msg); |
| } |
| |
| return ext; |
| #else |
| const Array& args = Array::Handle(Array::New(1)); |
| args.SetAt(0, |
| String::Handle(String::New( |
| "The dart:ffi library is not available on this platform."))); |
| Exceptions::ThrowByType(Exceptions::kUnsupported, args); |
| #endif |
| } |
| |
| DEFINE_NATIVE_ENTRY(Ffi_dl_open, 0, 1) { |
| GET_NON_NULL_NATIVE_ARGUMENT(String, lib_path, arguments->NativeArgAt(0)); |
| |
| void* handle = LoadExtensionLibrary(lib_path.ToCString()); |
| |
| return DynamicLibrary::New(handle); |
| } |
| |
| DEFINE_NATIVE_ENTRY(Ffi_dl_processLibrary, 0, 0) { |
| #if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_MACOS) || \ |
| defined(DART_HOST_OS_ANDROID) || defined(DART_HOST_OS_FUCHSIA) |
| return DynamicLibrary::New(RTLD_DEFAULT); |
| #else |
| const Array& args = Array::Handle(Array::New(1)); |
| args.SetAt(0, |
| String::Handle(String::New( |
| "DynamicLibrary.process is not available on this platform."))); |
| Exceptions::ThrowByType(Exceptions::kUnsupported, args); |
| #endif |
| } |
| |
| DEFINE_NATIVE_ENTRY(Ffi_dl_executableLibrary, 0, 0) { |
| return DynamicLibrary::New(LoadExtensionLibrary(nullptr)); |
| } |
| |
| static void* ResolveSymbol(void* handle, const char* symbol) { |
| #if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_MACOS) || \ |
| defined(DART_HOST_OS_ANDROID) || defined(DART_HOST_OS_FUCHSIA) |
| dlerror(); // Clear any errors. |
| void* pointer = dlsym(handle, symbol); |
| char* error = dlerror(); |
| if (error != nullptr) { |
| const String& msg = String::Handle( |
| String::NewFormatted("Failed to lookup symbol (%s)", error)); |
| Exceptions::ThrowArgumentError(msg); |
| } |
| return pointer; |
| #elif defined(DART_HOST_OS_WINDOWS) |
| SetLastError(0); |
| void* pointer = reinterpret_cast<void*>( |
| GetProcAddress(reinterpret_cast<HMODULE>(handle), symbol)); |
| if (pointer == nullptr) { |
| const int error = GetLastError(); |
| const String& msg = String::Handle( |
| String::NewFormatted("Failed to lookup symbol (%i)", error)); |
| Exceptions::ThrowArgumentError(msg); |
| } |
| return pointer; |
| #else |
| const Array& args = Array::Handle(Array::New(1)); |
| args.SetAt(0, |
| String::Handle(String::New( |
| "The dart:ffi library is not available on this platform."))); |
| Exceptions::ThrowByType(Exceptions::kUnsupported, args); |
| #endif |
| } |
| |
| DEFINE_NATIVE_ENTRY(Ffi_dl_lookup, 1, 2) { |
| GET_NATIVE_TYPE_ARGUMENT(type_arg, arguments->NativeTypeArgAt(0)); |
| |
| GET_NON_NULL_NATIVE_ARGUMENT(DynamicLibrary, dlib, arguments->NativeArgAt(0)); |
| GET_NON_NULL_NATIVE_ARGUMENT(String, argSymbolName, |
| arguments->NativeArgAt(1)); |
| |
| void* handle = dlib.GetHandle(); |
| |
| const uword pointer = |
| reinterpret_cast<uword>(ResolveSymbol(handle, argSymbolName.ToCString())); |
| return Pointer::New(type_arg, pointer); |
| } |
| |
| DEFINE_NATIVE_ENTRY(Ffi_dl_getHandle, 0, 1) { |
| GET_NON_NULL_NATIVE_ARGUMENT(DynamicLibrary, dlib, arguments->NativeArgAt(0)); |
| |
| intptr_t handle = reinterpret_cast<intptr_t>(dlib.GetHandle()); |
| return Integer::NewFromUint64(handle); |
| } |
| |
| static bool SymbolExists(void* handle, const char* symbol) { |
| #if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_MACOS) || \ |
| defined(DART_HOST_OS_ANDROID) || defined(DART_HOST_OS_FUCHSIA) |
| dlerror(); // Clear previous error, if any. |
| dlsym(handle, symbol); |
| // Checking whether dlsym returns a nullptr is not enough, as the value of |
| // the symbol could actually be NULL. Check the error condition instead. |
| return dlerror() == nullptr; |
| #elif defined(DART_HOST_OS_WINDOWS) |
| return GetProcAddress(reinterpret_cast<HMODULE>(handle), symbol) != nullptr; |
| #else |
| const Array& args = Array::Handle(Array::New(1)); |
| args.SetAt(0, |
| String::Handle(String::New( |
| "The dart:ffi library is not available on this platform."))); |
| Exceptions::ThrowByType(Exceptions::kUnsupported, args); |
| #endif |
| } |
| |
| DEFINE_NATIVE_ENTRY(Ffi_dl_providesSymbol, 0, 2) { |
| GET_NON_NULL_NATIVE_ARGUMENT(DynamicLibrary, dlib, arguments->NativeArgAt(0)); |
| GET_NON_NULL_NATIVE_ARGUMENT(String, argSymbolName, |
| arguments->NativeArgAt(1)); |
| |
| void* handle = dlib.GetHandle(); |
| return Bool::Get(SymbolExists(handle, argSymbolName.ToCString())).ptr(); |
| } |
| |
| } // namespace dart |