blob: d0e648341253c7bbda064b152c1d178a8bb1e406 [file] [log] [blame]
// Copyright 2023 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.
#ifndef LIB_LD_TEST_LD_STARTUP_CREATE_PROCESS_TESTS_H_
#define LIB_LD_TEST_LD_STARTUP_CREATE_PROCESS_TESTS_H_
#include <lib/elfldltl/layout.h>
#include <lib/elfldltl/testing/loader.h>
#include <lib/ld/abi.h>
#include <lib/ld/testing/test-processargs.h>
#include <lib/ld/testing/vdso.h>
#include <lib/zx/thread.h>
#include <lib/zx/vmar.h>
#include <lib/zx/vmo.h>
#include <cstdint>
#include <initializer_list>
#include <optional>
#include <string_view>
#include <gtest/gtest.h>
#include "ld-load-zircon-process-tests-base.h"
namespace ld::testing {
// This is the common base class for template instantiations. It handles the
// process mechanics, while the templated subclass does the loading.
class LdStartupCreateProcessTestsBase : public LdLoadZirconProcessTestsBase {
public:
void Init(std::initializer_list<std::string_view> args = {},
std::initializer_list<std::string_view> env = {});
int64_t Run();
~LdStartupCreateProcessTestsBase();
TestProcessArgs& bootstrap() { return procargs_; }
zx::channel& bootstrap_sender() { return procargs_.bootstrap_sender(); }
protected:
const zx::vmar& root_vmar() { return root_vmar_; }
void set_entry(uintptr_t entry) { entry_ = entry; }
void set_vdso_base(uintptr_t vdso_base) { vdso_base_ = vdso_base; }
void set_stack_size(std::optional<size_t> stack_size) { stack_size_ = stack_size; }
void FinishLoad(zx::vmo executable_vmo);
private:
uintptr_t entry_ = 0;
uintptr_t vdso_base_ = 0;
std::optional<size_t> stack_size_;
TestProcessArgs procargs_;
zx::vmar root_vmar_;
zx::thread thread_;
};
template <class Elf = elfldltl::Elf<>>
class LdStartupCreateProcessTests
: public elfldltl::testing::LoadTests<elfldltl::testing::RemoteVmarLoaderTraits, Elf>,
public LdStartupCreateProcessTestsBase {
public:
using LdStartupCreateProcessTestsBase::Run;
void Load(std::string_view executable_name,
std::optional<std::string_view> expected_config = std::nullopt) {
ASSERT_TRUE(root_vmar()); // Init must have been called already.
// This points GetLibVmo() to the right place.
LdsvcPathPrefix(executable_name);
// This will adjust GetLibVmo() to use the libprefix from PT_INTERP so the
// fetch of abi::kInterp will get the right install location.
zx::vmo executable_vmo = GetExecutableVmoWithInterpConfig(executable_name, expected_config);
ASSERT_TRUE(executable_vmo);
// Load the dynamic linker and record its entry point.
std::optional<LoadResult> result;
ASSERT_NO_FATAL_FAILURE(
this->Load(GetInterp(executable_name, expected_config), result, root_vmar()));
set_entry(result->entry + result->loader.load_bias());
set_stack_size(result->stack_size);
// The bootstrap message gets the VMAR where the dynamic linker resides.
zx::vmar self_vmar = std::move(result->loader).Commit(kNoRelro).TakeVmar();
ASSERT_NO_FATAL_FAILURE(bootstrap().AddSelfVmar(std::move(self_vmar)));
// Load the vDSO and record its base address.
// No handles to the VMAR where it was loaded survive.
ASSERT_NO_FATAL_FAILURE(this->Load(*GetVdsoVmo(), result, root_vmar()));
set_vdso_base(result->info.vaddr_start() + result->loader.load_bias());
std::ignore = std::move(result->loader).Commit(kNoRelro);
ASSERT_NO_FATAL_FAILURE(FinishLoad(std::move(executable_vmo)));
}
template <class... Reports>
void LoadAndFail(std::string_view name, Reports&&... reports) {
ASSERT_NO_FATAL_FAILURE(StartupLoadAndFail(*this, name, std::forward<Reports>(reports)...));
}
private:
using Base = elfldltl::testing::LoadTests<elfldltl::testing::RemoteVmarLoaderTraits, Elf>;
using Base::kNoRelro;
using Base::Load;
using typename Base::LoadResult;
};
} // namespace ld::testing
#endif // LIB_LD_TEST_LD_STARTUP_CREATE_PROCESS_TESTS_H_