blob: 53c73e7a5dd595d34605654aac6e473d8f68bd4d [file] [log] [blame]
// Copyright 2025 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 <gmock/gmock.h>
#include <gtest/gtest.h>
#include "../asm-linkage.h"
#include "../dlfcn/dlfcn-abi.h"
#include "src/__support/common.h"
#include "src/link/dl_iterate_phdr.h"
namespace LIBC_NAMESPACE_DECL {
namespace {
using ::testing::Return;
// While each test runs, _dlfcn_phdr_info_counts and _dlfcn_iterate_phdr will
// turn into calls on the mock().
class LibcDlfcnAbiTests : public ::testing::Test {
public:
struct Mock {
MOCK_METHOD(ld::DlPhdrInfoCounts, PhdrInfoCounts, ());
MOCK_METHOD(int, IteratePhdr, (__dl_iterate_phdr_callback_t, void*));
};
static void SetUpTestSuite() {
ASSERT_EQ(_dlfcn_phdr_info_counts, MockPhdrInfoCounts);
ASSERT_EQ(_dlfcn_iterate_phdr, MockIteratePhdr);
}
void SetUp() override {
ASSERT_EQ(current_mock_, nullptr);
current_mock_ = &mock_;
}
void TearDown() override {
EXPECT_EQ(current_mock_, &mock_);
current_mock_ = nullptr;
}
auto& mock() { return mock_; }
private:
// These have internal linkage, but use asm-linkage names to get unmangled
// names to use in the aliases below.
static decltype(_dlfcn_phdr_info_counts) MockPhdrInfoCounts
LIBC_ASM_LINKAGE_DECLARE(MockPhdrInfoCounts);
static decltype(_dlfcn_iterate_phdr) MockIteratePhdr LIBC_ASM_LINKAGE_DECLARE(MockIteratePhdr);
inline static ::testing::StrictMock<Mock>* current_mock_ = nullptr;
::testing::StrictMock<Mock> mock_;
};
ld::DlPhdrInfoCounts LibcDlfcnAbiTests::MockPhdrInfoCounts() {
return current_mock_->PhdrInfoCounts();
}
int LibcDlfcnAbiTests::MockIteratePhdr(__dl_iterate_phdr_callback_t callback, void* arg) {
return current_mock_->IteratePhdr(callback, arg);
}
constexpr ld::DlPhdrInfoCounts kFakeCounts = {.adds = 123, .subs = 456};
// Because the global declaration from <link.h> is also in scope, all calls
// here have to be disambiguated with explicit LIBC_NAMESPACE::dl_iterate_phdr.
TEST_F(LibcDlfcnAbiTests, PhdrInfoCounts) {
EXPECT_CALL(mock(), PhdrInfoCounts()).WillOnce(Return(kFakeCounts));
EXPECT_EQ(LIBC_NAMESPACE::dl_iterate_phdr(
[](dl_phdr_info* info, size_t size, void*) -> int {
EXPECT_EQ(info->dlpi_adds, kFakeCounts.adds);
EXPECT_EQ(info->dlpi_subs, kFakeCounts.subs);
return 42;
},
nullptr),
42);
}
TEST_F(LibcDlfcnAbiTests, IteratePhdrBailEarly) {
EXPECT_CALL(mock(), PhdrInfoCounts());
// The mock() expects no other calls.
auto bail_early = [](dl_phdr_info* info, size_t size, void*) { return 42; };
EXPECT_EQ(LIBC_NAMESPACE::dl_iterate_phdr(bail_early, nullptr), 42);
}
TEST_F(LibcDlfcnAbiTests, IteratePhdr) {
EXPECT_CALL(mock(), PhdrInfoCounts());
auto succeed = [](dl_phdr_info* info, size_t size, void*) { return 0; };
EXPECT_CALL(mock(), IteratePhdr(+succeed, &succeed)).WillOnce(Return(42));
EXPECT_EQ(LIBC_NAMESPACE::dl_iterate_phdr(+succeed, &succeed), 42);
}
} // namespace
// These are defined here so calling into LIBC_NAMESPACE::dl_iterate_phdr will
// exercise the defined-symbols case rather than the weak-undefined case that's
// exercised in the dl_iterate_phdr_test.cc tests in the main libc-unittests.
// The assertions in SetUpTestSuite ensure there wasn't some other definition
// linked into this test binary (such as libdl's).
decltype(_dlfcn_phdr_info_counts) _dlfcn_phdr_info_counts
[[gnu::alias(LIBC_ASM_LINKAGE_STRING(MockPhdrInfoCounts))]];
decltype(_dlfcn_iterate_phdr) _dlfcn_iterate_phdr
[[gnu::alias(LIBC_ASM_LINKAGE_STRING(MockIteratePhdr))]];
} // namespace LIBC_NAMESPACE_DECL