blob: 38b87b9cda6887e1b0695b17008723cb7e2c6e79 [file] [log] [blame]
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <fidl/fuchsia.ldsvc/cpp/wire.h>
#include <lib/elfldltl/testing/get-test-data.h>
#include <lib/fdio/fd.h>
#include <lib/zx/channel.h>
#include <zircon/dlfcn.h>
#include <zircon/status.h>
#include <zircon/types.h>
#include <cerrno>
#include <gtest/gtest.h>
namespace elfldltl::testing {
// The fdio open doesn't support getting an fd that will allow PROT_EXEC mmap
// usage, i.e. yield a VMO with ZX_RIGHT_EXECUTE. Instead, use the loader
// service to look up the file in /pkg/lib. It is permissible for the VMO to not
// be found, but otherwise gtest assertions are used for all other failures.
// This should only be used inside a gtest Test(...) function.
zx::vmo TryGetTestLibVmo(std::string_view libname) {
constexpr auto init_ldsvc = []() {
// The dl_set_loader_service API replaces the handle used by `dlopen` et al
// and returns the old one, so initialize by borrowing that handle while
// leaving it intact in the system runtime.
zx::unowned_channel channel{dl_set_loader_service(ZX_HANDLE_INVALID)};
EXPECT_TRUE(channel->is_valid());
zx_handle_t reset = dl_set_loader_service(channel->get());
EXPECT_EQ(reset, ZX_HANDLE_INVALID);
return fidl::UnownedClientEnd<fuchsia_ldsvc::Loader>{channel};
};
static const auto ldsvc_endpoint = init_ldsvc();
fidl::Arena arena;
fidl::WireResult result = fidl::WireCall(ldsvc_endpoint)->LoadObject({arena, libname});
// Expect the FIDL call to succeed.
EXPECT_TRUE(result.ok()) << libname << ": " << zx_status_get_string(result.status());
// If the VMO was not found, return an empty object.
if (result->rv == ZX_ERR_NOT_FOUND) {
return zx::vmo(ZX_HANDLE_INVALID);
}
EXPECT_EQ(result->rv, ZX_OK) << libname << ": " << zx_status_get_string(result->rv);
return std::move(result->object);
}
// Note this uses gtest assertions for all failures and so must be used inside
// a gtest TEST(...) function.
zx::vmo GetTestLibVmo(std::string_view libname) {
auto vmo = TryGetTestLibVmo(libname);
EXPECT_TRUE(vmo) << libname << ": not found";
return vmo;
}
// Fuchsia-specific implementation of TryGetTestLib (see get-test-data-path.cc);
// a custom implementation is needed because fdio open does not support
// returning an executable fd.
fbl::unique_fd TryGetTestLib(std::string_view libname) {
fbl::unique_fd fd;
zx::vmo lib_vmo = TryGetTestLibVmo(libname);
// If the VMO is not found, return the default-constructed invalid fd to the
// caller.
if (!lib_vmo) {
return fd;
}
// Create and return a valid FD for the VMO handle.
int fd_out;
zx_status_t status = fdio_fd_create(lib_vmo.release(), &fd_out);
EXPECT_EQ(status, ZX_OK) << libname << ": fdio_fd_create: " << zx_status_get_string(status);
return fbl::unique_fd{fd_out};
}
fbl::unique_fd GetTestLib(std::string_view libname) {
auto fd = TryGetTestLib(libname);
EXPECT_TRUE(fd) << "elfldltl::GetTestLib(\"" << libname << "\"): VMO not found";
return fd;
}
} // namespace elfldltl::testing