#include "lldb/Core/ModuleList.h"
#include "TestingSupport/SubsystemRAII.h"
#include "TestingSupport/TestUtilities.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Host/FileSystem.h"
#include "lldb/Utility/ArchSpec.h"
#include "lldb/Utility/UUID.h"
#include "Plugins/ObjectFile/ELF/ObjectFileELF.h"
#include "gtest/gtest.h"
using namespace lldb;
using namespace lldb_private;
TEST(ModuleListTest, GetSharedModuleReusesExistingModuleWithSameUUID) {
SubsystemRAII<FileSystem, ObjectFileELF> subsystems;
auto ExpectedFile = TestFile::fromYaml(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 ]
AddressAlign: 0x0000000000000010
...
)");
ASSERT_THAT_EXPECTED(ExpectedFile, llvm::Succeeded());
ModuleSP first_module;
bool first_did_create = false;
Status error_first =
ModuleList::GetSharedModule(ExpectedFile->moduleSpec(), first_module,
nullptr, &first_did_create, false);
ModuleSP second_module;
bool second_did_create = false;
Status error_second =
ModuleList::GetSharedModule(ExpectedFile->moduleSpec(), second_module,
nullptr, &second_did_create, false);
if (error_first.Success() && error_second.Success()) {
EXPECT_EQ(first_module.get(), second_module.get())
<< "GetSharedModule should return the same module for the same spec";
EXPECT_TRUE(first_did_create) << "First call should create the module";
EXPECT_FALSE(second_did_create)
<< "Second call should reuse the existing module";
}
}
TEST(ModuleListTest, FindSharedModuleByUUID) {
SubsystemRAII<FileSystem, ObjectFileELF> subsystems;
auto ExpectedFile = TestFile::fromYaml(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 ]
AddressAlign: 0x0000000000000010
...
)");
ASSERT_THAT_EXPECTED(ExpectedFile, llvm::Succeeded());
ModuleSP created_module;
bool did_create = false;
Status error = ModuleList::GetSharedModule(
ExpectedFile->moduleSpec(), created_module, nullptr, &did_create, false);
if (error.Success() && created_module) {
UUID module_uuid = created_module->GetUUID();
if (module_uuid.IsValid()) {
ModuleSP found_module = ModuleList::FindSharedModule(module_uuid);
ASSERT_NE(found_module.get(), nullptr)
<< "FindSharedModule should find the module by UUID";
EXPECT_EQ(found_module.get(), created_module.get())
<< "FindSharedModule should return the same module instance";
EXPECT_EQ(found_module->GetUUID(), module_uuid)
<< "Found module should have the same UUID";
}
}
}
TEST(ModuleListTest, GetSharedModuleByUUIDIgnoresPath) {
SubsystemRAII<FileSystem, ObjectFileELF> subsystems;
auto ExpectedFile = TestFile::fromYaml(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 ]
AddressAlign: 0x0000000000000010
...
)");
ASSERT_THAT_EXPECTED(ExpectedFile, llvm::Succeeded());
ModuleSP first_module;
bool first_did_create = false;
Status first_error =
ModuleList::GetSharedModule(ExpectedFile->moduleSpec(), first_module,
nullptr, &first_did_create, false);
if (first_error.Success() && first_module) {
UUID module_uuid = first_module->GetUUID();
if (module_uuid.IsValid()) {
ModuleSpec second_spec;
second_spec.GetFileSpec() = FileSpec("/different/path/to/module.so");
second_spec.GetArchitecture() = ArchSpec("x86_64-pc-linux");
second_spec.GetUUID() = module_uuid;
ModuleSP second_module;
bool second_did_create = false;
Status second_error = ModuleList::GetSharedModule(
second_spec, second_module, nullptr, &second_did_create, false);
if (second_error.Success() && second_module) {
bool is_same_module = (second_module.get() == first_module.get());
EXPECT_TRUE(is_same_module)
<< "GetSharedModule with matching UUID should return existing "
"module, "
<< "even with different path (per PR #160199)";
if (is_same_module) {
EXPECT_FALSE(second_did_create)
<< "Should not create a new module when UUID matches";
}
}
}
}
}