diff --git a/lldb/include/lldb/Host/FileSpec.h b/lldb/include/lldb/Host/FileSpec.h index 173d948e687b..a28eca4173bb 100644 --- a/lldb/include/lldb/Host/FileSpec.h +++ b/lldb/include/lldb/Host/FileSpec.h @@ -530,6 +530,45 @@ public: lldb::DataBufferSP MemoryMapFileContents (off_t offset = 0, size_t length = SIZE_MAX) const; + + //------------------------------------------------------------------ + /// Memory map part of, or the entire contents of, a file only if + /// the file is local (not on a network mount). + /// + /// Returns a shared pointer to a data buffer that contains all or + /// part of the contents of a file. The data will be memory mapped + /// if the file is local and will lazily page in data from the file + /// as memory is accessed. If the data is memory mapped, the data + /// that is mapped will start \a offset bytes into the file, and + /// \a length bytes will be mapped. If \a length is + /// greater than the number of bytes available in the file starting + /// at \a offset, the number of bytes will be appropriately + /// truncated. The final number of bytes that get mapped can be + /// verified using the DataBuffer::GetByteSize() function on the return + /// shared data pointer object contents. + /// + /// If the file is on a network mount the data will be read into a + /// heap buffer immediately so that accesses to the data won't later + /// cause a crash if we touch a page that isn't paged in and the + /// network mount has been disconnected or gone away. + /// + /// @param[in] offset + /// The offset in bytes from the beginning of the file where + /// memory mapping should begin. + /// + /// @param[in] length + /// The size in bytes that should be mapped starting \a offset + /// bytes into the file. If \a length is \c SIZE_MAX, map + /// as many bytes as possible. + /// + /// @return + /// A shared pointer to the memory mapped data. This shared + /// pointer can contain a NULL DataBuffer pointer, so the contained + /// pointer must be checked prior to using it. + //------------------------------------------------------------------ + lldb::DataBufferSP + MemoryMapFileContentsIfLocal(off_t file_offset, size_t file_size) const; + //------------------------------------------------------------------ /// Read part of, or the entire contents of, a file into a heap based data buffer. /// diff --git a/lldb/include/lldb/Host/FileSystem.h b/lldb/include/lldb/Host/FileSystem.h index ddf82b3666e4..2120ffa8553f 100644 --- a/lldb/include/lldb/Host/FileSystem.h +++ b/lldb/include/lldb/Host/FileSystem.h @@ -38,6 +38,9 @@ class FileSystem static bool CalculateMD5(const FileSpec &file_spec, uint64_t &low, uint64_t &high); static bool CalculateMD5AsString(const FileSpec &file_spec, std::string& digest_str); + + /// Return \b true if \a spec is on a locally mounted file system, \b false otherwise. + static bool IsLocal(const FileSpec &spec); }; } diff --git a/lldb/source/Host/common/FileSpec.cpp b/lldb/source/Host/common/FileSpec.cpp index 6a6de53cd311..19f3b93f087a 100644 --- a/lldb/source/Host/common/FileSpec.cpp +++ b/lldb/source/Host/common/FileSpec.cpp @@ -852,6 +852,15 @@ FileSpec::MemoryMapFileContents(off_t file_offset, size_t file_size) const return data_sp; } +DataBufferSP +FileSpec::MemoryMapFileContentsIfLocal(off_t file_offset, size_t file_size) const +{ + if (FileSystem::IsLocal(*this)) + return MemoryMapFileContents(file_offset, file_size); + else + return ReadFileContents(file_offset, file_size, NULL); +} + //------------------------------------------------------------------ // Return the size in bytes that this object takes in memory. This diff --git a/lldb/source/Host/posix/FileSystem.cpp b/lldb/source/Host/posix/FileSystem.cpp index b55b01b45691..b8a455727ae5 100644 --- a/lldb/source/Host/posix/FileSystem.cpp +++ b/lldb/source/Host/posix/FileSystem.cpp @@ -10,6 +10,8 @@ #include "lldb/Host/FileSystem.h" // C includes +#include +#include #include #include @@ -172,3 +174,13 @@ FileSystem::Readlink(const char *path, char *buf, size_t buf_len) error.SetErrorString("'buf' buffer is too small to contain link contents"); return error; } + +bool +FileSystem::IsLocal(const FileSpec &spec) +{ + struct statfs statfs_info; + std::string path (spec.GetPath()); + if (statfs(path.c_str(), &statfs_info) == 0) + return (statfs_info.f_flags & MNT_LOCAL) != 0; + return false; +} diff --git a/lldb/source/Host/windows/FileSystem.cpp b/lldb/source/Host/windows/FileSystem.cpp index a58ddef13adc..f1926357b552 100644 --- a/lldb/source/Host/windows/FileSystem.cpp +++ b/lldb/source/Host/windows/FileSystem.cpp @@ -138,3 +138,15 @@ FileSystem::Readlink(const char *path, char *buf, size_t buf_len) ::CloseHandle(h); return error; } + +bool +FileSystem::IsLocal(const FileSpec &spec) +{ + if (spec) + { + // TODO: return true if the file is on a locally mounted file system + return true; + } + + return false; +} diff --git a/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp b/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp index 1e2a0c721ff6..87bf75321ed7 100644 --- a/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp +++ b/lldb/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp @@ -364,7 +364,7 @@ ObjectContainerBSDArchive::CreateInstance // Map the entire .a file to be sure that we don't lose any data if the file // gets updated by a new build while this .a file is being used for debugging - DataBufferSP archive_data_sp (file->MemoryMapFileContents(file_offset, length)); + DataBufferSP archive_data_sp (file->MemoryMapFileContentsIfLocal(file_offset, length)); lldb::offset_t archive_data_offset = 0; Archive::shared_ptr archive_sp (Archive::FindCachedArchive (*file, @@ -570,7 +570,7 @@ ObjectContainerBSDArchive::GetModuleSpecifications (const lldb_private::FileSpec if (!archive_sp) { set_archive_arch = true; - DataBufferSP data_sp (file.MemoryMapFileContents(file_offset, file_size)); + DataBufferSP data_sp (file.MemoryMapFileContentsIfLocal(file_offset, file_size)); data.SetData (data_sp, 0, data_sp->GetByteSize()); archive_sp = Archive::ParseAndCacheArchiveForFile(file, ArchSpec(), file_mod_time, file_offset, data); } diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp index bf466c7ee9bf..1b49aab0df16 100644 --- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp +++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp @@ -365,7 +365,7 @@ ObjectFileELF::CreateInstance (const lldb::ModuleSP &module_sp, { if (!data_sp) { - data_sp = file->MemoryMapFileContents(file_offset, length); + data_sp = file->MemoryMapFileContentsIfLocal(file_offset, length); data_offset = 0; } @@ -376,7 +376,7 @@ ObjectFileELF::CreateInstance (const lldb::ModuleSP &module_sp, { // Update the data to contain the entire file if it doesn't already if (data_sp->GetByteSize() < length) { - data_sp = file->MemoryMapFileContents(file_offset, length); + data_sp = file->MemoryMapFileContentsIfLocal(file_offset, length); data_offset = 0; magic = data_sp->GetBytes(); } @@ -636,7 +636,7 @@ ObjectFileELF::GetModuleSpecifications (const lldb_private::FileSpec& file, size_t section_header_end = header.e_shoff + header.e_shnum * header.e_shentsize; if (section_header_end > data_sp->GetByteSize()) { - data_sp = file.MemoryMapFileContents (file_offset, section_header_end); + data_sp = file.MemoryMapFileContentsIfLocal (file_offset, section_header_end); data.SetData(data_sp); } @@ -678,7 +678,7 @@ ObjectFileELF::GetModuleSpecifications (const lldb_private::FileSpec& file, size_t program_headers_end = header.e_phoff + header.e_phnum * header.e_phentsize; if (program_headers_end > data_sp->GetByteSize()) { - data_sp = file.MemoryMapFileContents(file_offset, program_headers_end); + data_sp = file.MemoryMapFileContentsIfLocal(file_offset, program_headers_end); data.SetData(data_sp); } ProgramHeaderColl program_headers; @@ -693,7 +693,7 @@ ObjectFileELF::GetModuleSpecifications (const lldb_private::FileSpec& file, if (segment_data_end > data_sp->GetByteSize()) { - data_sp = file.MemoryMapFileContents(file_offset, segment_data_end); + data_sp = file.MemoryMapFileContentsIfLocal(file_offset, segment_data_end); data.SetData(data_sp); } @@ -702,7 +702,7 @@ ObjectFileELF::GetModuleSpecifications (const lldb_private::FileSpec& file, else { // Need to map entire file into memory to calculate the crc. - data_sp = file.MemoryMapFileContents (file_offset, SIZE_MAX); + data_sp = file.MemoryMapFileContentsIfLocal (file_offset, SIZE_MAX); data.SetData(data_sp); gnu_debuglink_crc = calc_gnu_debuglink_crc32 (data.GetDataStart(), data.GetByteSize()); } diff --git a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp index ec14450c4b8f..7b49daa59ab9 100644 --- a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp +++ b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp @@ -931,7 +931,7 @@ ObjectFileMachO::CreateInstance (const lldb::ModuleSP &module_sp, { if (!data_sp) { - data_sp = file->MemoryMapFileContents(file_offset, length); + data_sp = file->MemoryMapFileContentsIfLocal(file_offset, length); data_offset = 0; } @@ -940,7 +940,7 @@ ObjectFileMachO::CreateInstance (const lldb::ModuleSP &module_sp, // Update the data to contain the entire file if it doesn't already if (data_sp->GetByteSize() < length) { - data_sp = file->MemoryMapFileContents(file_offset, length); + data_sp = file->MemoryMapFileContentsIfLocal(file_offset, length); data_offset = 0; } std::unique_ptr objfile_ap(new ObjectFileMachO (module_sp, data_sp, data_offset, file, file_offset, length)); @@ -2650,7 +2650,7 @@ ObjectFileMachO::ParseSymtab () // Save some VM space, do not map the entire cache in one shot. DataBufferSP dsc_data_sp; - dsc_data_sp = dsc_filespec.MemoryMapFileContents(0, sizeof(struct lldb_copy_dyld_cache_header_v1)); + dsc_data_sp = dsc_filespec.MemoryMapFileContentsIfLocal(0, sizeof(struct lldb_copy_dyld_cache_header_v1)); if (dsc_data_sp) { @@ -2704,7 +2704,7 @@ ObjectFileMachO::ParseSymtab () if (uuid_match && mappingOffset >= sizeof(struct lldb_copy_dyld_cache_header_v0)) { - DataBufferSP dsc_mapping_info_data_sp = dsc_filespec.MemoryMapFileContents(mappingOffset, sizeof (struct lldb_copy_dyld_cache_mapping_info)); + DataBufferSP dsc_mapping_info_data_sp = dsc_filespec.MemoryMapFileContentsIfLocal(mappingOffset, sizeof (struct lldb_copy_dyld_cache_mapping_info)); DataExtractor dsc_mapping_info_data(dsc_mapping_info_data_sp, byte_order, addr_byte_size); offset = 0; @@ -2721,7 +2721,7 @@ ObjectFileMachO::ParseSymtab () if (localSymbolsOffset && localSymbolsSize) { // Map the local symbols - if (DataBufferSP dsc_local_symbols_data_sp = dsc_filespec.MemoryMapFileContents(localSymbolsOffset, localSymbolsSize)) + if (DataBufferSP dsc_local_symbols_data_sp = dsc_filespec.MemoryMapFileContentsIfLocal(localSymbolsOffset, localSymbolsSize)) { DataExtractor dsc_local_symbols_data(dsc_local_symbols_data_sp, byte_order, addr_byte_size); diff --git a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp index 6defd643a43b..5f7935e1275f 100644 --- a/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp +++ b/lldb/source/Plugins/ObjectFile/PECOFF/ObjectFilePECOFF.cpp @@ -76,7 +76,7 @@ ObjectFilePECOFF::CreateInstance (const lldb::ModuleSP &module_sp, { if (!data_sp) { - data_sp = file->MemoryMapFileContents(file_offset, length); + data_sp = file->MemoryMapFileContentsIfLocal(file_offset, length); data_offset = 0; } @@ -84,7 +84,7 @@ ObjectFilePECOFF::CreateInstance (const lldb::ModuleSP &module_sp, { // Update the data to contain the entire file if it doesn't already if (data_sp->GetByteSize() < length) - data_sp = file->MemoryMapFileContents(file_offset, length); + data_sp = file->MemoryMapFileContentsIfLocal(file_offset, length); std::unique_ptr objfile_ap(new ObjectFilePECOFF (module_sp, data_sp, data_offset, file, file_offset, length)); if (objfile_ap.get() && objfile_ap->ParseHeader()) return objfile_ap.release();