diff --git a/lldb/include/lldb/Core/SourceManager.h b/lldb/include/lldb/Core/SourceManager.h --- a/lldb/include/lldb/Core/SourceManager.h +++ b/lldb/include/lldb/Core/SourceManager.h @@ -86,6 +86,10 @@ private: void CommonInitializer(const FileSpec &file_spec, Target *target); + + bool IsCurrentModuleAndNewer(llvm::sys::TimePoint<> time); + bool IsNewerThanItsModule(llvm::sys::TimePoint<> time); + void Update(llvm::sys::TimePoint<> mod_time); }; typedef std::shared_ptr FileSP; diff --git a/lldb/source/Core/SourceManager.cpp b/lldb/source/Core/SourceManager.cpp --- a/lldb/source/Core/SourceManager.cpp +++ b/lldb/source/Core/SourceManager.cpp @@ -21,7 +21,10 @@ #include "lldb/Symbol/LineEntry.h" #include "lldb/Symbol/SymbolContext.h" #include "lldb/Target/PathMappingList.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/StackFrame.h" #include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" #include "lldb/Utility/AnsiTerminal.h" #include "lldb/Utility/ConstString.h" #include "lldb/Utility/DataBuffer.h" @@ -30,6 +33,8 @@ #include "lldb/Utility/Stream.h" #include "lldb/lldb-enumerations.h" +#include "lldb/Utility/Log.h" + #include "llvm/ADT/Twine.h" #include @@ -436,7 +441,8 @@ sc_list.GetContextAtIndex(0, sc); if (sc.comp_unit) m_file_spec = sc.comp_unit->GetPrimaryFile(); - m_mod_time = FileSystem::Instance().GetModificationTime(m_file_spec); + m_mod_time = + FileSystem::Instance().GetModificationTime(m_file_spec); } } } @@ -531,12 +537,107 @@ // For now we check each time we want to display info for the file. auto curr_mod_time = FileSystem::Instance().GetModificationTime(m_file_spec); + // If the source file is newer than the module don't update, + // otherwise the source file being displayed will be different from + // the module being ran. + // (We only want to update if the module has been recompiled) + if (IsCurrentModuleAndNewer(curr_mod_time) || + IsNewerThanItsModule(curr_mod_time)) + // TODO: maybe issue a: + // 'warning: Source file is more recent than executable.' ? + return; + if (curr_mod_time != llvm::sys::TimePoint<>() && m_mod_time != curr_mod_time) { - m_mod_time = curr_mod_time; - m_data_sp = FileSystem::Instance().CreateDataBuffer(m_file_spec); - m_offsets.clear(); + Update(curr_mod_time); + } +} + +bool SourceManager::File::IsCurrentModuleAndNewer(llvm::sys::TimePoint<> time) { + DebuggerSP debugger_sp(m_debugger_wp.lock()); + if (!debugger_sp) + return false; + + lldb::TargetSP target_sp(debugger_sp->GetSelectedTarget()); + if (!target_sp) + return false; + + lldb::ProcessSP process_sp(target_sp->CalculateProcess()); + if (!process_sp) + return false; + + ThreadList &thread_list(process_sp->GetThreadList()); + + lldb::ThreadSP thread_sp(thread_list.GetSelectedThread()); + if (!thread_sp) + return false; + + lldb::StackFrameSP stackframe_sp(thread_sp->GetSelectedFrame()); + if (!stackframe_sp) + return false; + + const Address pc_addr(stackframe_sp->GetFrameCodeAddress()); + + lldb::ModuleSP current_module(pc_addr.GetModule()); + if (!current_module) + return false; + + SymbolContextList sc_list; + auto num_matches = current_module->ResolveSymbolContextsForFileSpec( + m_file_spec, 0, false, eSymbolContextModule | eSymbolContextCompUnit, + sc_list); + + if (!num_matches) + return false; + + // FIXME: We need to get the timestamp from the filesystem because the Module + // doesn't properly update its m_mod_time. + auto current_module_mod_time = + FileSystem::Instance().GetModificationTime(current_module->GetFileSpec()); + + return time > current_module_mod_time; +} + +bool SourceManager::File::IsNewerThanItsModule(llvm::sys::TimePoint<> time) { + DebuggerSP debugger_sp(m_debugger_wp.lock()); + if (!debugger_sp) + return false; + + lldb::TargetSP target_sp(debugger_sp->GetSelectedTarget()); + if (!target_sp) + return false; + + SymbolContextList sc_list; + auto num_matches = target_sp->GetImages().ResolveSymbolContextsForFileSpec( + m_file_spec, 0, false, eSymbolContextModule | eSymbolContextCompUnit, + sc_list); + + if (num_matches == 1) { + SymbolContext sc; + ModuleSP module_sp = nullptr; + + sc_list.GetContextAtIndex(0, sc); + module_sp = sc.module_sp; + + // FIXME: We need to get the timestamp from the filesystem because the + // Module doesn't properly update its m_mod_time. + auto module_mod_time = + FileSystem::Instance().GetModificationTime(module_sp->GetFileSpec()); + + if (module_sp) + return time > module_mod_time; } + + // TODO: if (num_matches > 1) warn multiple source files found matching + + // We can't determine if the file is newer because we can't find its module. + return false; +} + +void SourceManager::File::Update(llvm::sys::TimePoint<> modification_time) { + m_data_sp = FileSystem::Instance().CreateDataBuffer(m_file_spec); + m_offsets.clear(); + m_mod_time = modification_time; } size_t SourceManager::File::DisplaySourceLines(uint32_t line, @@ -696,7 +797,7 @@ } void SourceManager::SourceFileCache::AddSourceFile(const FileSP &file_sp) { - FileSpec file_spec; + FileSpec file_spec(file_sp ? file_sp->GetFileSpec() : FileSpec()); FileCache::iterator pos = m_file_cache.find(file_spec); if (pos == m_file_cache.end()) m_file_cache[file_spec] = file_sp; diff --git a/lldb/test/API/source-manager/TestSourceManager.py b/lldb/test/API/source-manager/TestSourceManager.py --- a/lldb/test/API/source-manager/TestSourceManager.py +++ b/lldb/test/API/source-manager/TestSourceManager.py @@ -230,12 +230,14 @@ "os.path.getmtime() after writing new content:", os.path.getmtime(self.file)) - # Display the source code again. We should see the updated line. + # Display the source code again. + # We should not see the updated line or there would be an incoherence + # with the module being ran. self.expect( "source list -f main-copy.c -l %d" % self.line, SOURCE_DISPLAYED_CORRECTLY, - substrs=['Hello lldb']) + substrs=['Hello world']) def test_set_breakpoint_with_absolute_path(self): self.build()