blob: c082a119cb66a865563eaa34d24b82ad85e35a91 [file] [log] [blame]
/*
*
* Copyright (c) 2021 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include "dlopen_fuchsia.h"
#include <fcntl.h>
#include <fidl/fuchsia.io/cpp/wire.h>
#include <lib/fdio/directory.h>
#include <lib/fdio/io.h>
#include <stdio.h>
#include <string.h>
#include <zircon/dlfcn.h>
#include <zircon/syscalls.h>
#include "loader_service.h"
static char g_error[128] = {};
const char *dlerror_fuchsia(void) { return g_error; }
namespace fio = fuchsia_io;
// Some VMOs may be loaded from directories outside the package which the shared library loader
// doesn't have access to. They can only be loaded by opening the file and using dlopen_vmo.
static void *dlopen_using_vmo(const char *name, int mode) {
int fd;
zx_status_t status =
fdio_open_fd(name, fio::wire::kOpenRightReadable | fio::wire::kOpenRightExecutable, &fd);
if (status != ZX_OK) {
snprintf(g_error, sizeof(g_error), "libopencl.so:dlopen_using_vmo: couldn't open fd, %d\n",
status);
return nullptr;
}
zx::vmo vmo;
status = fdio_get_vmo_exec(fd, vmo.reset_and_get_address());
close(fd);
if (status != ZX_OK) {
snprintf(g_error, sizeof(g_error), "libopencl.so:dlopen_using_vmo: couldn't get vmo exec: %d\n",
status);
return nullptr;
}
void *result = dlopen_vmo(vmo.get(), mode);
if (!result) {
snprintf(g_error, sizeof(g_error), "%s", dlerror());
}
return result;
}
static void *dlopen_from_opencl_loader(const char *name, int mode) {
// Connect to the opencl loader service to request this library.
auto &loader_svc = get_opencl_loader_service();
if (!loader_svc.client_end()) {
snprintf(g_error, sizeof(g_error),
"libopencl.so:dlopen_fuchsia: no connection to loader svc\n");
return nullptr;
}
auto get_result = loader_svc->Get(fidl::StringView::FromExternal(name));
if (!get_result.ok()) {
snprintf(g_error, sizeof(g_error), "libopencl.so:dlopen_fuchsia: Get() failed: %d\n",
get_result.status());
return nullptr;
}
if (!get_result->lib) {
snprintf(g_error, sizeof(g_error), "libopencl.so:dlopen_fuchsia: Get() returned invalid vmo\n");
return nullptr;
}
void *result = dlopen_vmo(get_result->lib.get(), mode);
if (!result) {
snprintf(g_error, sizeof(g_error), "%s", dlerror());
}
return result;
}
void *dlopen_fuchsia(const char *name, int mode, bool driver) {
void *result;
if (!driver) {
result = dlopen(name, mode);
if (result != nullptr) {
return result;
}
return dlopen_using_vmo(name, mode);
} else {
return dlopen_from_opencl_loader(name, mode);
}
}