blob: b083e04e390830b33065268fcce11d1529fce233 [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.
#if !defined(TARGET_OS_LINUX) && !defined(TARGET_OS_MACOS)
// TODO(dacoharkes): implement dynamic libraries for other targets.
// see
// - runtime/vm/native_symbol.h
// - runtime/vm/native_symbol_linux.cc
// - runtime/bin/extensions.h (but we cannot import from bin)
// - runtime/bin/extensions_linux.cc
#else
#include <dlfcn.h>
#endif
#include "include/dart_api.h"
#include "vm/bootstrap_natives.h"
#include "vm/exceptions.h"
#include "vm/native_entry.h"
namespace dart {
// Concatenates a NULL terminated array of strings.
// The returned string is scope allocated.
// TODO(dacoharkes): Can we share this with runtime/bin/extensions.cc?
const char* Concatenate(const char** strings) {
int size = 1; // null termination.
for (int i = 0; strings[i] != NULL; i++) {
size += strlen(strings[i]);
}
char* result = reinterpret_cast<char*>(Dart_ScopeAllocate(size));
int index = 0;
for (int i = 0; strings[i] != NULL; i++) {
index += snprintf(result + index, size - index, "%s", strings[i]);
}
ASSERT(index == size - 1);
ASSERT(result[size - 1] == '\0');
return result;
}
// TODO(dacoharkes): Can we share this with runtime/bin/extensions.cc?
const char* LibraryPath(const char* library_name) {
const char* library_prefix = "lib";
#if defined(TARGET_OS_LINUX)
const char* library_extension = "so";
#elif defined(TARGET_OS_MACOS)
const char* library_extension = "dylib";
#else
const char* library_extension = "";
UNREACHABLE();
#endif
const char* path_components[] = {
library_prefix, library_name, ".", library_extension, NULL,
};
return Concatenate(path_components);
}
DEFINE_NATIVE_ENTRY(Ffi_dl_open, 0, 1) {
#if !defined(TARGET_OS_LINUX) && !defined(TARGET_OS_MACOS)
UNREACHABLE();
#else
GET_NON_NULL_NATIVE_ARGUMENT(String, argName, arguments->NativeArgAt(0));
dlerror(); // Clear any errors.
void* handle = dlopen(LibraryPath(argName.ToCString()), RTLD_LAZY);
if (handle == nullptr) {
char* error = dlerror();
const String& msg = String::Handle(
String::NewFormatted("Failed to load dynamic library(%s)", error));
Exceptions::ThrowArgumentError(msg);
}
return DynamicLibrary::New(handle);
#endif
}
DEFINE_NATIVE_ENTRY(Ffi_dl_lookup, 1, 2) {
#if !defined(TARGET_OS_LINUX) && !defined(TARGET_OS_MACOS)
UNREACHABLE();
#else
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();
dlerror(); // Clear any errors.
uint8_t* pointer =
reinterpret_cast<uint8_t*>(dlsym(handle, argSymbolName.ToCString()));
char* error;
if ((error = dlerror()) != NULL) {
const String& msg = String::Handle(
String::NewFormatted("Failed to lookup symbol (%s)", error));
Exceptions::ThrowArgumentError(msg);
}
// TODO(dacoharkes): should this return NULL if addres is 0?
// https://github.com/dart-lang/sdk/issues/35756
RawPointer* result = Pointer::New(type_arg, pointer);
return result;
#endif
}
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);
}
} // namespace dart