blob: 633f72c4f363687fb6455933f24bc5cca16056e5 [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 <gtest/gtest.h>
#ifdef __Fuchsia__
#include "ld-startup-create-process-tests.h"
#include "ld-startup-in-process-tests-zircon.h"
#include "ld-startup-spawn-process-tests-zircon.h"
#include "lib/ld/test/ld-remote-process-tests.h"
#else
#include "ld-startup-in-process-tests-posix.h"
#include "ld-startup-spawn-process-tests-posix.h"
#endif
namespace {
template <class Fixture>
using LdLoadTests = Fixture;
template <class Fixture>
using LdLoadFailureTests = Fixture;
// This lists all the types that are compatible with both LdLoadTests and LdLoadFailureTests.
template <class... Tests>
using TestTypes = ::testing::Types<
// TODO(fxbug.dev/130483): The separate-process tests require symbolic
// relocation so they can make the syscall to exit. The spawn-process
// tests also need a loader service to get ld.so.1 itself.
#ifdef __Fuchsia__
ld::testing::LdStartupCreateProcessTests<>,
#else
ld::testing::LdStartupSpawnProcessTests,
#endif
Tests...>;
// This types are meaningul for the successful tests, LdLoadTests.
using LoadTypes = TestTypes<
// TODO(fxbug.dev/134320): LdRemoteProcessTests::Run doesn't actually run the
// test, instead it always returns 17. This isn't suitable for failure tests
// which don't return 17. When remote loading is implemented and these tests
// are actually run this can be moved into the default types in TestTypes.
#ifdef __Fuchsia__
ld::testing::LdRemoteProcessTests,
#endif
ld::testing::LdStartupInProcessTests>;
// These types are the types which are compatible with the failure tests, LdLoadFailureTests.
using FailTypes = TestTypes<>;
TYPED_TEST_SUITE(LdLoadTests, LoadTypes);
TYPED_TEST_SUITE(LdLoadFailureTests, FailTypes);
TYPED_TEST(LdLoadTests, Basic) {
constexpr int64_t kReturnValue = 17;
ASSERT_NO_FATAL_FAILURE(this->Init());
ASSERT_NO_FATAL_FAILURE(this->Load("ret17"));
EXPECT_EQ(this->Run(), kReturnValue);
this->ExpectLog("");
}
TYPED_TEST(LdLoadTests, Relative) {
constexpr int64_t kReturnValue = 17;
ASSERT_NO_FATAL_FAILURE(this->Init());
ASSERT_NO_FATAL_FAILURE(this->Load("relative-reloc"));
EXPECT_EQ(this->Run(), kReturnValue);
this->ExpectLog("");
}
TYPED_TEST(LdLoadTests, Symbolic) {
constexpr int64_t kReturnValue = 17;
ASSERT_NO_FATAL_FAILURE(this->Init());
ASSERT_NO_FATAL_FAILURE(this->Load("symbolic-reloc"));
EXPECT_EQ(this->Run(), kReturnValue);
this->ExpectLog("");
}
TYPED_TEST(LdLoadTests, LoadWithNeeded) {
constexpr int64_t kReturnValue = 17;
ASSERT_NO_FATAL_FAILURE(this->Init());
// There is only a reference to ld.so which doesn't need to be loaded to satisfy.
ASSERT_NO_FATAL_FAILURE(this->Needed(std::initializer_list<std::string_view>{}));
ASSERT_NO_FATAL_FAILURE(this->Load("ld-dep"));
EXPECT_EQ(this->Run(), kReturnValue);
this->ExpectLog("");
}
TYPED_TEST(LdLoadTests, BasicDep) {
constexpr int64_t kReturnValue = 17;
ASSERT_NO_FATAL_FAILURE(this->Init());
ASSERT_NO_FATAL_FAILURE(this->Needed({"libld-dep-a.so"}));
ASSERT_NO_FATAL_FAILURE(this->Load("basic-dep"));
EXPECT_EQ(this->Run(), kReturnValue);
this->ExpectLog("");
}
TYPED_TEST(LdLoadTests, IndirectDeps) {
constexpr int64_t kReturnValue = 17;
ASSERT_NO_FATAL_FAILURE(this->Init());
ASSERT_NO_FATAL_FAILURE(this->Needed({
"libindirect-deps-a.so",
"libindirect-deps-b.so",
"libindirect-deps-c.so",
}));
ASSERT_NO_FATAL_FAILURE(this->Load("indirect-deps"));
EXPECT_EQ(this->Run(), kReturnValue);
this->ExpectLog("");
}
TYPED_TEST(LdLoadTests, PassiveAbiBasic) {
constexpr int64_t kReturnValue = 17;
ASSERT_NO_FATAL_FAILURE(this->Init());
ASSERT_NO_FATAL_FAILURE(this->Load("passive-abi-basic"));
EXPECT_EQ(this->Run(), kReturnValue);
this->ExpectLog("");
}
TYPED_TEST(LdLoadTests, SymbolicNamespace) {
constexpr int64_t kReturnValue = 17;
ASSERT_NO_FATAL_FAILURE(this->Init());
ASSERT_NO_FATAL_FAILURE(this->Needed({"libld-dep-a.so"}));
ASSERT_NO_FATAL_FAILURE(this->Load("symbolic-namespace"));
EXPECT_EQ(this->Run(), kReturnValue);
this->ExpectLog("");
}
TYPED_TEST(LdLoadTests, ManyDeps) {
constexpr int64_t kReturnValue = 17;
ASSERT_NO_FATAL_FAILURE(this->Init());
ASSERT_NO_FATAL_FAILURE(this->Needed({
"libld-dep-a.so",
"libld-dep-b.so",
"libld-dep-f.so",
"libld-dep-c.so",
"libld-dep-d.so",
"libld-dep-e.so",
}));
ASSERT_NO_FATAL_FAILURE(this->Load("many-deps"));
EXPECT_EQ(this->Run(), kReturnValue);
this->ExpectLog("");
}
TYPED_TEST(LdLoadTests, InitFini) {
constexpr int64_t kReturnValue = 17;
ASSERT_NO_FATAL_FAILURE(this->Init());
ASSERT_NO_FATAL_FAILURE(this->Load("init-fini"));
EXPECT_EQ(this->Run(), kReturnValue);
this->ExpectLog("");
}
TYPED_TEST(LdLoadTests, TlsExecOnly) {
constexpr int64_t kReturnValue = 17;
ASSERT_NO_FATAL_FAILURE(this->Init());
ASSERT_NO_FATAL_FAILURE(this->Load("tls-exec-only"));
EXPECT_EQ(this->Run(), kReturnValue);
this->ExpectLog("");
}
TYPED_TEST(LdLoadTests, TlsShlibOnly) {
constexpr int64_t kReturnValue = 17;
ASSERT_NO_FATAL_FAILURE(this->Init());
ASSERT_NO_FATAL_FAILURE(this->Needed({"libtls-dep.so"}));
ASSERT_NO_FATAL_FAILURE(this->Load("tls-shlib-only"));
EXPECT_EQ(this->Run(), kReturnValue);
this->ExpectLog("");
}
TYPED_TEST(LdLoadTests, TlsExecShlib) {
constexpr int64_t kReturnValue = 17;
ASSERT_NO_FATAL_FAILURE(this->Init());
ASSERT_NO_FATAL_FAILURE(this->Needed({"libtls-dep.so"}));
ASSERT_NO_FATAL_FAILURE(this->Load("tls-exec-shlib"));
EXPECT_EQ(this->Run(), kReturnValue);
this->ExpectLog("");
}
TYPED_TEST(LdLoadTests, TlsInitialExecAccess) {
constexpr int64_t kReturnValue = 17;
ASSERT_NO_FATAL_FAILURE(this->Init());
ASSERT_NO_FATAL_FAILURE(this->Needed({"libtls-ie-dep.so"}));
ASSERT_NO_FATAL_FAILURE(this->Load("tls-ie"));
EXPECT_EQ(this->Run(), kReturnValue);
this->ExpectLog("");
}
TYPED_TEST(LdLoadTests, TlsGlobalDynamicAccess) {
constexpr int64_t kReturnValue = 17;
constexpr int64_t kSkipReturnValue = 77;
ASSERT_NO_FATAL_FAILURE(this->Init());
ASSERT_NO_FATAL_FAILURE(this->Needed({"libtls-dep.so"}));
ASSERT_NO_FATAL_FAILURE(this->Load("tls-gd"));
const int64_t return_value = this->Run();
// Check the log before the return value so we've handled it in case we skip.
this->ExpectLog("");
if (return_value == kSkipReturnValue) {
GTEST_SKIP() << "tls-gd module compiled with TLSDESC";
}
EXPECT_EQ(return_value, kReturnValue);
}
TYPED_TEST(LdLoadFailureTests, MissingSymbol) {
ASSERT_NO_FATAL_FAILURE(this->Init());
ASSERT_NO_FATAL_FAILURE(this->Needed({"libld-dep-a.so"}));
ASSERT_NO_FATAL_FAILURE(this->Load("missing-sym"));
EXPECT_EQ(this->Run(), this->kRunFailureForTrap);
this->ExpectLog(R"(undefined symbol: b
startup dynamic linking failed with 1 errors and 0 warnings
)");
}
TYPED_TEST(LdLoadFailureTests, MissingDependency) {
ASSERT_NO_FATAL_FAILURE(this->Init());
ASSERT_NO_FATAL_FAILURE(this->Needed({std::pair{"libmissing-dep-dep.so", false}}));
ASSERT_NO_FATAL_FAILURE(this->Load("missing-dep"));
EXPECT_EQ(this->Run(), this->kRunFailureForTrap);
this->ExpectLog(R"(cannot open dependency: libmissing-dep-dep.so
startup dynamic linking failed with 1 errors and 0 warnings
)");
}
TYPED_TEST(LdLoadFailureTests, Relro) {
ASSERT_NO_FATAL_FAILURE(this->Init());
ASSERT_NO_FATAL_FAILURE(this->Load("relro"));
EXPECT_EQ(this->Run(), this->kRunFailureForBadPointer);
this->ExpectLog("");
}
} // namespace