blob: 0801c866d615f8f834e58f32dc55f29072edb9af [file] [log] [blame] [edit]
// 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.
#include "ld-load-zircon-process-tests-base.h"
#include <lib/elfldltl/machine.h>
#include <gtest/gtest.h>
namespace ld::testing {
const char* LdLoadZirconProcessTestsBase::process_name() const {
return ::testing::UnitTest::GetInstance()->current_test_info()->name();
}
void LdLoadZirconProcessTestsBase::set_process(zx::process process) {
ASSERT_FALSE(process_);
process_ = std::move(process);
}
int64_t LdLoadZirconProcessTestsBase::Wait() {
int64_t result = -1;
auto wait_for_termination = [this, &result]() {
zx_signals_t signals;
ASSERT_EQ(process_.wait_one(ZX_PROCESS_TERMINATED, zx::time::infinite(), &signals), ZX_OK);
ASSERT_TRUE(signals & ZX_PROCESS_TERMINATED);
zx_info_process_t info;
ASSERT_EQ(process_.get_info(ZX_INFO_PROCESS, &info, sizeof(info), nullptr, nullptr), ZX_OK);
ASSERT_TRUE(info.flags & ZX_INFO_PROCESS_FLAG_STARTED);
ASSERT_TRUE(info.flags & ZX_INFO_PROCESS_FLAG_EXITED);
result = info.return_code;
};
wait_for_termination();
return result;
}
int64_t LdLoadZirconProcessTestsBase::Run(TestProcessArgs* bootstrap,
std::optional<size_t> stack_size,
const zx::thread& thread, uintptr_t entry,
uintptr_t vdso_base, const zx::vmar& root_vmar) {
// Allocate the stack. This is delayed until here in case the test uses
// bootstrap() methods after Init() that affect bootstrap().GetStackSize().
zx::vmo stack_vmo;
uintptr_t sp;
auto allocate_stack = [&]() {
size_t bootstrap_stack_size;
if (!bootstrap) {
ASSERT_TRUE(stack_size);
bootstrap_stack_size = *stack_size;
} else {
// TODO(mcgrathr): stack use too big for procargs piddly default
// bootstrap_stack_size = bootstrap.GetStackSize();
bootstrap_stack_size = 64 << 10;
}
const size_t page_size = zx_system_get_page_size();
const size_t stack_vmo_size = (bootstrap_stack_size + page_size - 1) & -page_size;
const size_t stack_vmar_size = stack_vmo_size + page_size;
ASSERT_EQ(zx::vmo::create(stack_vmo_size, 0, &stack_vmo), ZX_OK);
zx::vmar stack_vmar;
uintptr_t stack_vmar_base;
ASSERT_EQ(root_vmar.allocate(ZX_VM_CAN_MAP_SPECIFIC | ZX_VM_CAN_MAP_READ | ZX_VM_CAN_MAP_WRITE,
0, stack_vmar_size, &stack_vmar, &stack_vmar_base),
ZX_OK);
zx_vaddr_t stack_base;
ASSERT_EQ(
stack_vmar.map(ZX_VM_PERM_READ | ZX_VM_PERM_WRITE | ZX_VM_SPECIFIC | ZX_VM_ALLOW_FAULTS,
page_size, stack_vmo, 0, stack_vmo_size, &stack_base),
ZX_OK);
if (bootstrap) {
ASSERT_NO_FATAL_FAILURE(bootstrap->AddStackVmo(std::move(stack_vmo)));
}
sp = elfldltl::AbiTraits<>::InitialStackPointer(stack_base, stack_vmo_size);
};
allocate_stack();
if (::testing::Test::HasFailure()) {
return -1;
}
// Pack up the bootstrap message and start the process running.
auto start_process = [&]() {
zx::channel bootstrap_receiver =
bootstrap ? bootstrap->PackBootstrap() : zx::channel(ZX_HANDLE_INVALID);
ASSERT_EQ(this->process().start(thread, entry, sp, std::move(bootstrap_receiver), vdso_base),
ZX_OK);
};
start_process();
if (::testing::Test::HasFailure()) {
return -1;
}
return Wait();
}
LdLoadZirconProcessTestsBase::~LdLoadZirconProcessTestsBase() {
if (process_) {
EXPECT_EQ(process_.kill(), ZX_OK);
}
}
} // namespace ld::testing