blob: b2f8c3749ffc0ea4cafc7159da5b9028d76e387e [file] [log] [blame]
// 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