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
23namespace dart {
24
25static 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
71DEFINE_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
79DEFINE_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
91DEFINE_NATIVE_ENTRY(Ffi_dl_executableLibrary, 0, 0) {
92 return DynamicLibrary::New(LoadExtensionLibrary(nullptr));
93}
94
95static 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
126DEFINE_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
140DEFINE_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