diff --git a/lldb/include/lldb/Core/Module.h b/lldb/include/lldb/Core/Module.h --- a/lldb/include/lldb/Core/Module.h +++ b/lldb/include/lldb/Core/Module.h @@ -958,6 +958,12 @@ ///by \a m_file. uint64_t m_object_offset; llvm::sys::TimePoint<> m_object_mod_time; + + /// DataBuffer containing the module image, if it was provided at + /// construction time. Otherwise the data will be retrieved by mapping + /// one of the FileSpec members above. + lldb::DataBufferSP m_data_sp; + lldb::ObjectFileSP m_objfile_sp; ///< A shared pointer to the object file ///parser for this module as it may or may ///not be shared with the SymbolFile diff --git a/lldb/include/lldb/Core/ModuleSpec.h b/lldb/include/lldb/Core/ModuleSpec.h --- a/lldb/include/lldb/Core/ModuleSpec.h +++ b/lldb/include/lldb/Core/ModuleSpec.h @@ -30,11 +30,19 @@ m_object_name(), m_object_offset(0), m_object_size(0), m_source_mappings() {} - ModuleSpec(const FileSpec &file_spec, const UUID &uuid = UUID()) + /// If the \param data argument is passed, its contents will be used + /// as the module contents instead of trying to read them from + /// \param file_spec. + ModuleSpec(const FileSpec &file_spec, const UUID &uuid = UUID(), + lldb::DataBufferSP data = lldb::DataBufferSP()) : m_file(file_spec), m_platform_file(), m_symbol_file(), m_arch(), - m_uuid(uuid), m_object_name(), m_object_offset(0), - m_object_size(FileSystem::Instance().GetByteSize(file_spec)), - m_source_mappings() {} + m_uuid(uuid), m_object_name(), m_object_offset(0), m_source_mappings(), + m_data(data) { + if (data) + m_object_size = data->GetByteSize(); + else if (m_file) + m_object_size = FileSystem::Instance().GetByteSize(file_spec); + } ModuleSpec(const FileSpec &file_spec, const ArchSpec &arch) : m_file(file_spec), m_platform_file(), m_symbol_file(), m_arch(arch), @@ -42,30 +50,6 @@ m_object_size(FileSystem::Instance().GetByteSize(file_spec)), m_source_mappings() {} - ModuleSpec(const ModuleSpec &rhs) - : m_file(rhs.m_file), m_platform_file(rhs.m_platform_file), - m_symbol_file(rhs.m_symbol_file), m_arch(rhs.m_arch), - m_uuid(rhs.m_uuid), m_object_name(rhs.m_object_name), - m_object_offset(rhs.m_object_offset), m_object_size(rhs.m_object_size), - m_object_mod_time(rhs.m_object_mod_time), - m_source_mappings(rhs.m_source_mappings) {} - - ModuleSpec &operator=(const ModuleSpec &rhs) { - if (this != &rhs) { - m_file = rhs.m_file; - m_platform_file = rhs.m_platform_file; - m_symbol_file = rhs.m_symbol_file; - m_arch = rhs.m_arch; - m_uuid = rhs.m_uuid; - m_object_name = rhs.m_object_name; - m_object_offset = rhs.m_object_offset; - m_object_size = rhs.m_object_size; - m_object_mod_time = rhs.m_object_mod_time; - m_source_mappings = rhs.m_source_mappings; - } - return *this; - } - FileSpec *GetFileSpecPtr() { return (m_file ? &m_file : nullptr); } const FileSpec *GetFileSpecPtr() const { @@ -146,6 +130,8 @@ PathMappingList &GetSourceMappingList() const { return m_source_mappings; } + lldb::DataBufferSP GetData() const { return m_data; } + void Clear() { m_file.Clear(); m_platform_file.Clear(); @@ -289,6 +275,7 @@ uint64_t m_object_size; llvm::sys::TimePoint<> m_object_mod_time; mutable PathMappingList m_source_mappings; + lldb::DataBufferSP m_data = {}; }; class ModuleSpecList { diff --git a/lldb/include/lldb/Symbol/ObjectFile.h b/lldb/include/lldb/Symbol/ObjectFile.h --- a/lldb/include/lldb/Symbol/ObjectFile.h +++ b/lldb/include/lldb/Symbol/ObjectFile.h @@ -172,10 +172,10 @@ lldb::addr_t header_addr, lldb::DataBufferSP &file_data_sp); - static size_t GetModuleSpecifications(const FileSpec &file, - lldb::offset_t file_offset, - lldb::offset_t file_size, - ModuleSpecList &specs); + static size_t + GetModuleSpecifications(const FileSpec &file, lldb::offset_t file_offset, + lldb::offset_t file_size, ModuleSpecList &specs, + lldb::DataBufferSP data_sp = lldb::DataBufferSP()); static size_t GetModuleSpecifications(const lldb_private::FileSpec &file, lldb::DataBufferSP &data_sp, diff --git a/lldb/include/lldb/Utility/DataBuffer.h b/lldb/include/lldb/Utility/DataBuffer.h --- a/lldb/include/lldb/Utility/DataBuffer.h +++ b/lldb/include/lldb/Utility/DataBuffer.h @@ -79,6 +79,20 @@ } }; +class DataBufferUnowned : public DataBuffer { +public: + DataBufferUnowned(uint8_t *bytes, lldb::offset_t size) + : m_bytes(bytes), m_size(size) {} + + uint8_t *GetBytes() override { return m_bytes; } + const uint8_t *GetBytes() const override { return m_bytes; } + lldb::offset_t GetByteSize() const override { return m_size; } + +private: + uint8_t *m_bytes; + lldb::offset_t m_size; +}; + } // namespace lldb_private #endif /// #if defined(__cplusplus) diff --git a/lldb/source/Core/Module.cpp b/lldb/source/Core/Module.cpp --- a/lldb/source/Core/Module.cpp +++ b/lldb/source/Core/Module.cpp @@ -147,11 +147,16 @@ : module_spec.GetObjectName().AsCString(""), module_spec.GetObjectName().IsEmpty() ? "" : ")"); + auto data_sp = module_spec.GetData(); + lldb::offset_t file_size = 0; + if (data_sp) + file_size = data_sp->GetByteSize(); + // First extract all module specifications from the file using the local file // path. If there are no specifications, then don't fill anything in ModuleSpecList modules_specs; - if (ObjectFile::GetModuleSpecifications(module_spec.GetFileSpec(), 0, 0, - modules_specs) == 0) + if (ObjectFile::GetModuleSpecifications( + module_spec.GetFileSpec(), 0, file_size, modules_specs, data_sp) == 0) return; // Now make sure that one of the module specifications matches what we just @@ -170,11 +175,20 @@ return; } - if (module_spec.GetFileSpec()) - m_mod_time = FileSystem::Instance().GetModificationTime(module_spec.GetFileSpec()); - else if (matching_module_spec.GetFileSpec()) - m_mod_time = - FileSystem::Instance().GetModificationTime(matching_module_spec.GetFileSpec()); + // Set m_data_sp if it was initially provided in the ModuleSpec. Note that + // we cannot use the data_sp variable here, because it will have been + // modified by GetModuleSpecifications(). + if (auto module_spec_data_sp = module_spec.GetData()) { + m_data_sp = module_spec_data_sp; + m_mod_time = {}; + } else { + if (module_spec.GetFileSpec()) + m_mod_time = + FileSystem::Instance().GetModificationTime(module_spec.GetFileSpec()); + else if (matching_module_spec.GetFileSpec()) + m_mod_time = FileSystem::Instance().GetModificationTime( + matching_module_spec.GetFileSpec()); + } // Copy the architecture from the actual spec if we got one back, else use // the one that was specified @@ -1110,6 +1124,10 @@ } bool Module::FileHasChanged() const { + // We have provided the DataBuffer for this module to avoid accessing the + // filesystem. We never want to reload those files. + if (m_data_sp) + return false; if (!m_file_has_changed) m_file_has_changed = (FileSystem::Instance().GetModificationTime(m_file) != m_mod_time); @@ -1229,12 +1247,19 @@ static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); Timer scoped_timer(func_cat, "Module::GetObjectFile () module = %s", GetFileSpec().GetFilename().AsCString("")); - DataBufferSP data_sp; lldb::offset_t data_offset = 0; - const lldb::offset_t file_size = - FileSystem::Instance().GetByteSize(m_file); + lldb::offset_t file_size = 0; + + if (m_data_sp) + file_size = m_data_sp->GetByteSize(); + else if (m_file) + file_size = FileSystem::Instance().GetByteSize(m_file); + if (file_size > m_object_offset) { m_did_load_objfile = true; + // FindPlugin will modify its data_sp argument. Do not let it + // modify our m_data_sp member. + auto data_sp = m_data_sp; m_objfile_sp = ObjectFile::FindPlugin( shared_from_this(), &m_file, m_object_offset, file_size - m_object_offset, data_sp, data_offset); diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp --- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp +++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp @@ -541,7 +541,8 @@ __FUNCTION__, file.GetPath().c_str()); } - data_sp = MapFileData(file, -1, file_offset); + if (data_sp->GetByteSize() < length) + data_sp = MapFileData(file, -1, file_offset); if (data_sp) data.SetData(data_sp); // In case there is header extension in the section #0, the header we @@ -580,8 +581,7 @@ func_cat, "Calculating module crc32 %s with size %" PRIu64 " KiB", file.GetLastPathComponent().AsCString(), - (FileSystem::Instance().GetByteSize(file) - file_offset) / - 1024); + (length - file_offset) / 1024); // For core files - which usually don't happen to have a // gnu_debuglink, and are pretty bulky - calculating whole diff --git a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp --- a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp +++ b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp @@ -169,8 +169,9 @@ Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT)); - if (DataBufferSP full_sp = MapFileData(file, -1, file_offset)) - data_sp = std::move(full_sp); + if (data_sp->GetByteSize() < length) + if (DataBufferSP full_sp = MapFileData(file, -1, file_offset)) + data_sp = std::move(full_sp); auto binary = llvm::object::createBinary(llvm::MemoryBufferRef( toStringRef(data_sp->GetData()), file.GetFilename().GetStringRef())); @@ -539,6 +540,9 @@ if (!size) return {}; + if (m_data.ValidOffsetForDataOfSize(offset, size)) + return DataExtractor(m_data, offset, size); + if (m_file) { // A bit of a hack, but we intend to write to this buffer, so we can't // mmap it. @@ -562,13 +566,11 @@ } DataExtractor ObjectFilePECOFF::ReadImageDataByRVA(uint32_t rva, size_t size) { - if (m_file) { - Address addr = GetAddress(rva); - SectionSP sect = addr.GetSection(); - if (!sect) - return {}; - rva = sect->GetFileOffset() + addr.GetOffset(); - } + Address addr = GetAddress(rva); + SectionSP sect = addr.GetSection(); + if (!sect) + return {}; + rva = sect->GetFileOffset() + addr.GetOffset(); return ReadImageData(rva, size); } diff --git a/lldb/source/Symbol/ObjectFile.cpp b/lldb/source/Symbol/ObjectFile.cpp --- a/lldb/source/Symbol/ObjectFile.cpp +++ b/lldb/source/Symbol/ObjectFile.cpp @@ -47,8 +47,8 @@ FileSpec archive_file; ObjectContainerCreateInstance create_object_container_callback; - const bool file_exists = FileSystem::Instance().Exists(*file); if (!data_sp) { + const bool file_exists = FileSystem::Instance().Exists(*file); // We have an object name which most likely means we have a .o file in // a static archive (.a file). Try and see if we have a cached archive // first without reading any data first @@ -207,9 +207,11 @@ size_t ObjectFile::GetModuleSpecifications(const FileSpec &file, lldb::offset_t file_offset, lldb::offset_t file_size, - ModuleSpecList &specs) { - DataBufferSP data_sp = - FileSystem::Instance().CreateDataBuffer(file.GetPath(), 512, file_offset); + ModuleSpecList &specs, + DataBufferSP data_sp) { + if (!data_sp) + data_sp = FileSystem::Instance().CreateDataBuffer(file.GetPath(), 512, + file_offset); if (data_sp) { if (file_size == 0) { const lldb::offset_t actual_file_size = diff --git a/lldb/unittests/Core/CMakeLists.txt b/lldb/unittests/Core/CMakeLists.txt --- a/lldb/unittests/Core/CMakeLists.txt +++ b/lldb/unittests/Core/CMakeLists.txt @@ -1,6 +1,7 @@ add_lldb_unittest(LLDBCoreTests CommunicationTest.cpp MangledTest.cpp + ModuleSpecTest.cpp RichManglingContextTest.cpp SourceManagerTest.cpp StreamCallbackTest.cpp @@ -11,6 +12,8 @@ lldbHost lldbSymbol lldbPluginObjectFileELF + lldbPluginObjectFileMachO + lldbPluginObjectFilePECOFF lldbPluginSymbolFileSymtab lldbUtilityHelpers LLVMTestingSupport diff --git a/lldb/unittests/Core/MangledTest.cpp b/lldb/unittests/Core/MangledTest.cpp --- a/lldb/unittests/Core/MangledTest.cpp +++ b/lldb/unittests/Core/MangledTest.cpp @@ -165,8 +165,7 @@ )"); ASSERT_THAT_EXPECTED(ExpectedFile, llvm::Succeeded()); - ModuleSpec Spec{FileSpec(ExpectedFile->name())}; - auto M = std::make_shared(Spec); + auto M = std::make_shared(ExpectedFile->moduleSpec()); auto Count = [M](const char *Name, FunctionNameType Type) -> int { SymbolContextList SymList; diff --git a/lldb/unittests/Core/ModuleSpecTest.cpp b/lldb/unittests/Core/ModuleSpecTest.cpp new file mode 100644 --- /dev/null +++ b/lldb/unittests/Core/ModuleSpecTest.cpp @@ -0,0 +1,289 @@ +//===-- ModuleSpecTest.cpp ------------------------------------------------===// +// +// 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 "TestingSupport/SubsystemRAII.h" +#include "TestingSupport/TestUtilities.h" + +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Utility/DataBuffer.h" + +#include "Plugins/ObjectFile/ELF/ObjectFileELF.h" +#include "Plugins/ObjectFile/Mach-O/ObjectFileMachO.h" +#include "Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.h" + +#include "gtest/gtest.h" + +using namespace lldb; +using namespace lldb_private; + +extern const char *TestMainArgv0; + +// This test file intentionally doesn't initialize the FileSystem. +// Everything in this file should be able to run without requiring +// any interaction with the FileSystem class; by keeping it +// uninitialized, it will assert if anythign try to interact with +// it. + +TEST(ModuleSpecTest, InvalidInMemoryBuffer) { + uint8_t Invalid[] = "This is not a binary file."; + DataBufferSP InvalidBufferSP = + std::make_shared(Invalid, sizeof(Invalid)); + ModuleSpec Spec(FileSpec(), UUID(), InvalidBufferSP); + + auto InvalidModuleSP = std::make_shared(Spec); + ASSERT_EQ(InvalidModuleSP->GetObjectFile(), nullptr); +} + +TEST(ModuleSpecTest, InvalidInMemoryBufferValidFile) { + uint8_t Invalid[] = "This is not a binary file."; + DataBufferSP InvalidBufferSP = + std::make_shared(Invalid, sizeof(Invalid)); + ModuleSpec Spec(FileSpec(TestMainArgv0), UUID(), InvalidBufferSP); + + auto InvalidModuleSP = std::make_shared(Spec); + ASSERT_EQ(InvalidModuleSP->GetObjectFile(), nullptr); +} + +TEST(ModuleSpecTest, TestELFFile) { + SubsystemRAII subsystems; + + auto ExpectedFile = TestFile::fromYaml(R"( +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + AddressAlign: 0x0000000000000010 + - Name: .comment + Type: SHT_PROGBITS + Flags: [ SHF_MERGE, SHF_STRINGS ] + AddressAlign: 0x0000000000000001 + EntSize: 0x0000000000000001 + - Name: .note.GNU-stack + Type: SHT_PROGBITS + AddressAlign: 0x0000000000000001 + - Name: .eh_frame + Type: SHT_X86_64_UNWIND + Flags: [ SHF_ALLOC ] + AddressAlign: 0x0000000000000008 + - Name: .rela.eh_frame + Type: SHT_RELA + Link: .symtab + AddressAlign: 0x0000000000000008 + Info: .eh_frame + Relocations: + - Offset: 0x0000000000000020 + Symbol: .text + Type: R_X86_64_PC32 + - Name: .llvm_addrsig + Type: SHT_LLVM_ADDRSIG + Flags: [ SHF_EXCLUDE ] + Link: .symtab + AddressAlign: 0x0000000000000001 + Symbols: [ ] +Symbols: + - Name: '-' + Type: STT_FILE + Index: SHN_ABS + - Name: .text + Type: STT_SECTION + Section: .text + - Name: main + Type: STT_FUNC + Section: .text + Binding: STB_GLOBAL + Size: 0x000000000000000F +... +)"); + ASSERT_THAT_EXPECTED(ExpectedFile, llvm::Succeeded()); + + auto M = std::make_shared(ExpectedFile->moduleSpec()); + ObjectFile *OF = M->GetObjectFile(); + + ASSERT_EQ(llvm::isa(OF), true); +} + +TEST(ModuleSpecTest, TestCOFFFile) { + SubsystemRAII subsystems; + + auto ExpectedFile = TestFile::fromYaml(R"( +--- !COFF +OptionalHeader: + AddressOfEntryPoint: 0 + ImageBase: 16777216 + SectionAlignment: 4096 + FileAlignment: 512 + MajorOperatingSystemVersion: 6 + MinorOperatingSystemVersion: 0 + MajorImageVersion: 0 + MinorImageVersion: 0 + MajorSubsystemVersion: 6 + MinorSubsystemVersion: 0 + Subsystem: IMAGE_SUBSYSTEM_WINDOWS_CUI + DLLCharacteristics: [ IMAGE_DLL_CHARACTERISTICS_HIGH_ENTROPY_VA, IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE, IMAGE_DLL_CHARACTERISTICS_NX_COMPAT ] + SizeOfStackReserve: 1048576 + SizeOfStackCommit: 4096 + SizeOfHeapReserve: 1048576 + SizeOfHeapCommit: 4096 +header: + Machine: IMAGE_FILE_MACHINE_AMD64 + Characteristics: [ IMAGE_FILE_EXECUTABLE_IMAGE, IMAGE_FILE_LARGE_ADDRESS_AWARE ] +sections: + - Name: .text + Characteristics: [ IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE, IMAGE_SCN_MEM_READ ] + VirtualAddress: 4096 + VirtualSize: 4096 + - Name: .rdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + VirtualAddress: 8192 + VirtualSize: 68 + - Name: .pdata + Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ] + VirtualAddress: 12288 + VirtualSize: 60 +symbols: [] +... +)"); + ASSERT_THAT_EXPECTED(ExpectedFile, llvm::Succeeded()); + + auto M = std::make_shared(ExpectedFile->moduleSpec()); + ObjectFile *OF = M->GetObjectFile(); + + ASSERT_EQ(llvm::isa(OF), true); +} + +TEST(ModuleSpecTest, TestMachOFile) { + SubsystemRAII subsystems; + + auto ExpectedFile = TestFile::fromYaml(R"( +--- !mach-o +FileHeader: + magic: 0xFEEDFACF + cputype: 0x0100000C + cpusubtype: 0x00000000 + filetype: 0x00000001 + ncmds: 4 + sizeofcmds: 360 + flags: 0x00002000 + reserved: 0x00000000 +LoadCommands: + - cmd: LC_SEGMENT_64 + cmdsize: 232 + segname: '' + vmaddr: 0 + vmsize: 56 + fileoff: 392 + filesize: 56 + maxprot: 7 + initprot: 7 + nsects: 2 + flags: 0 + Sections: + - sectname: __text + segname: __TEXT + addr: 0x0000000000000000 + size: 24 + offset: 0x00000188 + align: 2 + reloff: 0x00000000 + nreloc: 0 + flags: 0x80000400 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + - sectname: __compact_unwind + segname: __LD + addr: 0x0000000000000018 + size: 32 + offset: 0x000001A0 + align: 3 + reloff: 0x000001C0 + nreloc: 1 + flags: 0x02000000 + reserved1: 0x00000000 + reserved2: 0x00000000 + reserved3: 0x00000000 + relocations: + - address: 0x00000000 + symbolnum: 1 + pcrel: false + length: 3 + extern: false + type: 0 + scattered: false + value: 0 + - cmd: LC_BUILD_VERSION + cmdsize: 24 + platform: 1 + minos: 659200 + sdk: 720896 + ntools: 0 + - cmd: LC_SYMTAB + cmdsize: 24 + symoff: 456 + nsyms: 3 + stroff: 504 + strsize: 20 + - cmd: LC_DYSYMTAB + cmdsize: 80 + ilocalsym: 0 + nlocalsym: 2 + iextdefsym: 2 + nextdefsym: 1 + iundefsym: 3 + nundefsym: 0 + tocoff: 0 + ntoc: 0 + modtaboff: 0 + nmodtab: 0 + extrefsymoff: 0 + nextrefsyms: 0 + indirectsymoff: 0 + nindirectsyms: 0 + extreloff: 0 + nextrel: 0 + locreloff: 0 + nlocrel: 0 +LinkEditData: + NameList: + - n_strx: 13 + n_type: 0x0E + n_sect: 1 + n_desc: 0 + n_value: 0 + - n_strx: 7 + n_type: 0x0E + n_sect: 2 + n_desc: 0 + n_value: 24 + - n_strx: 1 + n_type: 0x0F + n_sect: 1 + n_desc: 0 + n_value: 0 + StringTable: + - '' + - _main + - ltmp1 + - ltmp0 + - '' +... +)"); + ASSERT_THAT_EXPECTED(ExpectedFile, llvm::Succeeded()); + + auto M = std::make_shared(ExpectedFile->moduleSpec()); + ObjectFile *OF = M->GetObjectFile(); + + ASSERT_EQ(llvm::isa(OF), true); +} diff --git a/lldb/unittests/ObjectFile/ELF/TestObjectFileELF.cpp b/lldb/unittests/ObjectFile/ELF/TestObjectFileELF.cpp --- a/lldb/unittests/ObjectFile/ELF/TestObjectFileELF.cpp +++ b/lldb/unittests/ObjectFile/ELF/TestObjectFileELF.cpp @@ -91,10 +91,7 @@ )"); ASSERT_THAT_EXPECTED(ExpectedFile, llvm::Succeeded()); - ModuleSpec spec{FileSpec(ExpectedFile->name())}; - spec.GetSymbolFileSpec().SetFile(ExpectedFile->name(), - FileSpec::Style::native); - auto module_sp = std::make_shared(spec); + auto module_sp = std::make_shared(ExpectedFile->moduleSpec()); SectionList *list = module_sp->GetSectionList(); ASSERT_NE(nullptr, list); @@ -212,10 +209,7 @@ )"); ASSERT_THAT_EXPECTED(ExpectedFile, llvm::Succeeded()); - ModuleSpec spec{FileSpec(ExpectedFile->name())}; - spec.GetSymbolFileSpec().SetFile(ExpectedFile->name(), - FileSpec::Style::native); - auto module_sp = std::make_shared(spec); + auto module_sp = std::make_shared(ExpectedFile->moduleSpec()); auto entry_point_addr = module_sp->GetObjectFile()->GetEntryPointAddress(); ASSERT_TRUE(entry_point_addr.GetOffset() & 1); @@ -277,10 +271,7 @@ )"); ASSERT_THAT_EXPECTED(ExpectedFile, llvm::Succeeded()); - ModuleSpec spec{FileSpec(ExpectedFile->name())}; - spec.GetSymbolFileSpec().SetFile(ExpectedFile->name(), - FileSpec::Style::native); - auto module_sp = std::make_shared(spec); + auto module_sp = std::make_shared(ExpectedFile->moduleSpec()); auto entry_point_addr = module_sp->GetObjectFile()->GetEntryPointAddress(); ASSERT_EQ(entry_point_addr.GetAddressClass(), AddressClass::eCode); diff --git a/lldb/unittests/ObjectFile/PECOFF/TestPECallFrameInfo.cpp b/lldb/unittests/ObjectFile/PECOFF/TestPECallFrameInfo.cpp --- a/lldb/unittests/ObjectFile/PECOFF/TestPECallFrameInfo.cpp +++ b/lldb/unittests/ObjectFile/PECOFF/TestPECallFrameInfo.cpp @@ -192,7 +192,7 @@ )"); ASSERT_THAT_EXPECTED(ExpectedFile, llvm::Succeeded()); - ModuleSP module_sp = std::make_shared(ModuleSpec(FileSpec(ExpectedFile->name()))); + ModuleSP module_sp = std::make_shared(ExpectedFile->moduleSpec()); ObjectFile *object_file = module_sp->GetObjectFile(); ASSERT_NE(object_file, nullptr); diff --git a/lldb/unittests/Symbol/TestDWARFCallFrameInfo.cpp b/lldb/unittests/Symbol/TestDWARFCallFrameInfo.cpp --- a/lldb/unittests/Symbol/TestDWARFCallFrameInfo.cpp +++ b/lldb/unittests/Symbol/TestDWARFCallFrameInfo.cpp @@ -220,8 +220,7 @@ )"); ASSERT_THAT_EXPECTED(ExpectedFile, llvm::Succeeded()); - auto module_sp = - std::make_shared(ModuleSpec(FileSpec(ExpectedFile->name()))); + auto module_sp = std::make_shared(ExpectedFile->moduleSpec()); SectionList *list = module_sp->GetSectionList(); ASSERT_NE(nullptr, list); diff --git a/lldb/unittests/Symbol/TestLineEntry.cpp b/lldb/unittests/Symbol/TestLineEntry.cpp --- a/lldb/unittests/Symbol/TestLineEntry.cpp +++ b/lldb/unittests/Symbol/TestLineEntry.cpp @@ -49,7 +49,7 @@ auto ExpectedFile = TestFile::fromYamlFile("inlined-functions.yaml"); ASSERT_THAT_EXPECTED(ExpectedFile, llvm::Succeeded()); m_file.emplace(std::move(*ExpectedFile)); - m_module_sp = std::make_shared(ModuleSpec(FileSpec(m_file->name()))); + m_module_sp = std::make_shared(m_file->moduleSpec()); } llvm::Expected LineEntryTest::GetLineEntryForLine(uint32_t line) { diff --git a/lldb/unittests/TestingSupport/TestUtilities.h b/lldb/unittests/TestingSupport/TestUtilities.h --- a/lldb/unittests/TestingSupport/TestUtilities.h +++ b/lldb/unittests/TestingSupport/TestUtilities.h @@ -9,6 +9,8 @@ #ifndef LLDB_UNITTESTS_TESTINGSUPPORT_TESTUTILITIES_H #define LLDB_UNITTESTS_TESTINGSUPPORT_TESTUTILITIES_H +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Utility/DataBuffer.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/Error.h" @@ -34,22 +36,28 @@ static llvm::Expected fromYaml(llvm::StringRef Yaml); static llvm::Expected fromYamlFile(const llvm::Twine &Name); - TestFile(TestFile &&RHS) : Name(std::move(RHS.Name)) { - RHS.Name = llvm::None; + TestFile(TestFile &&RHS) : Buffer(std::move(RHS.Buffer)) { + RHS.Buffer = llvm::None; } - ~TestFile(); + ~TestFile() = default; - llvm::StringRef name() { return *Name; } + ModuleSpec moduleSpec() { + return ModuleSpec(FileSpec(), UUID(), dataBuffer()); + } private: - TestFile(llvm::StringRef Name, llvm::FileRemover &&Remover) - : Name(std::string(Name)) { - Remover.releaseFile(); - } + TestFile(std::string &&Buffer) : Buffer(Buffer) {} + void operator=(const TestFile &) = delete; - llvm::Optional Name; + lldb::DataBufferSP dataBuffer() { + auto *buffer = reinterpret_cast(Buffer->data()); + return std::make_shared(const_cast(buffer), + Buffer->size()); + } + + llvm::Optional Buffer; }; } diff --git a/lldb/unittests/TestingSupport/TestUtilities.cpp b/lldb/unittests/TestingSupport/TestUtilities.cpp --- a/lldb/unittests/TestingSupport/TestUtilities.cpp +++ b/lldb/unittests/TestingSupport/TestUtilities.cpp @@ -29,21 +29,14 @@ llvm::Expected TestFile::fromYaml(llvm::StringRef Yaml) { const auto *Info = testing::UnitTest::GetInstance()->current_test_info(); assert(Info); - llvm::SmallString<128> Name; - int FD; - if (std::error_code EC = llvm::sys::fs::createTemporaryFile( - llvm::Twine(Info->test_case_name()) + "-" + Info->name(), "test", FD, - Name)) - return llvm::errorCodeToError(EC); - llvm::FileRemover Remover(Name); - { - llvm::raw_fd_ostream OS(FD, /*shouldClose*/ true); - llvm::yaml::Input YIn(Yaml); - if (!llvm::yaml::convertYAML(YIn, OS, [](const llvm::Twine &Msg) {})) - return llvm::createStringError(llvm::inconvertibleErrorCode(), - "convertYAML() failed"); - } - return TestFile(Name, std::move(Remover)); + + std::string Buffer; + llvm::raw_string_ostream OS(Buffer); + llvm::yaml::Input YIn(Yaml); + if (!llvm::yaml::convertYAML(YIn, OS, [](const llvm::Twine &Msg) {})) + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "convertYAML() failed"); + return TestFile(std::move(Buffer)); } llvm::Expected TestFile::fromYamlFile(const llvm::Twine &Name) { @@ -55,11 +48,3 @@ return fromYaml(BufferOrError.get()->getBuffer()); } -TestFile::~TestFile() { - if (!Name) - return; - if (std::error_code EC = - llvm::sys::fs::remove(*Name, /*IgnoreNonExisting*/ false)) - GTEST_LOG_(WARNING) << "Failed to delete `" << Name->c_str() - << "`: " << EC.message(); -}