blob: d8fcb98b6df3763f263e3f358807e405c60d0ea6 [file] [edit]
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "Plugins/ObjectFile/ELF/ObjectFileELF.h"
#include "Plugins/Platform/Linux/PlatformLinux.h"
#include "Plugins/ScriptInterpreter/None/ScriptInterpreterNone.h"
#include "TestingSupport/SubsystemRAII.h"
#include "TestingSupport/TestUtilities.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Module.h"
#include "lldb/Host/FileSystem.h"
#include "lldb/Host/HostInfo.h"
#include "lldb/Target/Platform.h"
#include "lldb/Target/Target.h"
#include "llvm/Testing/Support/Error.h"
#include "gtest/gtest.h"
#include <optional>
using namespace lldb_private;
using namespace lldb;
namespace {
// An ELF shared library. A PIE executable is one too.
const char *k_shared_library_yaml = R"(
--- !ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_DYN
Machine: EM_X86_64
Sections:
- Name: .text
Type: SHT_PROGBITS
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
Address: 0x1000
AddressAlign: 0x10
Content: C3
...
)";
const char *k_executable_yaml = R"(
--- !ELF
FileHeader:
Class: ELFCLASS64
Data: ELFDATA2LSB
Type: ET_EXEC
Machine: EM_X86_64
Sections:
- Name: .text
Type: SHT_PROGBITS
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
Address: 0x1000
AddressAlign: 0x10
Content: C3
...
)";
class ExecutableModuleTest : public testing::Test {
public:
void SetUp() override {
llvm::Expected<TestFile> shared_library =
TestFile::fromYaml(k_shared_library_yaml);
ASSERT_THAT_EXPECTED(shared_library, llvm::Succeeded());
m_shared_library.emplace(std::move(*shared_library));
llvm::Expected<TestFile> executable = TestFile::fromYaml(k_executable_yaml);
ASSERT_THAT_EXPECTED(executable, llvm::Succeeded());
m_executable.emplace(std::move(*executable));
ArchSpec arch("x86_64-pc-linux");
std::call_once(TestUtilities::g_debugger_initialize_flag,
[]() { Debugger::Initialize(nullptr); });
Platform::SetHostPlatform(
platform_linux::PlatformLinux::CreateInstance(true, &arch));
m_debugger_sp = Debugger::CreateInstance();
ASSERT_TRUE(m_debugger_sp);
PlatformSP platform_sp;
m_debugger_sp->GetTargetList().CreateTarget(
*m_debugger_sp, "", arch, eLoadDependentsNo, platform_sp, m_target_sp);
ASSERT_TRUE(m_target_sp);
}
void TearDown() override {
m_target_sp.reset();
if (m_debugger_sp)
Debugger::Destroy(m_debugger_sp);
}
ModuleSP CreateSharedLibrary() {
return std::make_shared<Module>(m_shared_library->moduleSpec());
}
ModuleSP CreateExecutable() {
return std::make_shared<Module>(m_executable->moduleSpec());
}
SubsystemRAII<FileSystem, HostInfo, ObjectFileELF,
platform_linux::PlatformLinux, ScriptInterpreterNone>
subsystems;
// These back the target's modules and must outlive them.
std::optional<TestFile> m_shared_library;
std::optional<TestFile> m_executable;
DebuggerSP m_debugger_sp;
TargetSP m_target_sp;
};
} // namespace
TEST_F(ExecutableModuleTest, NoExecutable) {
m_target_sp->GetImages().Append(CreateSharedLibrary(), /*notify=*/false);
EXPECT_EQ(m_target_sp->GetExecutableModule(), nullptr);
}
TEST_F(ExecutableModuleTest, SharedLibraryExecutable) {
ModuleSP executable_sp = CreateSharedLibrary();
m_target_sp->RebuildModuleListWithExecutable(executable_sp,
eLoadDependentsNo);
m_target_sp->GetImages().Append(CreateSharedLibrary(), /*notify=*/false);
EXPECT_EQ(m_target_sp->GetExecutableModule(), executable_sp);
}
TEST_F(ExecutableModuleTest, MarkKeepsImages) {
ModuleList &images = m_target_sp->GetImages();
images.Append(CreateSharedLibrary(), /*notify=*/false);
ModuleSP executable_sp = CreateSharedLibrary();
images.Append(executable_sp, /*notify=*/false);
m_target_sp->MarkExecutableModule(executable_sp);
EXPECT_EQ(m_target_sp->GetExecutableModule(), executable_sp);
EXPECT_EQ(images.GetSize(), 2u);
}
TEST_F(ExecutableModuleTest, RemovedExecutable) {
ModuleSP executable_sp = CreateSharedLibrary();
m_target_sp->RebuildModuleListWithExecutable(executable_sp,
eLoadDependentsNo);
ModuleList &images = m_target_sp->GetImages();
images.Append(CreateSharedLibrary(), /*notify=*/false);
images.Remove(executable_sp);
EXPECT_EQ(m_target_sp->GetExecutableModule(), nullptr);
}
TEST_F(ExecutableModuleTest, ReplacedExecutable) {
ModuleSP executable_sp = CreateSharedLibrary();
m_target_sp->RebuildModuleListWithExecutable(executable_sp,
eLoadDependentsNo);
m_target_sp->GetImages().Append(CreateSharedLibrary(), /*notify=*/false);
// A replacement only becomes the executable once the target is rebuilt
// around it, which callers decide by comparing it against the executable.
ModuleSP replacement_sp = CreateSharedLibrary();
m_target_sp->GetImages().ReplaceModule(executable_sp, replacement_sp);
EXPECT_EQ(m_target_sp->GetExecutableModule(), nullptr);
}
TEST_F(ExecutableModuleTest, ExecutableTypeFirst) {
ModuleSP library_sp = CreateSharedLibrary();
m_target_sp->RebuildModuleListWithExecutable(library_sp, eLoadDependentsNo);
ModuleSP executable_sp = CreateExecutable();
m_target_sp->GetImages().Append(executable_sp, /*notify=*/false);
EXPECT_EQ(m_target_sp->GetExecutableModule(), executable_sp);
}