diff --git a/lldb/include/lldb/Core/Section.h b/lldb/include/lldb/Core/Section.h --- a/lldb/include/lldb/Core/Section.h +++ b/lldb/include/lldb/Core/Section.h @@ -236,6 +236,8 @@ void SetIsRelocated(bool b) { m_relocated = b; } + bool IsReadOnly(); + protected: ObjectFile *m_obj_file; // The object file that data for this section should // be read from diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h --- a/lldb/include/lldb/Target/Target.h +++ b/lldb/include/lldb/Target/Target.h @@ -229,6 +229,10 @@ bool GetDebugUtilityExpression() const; + void SetVerifyFileCacheMemoryReads(bool debug); + + bool GetVerifyFileCacheMemoryReads() const; + private: // Callbacks for m_launch_info. void Arg0ValueChangedCallback(); diff --git a/lldb/source/Core/Section.cpp b/lldb/source/Core/Section.cpp --- a/lldb/source/Core/Section.cpp +++ b/lldb/source/Core/Section.cpp @@ -599,3 +599,9 @@ } return count; } + +bool Section::IsReadOnly() { + auto permissions = Flags(GetPermissions()); + return !permissions.Test(ePermissionsWritable) && + permissions.Test(ePermissionsReadable); +} diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -1761,21 +1761,34 @@ // Read from file cache if read-only section. if (!force_live_memory && resolved_addr.IsSectionOffset()) { SectionSP section_sp(resolved_addr.GetSection()); - if (section_sp) { - auto permissions = Flags(section_sp->GetPermissions()); - bool is_readonly = !permissions.Test(ePermissionsWritable) && - permissions.Test(ePermissionsReadable); - if (is_readonly) { - file_cache_bytes_read = - ReadMemoryFromFileCache(resolved_addr, dst, dst_len, error); - if (file_cache_bytes_read == dst_len) - return file_cache_bytes_read; - else if (file_cache_bytes_read > 0) { - file_cache_read_buffer = - std::make_unique(file_cache_bytes_read); - std::memcpy(file_cache_read_buffer.get(), dst, file_cache_bytes_read); + if (section_sp && section_sp->IsReadOnly()) { + file_cache_bytes_read = + ReadMemoryFromFileCache(resolved_addr, dst, dst_len, error); + + if (GetVerifyFileCacheMemoryReads()) { + if (ProcessIsValid() && file_cache_bytes_read == dst_len) { + if (load_addr == LLDB_INVALID_ADDRESS) + load_addr = resolved_addr.GetLoadAddress(this); + if (load_addr != LLDB_INVALID_ADDRESS) { + uint8_t *live_buf = (uint8_t *)malloc(dst_len); + bytes_read = + m_process_sp->ReadMemory(load_addr, live_buf, dst_len, error); + if (bytes_read == dst_len) { + lldbassert(memcmp(live_buf, dst, dst_len) == 0 && + "File cache and live memory diverge!"); + } + free(live_buf); + } } } + + if (file_cache_bytes_read == dst_len) + return file_cache_bytes_read; + if (file_cache_bytes_read > 0) { + file_cache_read_buffer = + std::make_unique(file_cache_bytes_read); + std::memcpy(file_cache_read_buffer.get(), dst, file_cache_bytes_read); + } } } @@ -4368,6 +4381,17 @@ m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, debug); } +bool TargetProperties::GetVerifyFileCacheMemoryReads() const { + const uint32_t idx = ePropertyVerifyFileCacheMemoryReads; + return m_collection_sp->GetPropertyAtIndexAsBoolean( + nullptr, idx, g_target_properties[idx].default_uint_value != 0); +} + +void TargetProperties::SetVerifyFileCacheMemoryReads(bool verify) { + const uint32_t idx = ePropertyVerifyFileCacheMemoryReads; + m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, verify); +} + // Target::TargetEventData Target::TargetEventData::TargetEventData(const lldb::TargetSP &target_sp) diff --git a/lldb/source/Target/TargetProperties.td b/lldb/source/Target/TargetProperties.td --- a/lldb/source/Target/TargetProperties.td +++ b/lldb/source/Target/TargetProperties.td @@ -175,6 +175,9 @@ def DebugUtilityExpression: Property<"debug-utility-expression", "Boolean">, DefaultFalse, Desc<"Enable debugging of LLDB-internal utility expressions.">; + def VerifyFileCacheMemoryReads: Property<"verify-file-cache-memory-reads", "Boolean">, + DefaultFalse, + Desc<"Verify that memory read from the file-cache is identical to the memory read from the process.">; } let Definition = "process_experimental" in {