aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/lldb/source/Core/SourceManager.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2023-09-02 21:17:18 +0000
committerDimitry Andric <dim@FreeBSD.org>2023-12-08 17:34:50 +0000
commit06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e (patch)
tree62f873df87c7c675557a179e0c4c83fe9f3087bc /contrib/llvm-project/lldb/source/Core/SourceManager.cpp
parentcf037972ea8863e2bab7461d77345367d2c1e054 (diff)
parent7fa27ce4a07f19b07799a767fc29416f3b625afb (diff)
Diffstat (limited to 'contrib/llvm-project/lldb/source/Core/SourceManager.cpp')
-rw-r--r--contrib/llvm-project/lldb/source/Core/SourceManager.cpp241
1 files changed, 170 insertions, 71 deletions
diff --git a/contrib/llvm-project/lldb/source/Core/SourceManager.cpp b/contrib/llvm-project/lldb/source/Core/SourceManager.cpp
index 72fabb42507c..517a4b0268d2 100644
--- a/contrib/llvm-project/lldb/source/Core/SourceManager.cpp
+++ b/contrib/llvm-project/lldb/source/Core/SourceManager.cpp
@@ -21,10 +21,13 @@
#include "lldb/Symbol/LineEntry.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Target/PathMappingList.h"
+#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
#include "lldb/Utility/AnsiTerminal.h"
#include "lldb/Utility/ConstString.h"
#include "lldb/Utility/DataBuffer.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
#include "lldb/Utility/RegularExpression.h"
#include "lldb/Utility/Stream.h"
#include "lldb/lldb-enumerations.h"
@@ -73,39 +76,89 @@ SourceManager::~SourceManager() = default;
SourceManager::FileSP SourceManager::GetFile(const FileSpec &file_spec) {
if (!file_spec)
- return nullptr;
+ return {};
- FileSpec resolved_fspec = file_spec;
- resolve_tilde(resolved_fspec);
+ Log *log = GetLog(LLDBLog::Source);
DebuggerSP debugger_sp(m_debugger_wp.lock());
- FileSP file_sp;
- if (debugger_sp && debugger_sp->GetUseSourceCache())
- file_sp = debugger_sp->GetSourceFileCache().FindSourceFile(resolved_fspec);
-
TargetSP target_sp(m_target_wp.lock());
- // It the target source path map has been updated, get this file again so we
- // can successfully remap the source file
- if (target_sp && file_sp &&
- file_sp->GetSourceMapModificationID() !=
- target_sp->GetSourcePathMap().GetModificationID())
- file_sp.reset();
+ if (!debugger_sp || !debugger_sp->GetUseSourceCache()) {
+ LLDB_LOG(log, "Source file caching disabled: creating new source file: {0}",
+ file_spec);
+ if (target_sp)
+ return std::make_shared<File>(file_spec, target_sp);
+ return std::make_shared<File>(file_spec, debugger_sp);
+ }
- // Update the file contents if needed if we found a file
+ ProcessSP process_sp = target_sp ? target_sp->GetProcessSP() : ProcessSP();
+
+ // Check the process source cache first. This is the fast path which avoids
+ // touching the file system unless the path remapping has changed.
+ if (process_sp) {
+ if (FileSP file_sp =
+ process_sp->GetSourceFileCache().FindSourceFile(file_spec)) {
+ LLDB_LOG(log, "Found source file in the process cache: {0}", file_spec);
+ if (file_sp->PathRemappingIsStale()) {
+ LLDB_LOG(log, "Path remapping is stale: removing file from caches: {0}",
+ file_spec);
+
+ // Remove the file from the debugger and process cache. Otherwise we'll
+ // hit the same issue again below when querying the debugger cache.
+ debugger_sp->GetSourceFileCache().RemoveSourceFile(file_sp);
+ process_sp->GetSourceFileCache().RemoveSourceFile(file_sp);
+
+ file_sp.reset();
+ } else {
+ return file_sp;
+ }
+ }
+ }
+
+ // Cache miss in the process cache. Check the debugger source cache.
+ FileSP file_sp = debugger_sp->GetSourceFileCache().FindSourceFile(file_spec);
+
+ // We found the file in the debugger cache. Check if anything invalidated our
+ // cache result.
if (file_sp)
- file_sp->UpdateIfNeeded();
+ LLDB_LOG(log, "Found source file in the debugger cache: {0}", file_spec);
+
+ // Check if the path remapping has changed.
+ if (file_sp && file_sp->PathRemappingIsStale()) {
+ LLDB_LOG(log, "Path remapping is stale: {0}", file_spec);
+ file_sp.reset();
+ }
- // If file_sp is no good or it points to a non-existent file, reset it.
- if (!file_sp || !FileSystem::Instance().Exists(file_sp->GetFileSpec())) {
+ // Check if the modification time has changed.
+ if (file_sp && file_sp->ModificationTimeIsStale()) {
+ LLDB_LOG(log, "Modification time is stale: {0}", file_spec);
+ file_sp.reset();
+ }
+
+ // Check if the file exists on disk.
+ if (file_sp && !FileSystem::Instance().Exists(file_sp->GetFileSpec())) {
+ LLDB_LOG(log, "File doesn't exist on disk: {0}", file_spec);
+ file_sp.reset();
+ }
+
+ // If at this point we don't have a valid file, it means we either didn't find
+ // it in the debugger cache or something caused it to be invalidated.
+ if (!file_sp) {
+ LLDB_LOG(log, "Creating and caching new source file: {0}", file_spec);
+
+ // (Re)create the file.
if (target_sp)
- file_sp = std::make_shared<File>(resolved_fspec, target_sp.get());
+ file_sp = std::make_shared<File>(file_spec, target_sp);
else
- file_sp = std::make_shared<File>(resolved_fspec, debugger_sp);
+ file_sp = std::make_shared<File>(file_spec, debugger_sp);
- if (debugger_sp && debugger_sp->GetUseSourceCache())
- debugger_sp->GetSourceFileCache().AddSourceFile(file_sp);
+ // Add the file to the debugger and process cache. If the file was
+ // invalidated, this will overwrite it.
+ debugger_sp->GetSourceFileCache().AddSourceFile(file_spec, file_sp);
+ if (process_sp)
+ process_sp->GetSourceFileCache().AddSourceFile(file_spec, file_sp);
}
+
return file_sp;
}
@@ -205,7 +258,8 @@ size_t SourceManager::DisplaySourceLinesWithLineNumbersUsingLastFile(
}
char buffer[3];
- sprintf(buffer, "%2.2s", (line == curr_line) ? current_line_cstr : "");
+ snprintf(buffer, sizeof(buffer), "%2.2s",
+ (line == curr_line) ? current_line_cstr : "");
std::string current_line_highlight(buffer);
auto debugger_sp = m_debugger_wp.lock();
@@ -358,10 +412,7 @@ bool SourceManager::GetDefaultFileAndLine(FileSpec &file_spec, uint32_t &line) {
executable_ptr->FindFunctions(main_name, CompilerDeclContext(),
lldb::eFunctionNameTypeBase,
function_options, sc_list);
- size_t num_matches = sc_list.GetSize();
- for (size_t idx = 0; idx < num_matches; idx++) {
- SymbolContext sc;
- sc_list.GetContextAtIndex(idx, sc);
+ for (const SymbolContext &sc : sc_list) {
if (sc.function) {
lldb_private::LineEntry line_entry;
if (sc.function->GetAddressRange()
@@ -395,33 +446,37 @@ void SourceManager::FindLinesMatchingRegex(FileSpec &file_spec,
SourceManager::File::File(const FileSpec &file_spec,
lldb::DebuggerSP debugger_sp)
- : m_file_spec_orig(file_spec), m_file_spec(file_spec),
- m_mod_time(FileSystem::Instance().GetModificationTime(file_spec)),
- m_debugger_wp(debugger_sp) {
- CommonInitializer(file_spec, nullptr);
+ : m_file_spec_orig(file_spec), m_file_spec(), m_mod_time(),
+ m_debugger_wp(debugger_sp), m_target_wp(TargetSP()) {
+ CommonInitializer(file_spec, {});
}
-SourceManager::File::File(const FileSpec &file_spec, Target *target)
- : m_file_spec_orig(file_spec), m_file_spec(file_spec),
- m_mod_time(FileSystem::Instance().GetModificationTime(file_spec)),
- m_debugger_wp(target ? target->GetDebugger().shared_from_this()
- : DebuggerSP()) {
- CommonInitializer(file_spec, target);
+SourceManager::File::File(const FileSpec &file_spec, TargetSP target_sp)
+ : m_file_spec_orig(file_spec), m_file_spec(), m_mod_time(),
+ m_debugger_wp(target_sp ? target_sp->GetDebugger().shared_from_this()
+ : DebuggerSP()),
+ m_target_wp(target_sp) {
+ CommonInitializer(file_spec, target_sp);
}
void SourceManager::File::CommonInitializer(const FileSpec &file_spec,
- Target *target) {
- if (m_mod_time == llvm::sys::TimePoint<>()) {
- if (target) {
- m_source_map_mod_id = target->GetSourcePathMap().GetModificationID();
+ TargetSP target_sp) {
+ // Set the file and update the modification time.
+ SetFileSpec(file_spec);
+
+ // Always update the source map modification ID if we have a target.
+ if (target_sp)
+ m_source_map_mod_id = target_sp->GetSourcePathMap().GetModificationID();
+ // File doesn't exist.
+ if (m_mod_time == llvm::sys::TimePoint<>()) {
+ if (target_sp) {
+ // If this is just a file name, try finding it in the target.
if (!file_spec.GetDirectory() && file_spec.GetFilename()) {
- // If this is just a file name, lets see if we can find it in the
- // target:
bool check_inlines = false;
SymbolContextList sc_list;
size_t num_matches =
- target->GetImages().ResolveSymbolContextForFilePath(
+ target_sp->GetImages().ResolveSymbolContextForFilePath(
file_spec.GetFilename().AsCString(), 0, check_inlines,
SymbolContextItem(eSymbolContextModule |
eSymbolContextCompUnit),
@@ -429,11 +484,8 @@ void SourceManager::File::CommonInitializer(const FileSpec &file_spec,
bool got_multiple = false;
if (num_matches != 0) {
if (num_matches > 1) {
- SymbolContext sc;
CompileUnit *test_cu = nullptr;
-
- for (unsigned i = 0; i < num_matches; i++) {
- sc_list.GetContextAtIndex(i, sc);
+ for (const SymbolContext &sc : sc_list) {
if (sc.comp_unit) {
if (test_cu) {
if (test_cu != sc.comp_unit)
@@ -448,35 +500,39 @@ void SourceManager::File::CommonInitializer(const FileSpec &file_spec,
SymbolContext sc;
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);
+ SetFileSpec(sc.comp_unit->GetPrimaryFile());
}
}
}
- resolve_tilde(m_file_spec);
- // Try remapping if m_file_spec does not correspond to an existing file.
+
+ // Try remapping the file if it doesn't exist.
if (!FileSystem::Instance().Exists(m_file_spec)) {
// Check target specific source remappings (i.e., the
// target.source-map setting), then fall back to the module
// specific remapping (i.e., the .dSYM remapping dictionary).
- auto remapped = target->GetSourcePathMap().FindFile(m_file_spec);
+ auto remapped = target_sp->GetSourcePathMap().FindFile(m_file_spec);
if (!remapped) {
FileSpec new_spec;
- if (target->GetImages().FindSourceFile(m_file_spec, new_spec))
+ if (target_sp->GetImages().FindSourceFile(m_file_spec, new_spec))
remapped = new_spec;
}
- if (remapped) {
- m_file_spec = *remapped;
- m_mod_time = FileSystem::Instance().GetModificationTime(m_file_spec);
- }
+ if (remapped)
+ SetFileSpec(*remapped);
}
}
}
+ // If the file exists, read in the data.
if (m_mod_time != llvm::sys::TimePoint<>())
m_data_sp = FileSystem::Instance().CreateDataBuffer(m_file_spec);
}
+void SourceManager::File::SetFileSpec(FileSpec file_spec) {
+ resolve_tilde(file_spec);
+ m_file_spec = std::move(file_spec);
+ m_mod_time = FileSystem::Instance().GetModificationTime(m_file_spec);
+}
+
uint32_t SourceManager::File::GetLineOffset(uint32_t line) {
if (line == 0)
return UINT32_MAX;
@@ -543,18 +599,20 @@ bool SourceManager::File::LineIsValid(uint32_t line) {
return false;
}
-void SourceManager::File::UpdateIfNeeded() {
+bool SourceManager::File::ModificationTimeIsStale() const {
// TODO: use host API to sign up for file modifications to anything in our
// source cache and only update when we determine a file has been updated.
// For now we check each time we want to display info for the file.
auto curr_mod_time = FileSystem::Instance().GetModificationTime(m_file_spec);
+ return curr_mod_time != llvm::sys::TimePoint<>() &&
+ m_mod_time != curr_mod_time;
+}
- 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();
- }
+bool SourceManager::File::PathRemappingIsStale() const {
+ if (TargetSP target_sp = m_target_wp.lock())
+ return GetSourceMapModificationID() !=
+ target_sp->GetSourcePathMap().GetModificationID();
+ return false;
}
size_t SourceManager::File::DisplaySourceLines(uint32_t line,
@@ -713,12 +771,40 @@ bool SourceManager::File::GetLine(uint32_t line_no, std::string &buffer) {
return true;
}
-void SourceManager::SourceFileCache::AddSourceFile(const FileSP &file_sp) {
- FileSpec file_spec = file_sp->GetFileSpec();
+void SourceManager::SourceFileCache::AddSourceFile(const FileSpec &file_spec,
+ FileSP file_sp) {
+ llvm::sys::ScopedWriter guard(m_mutex);
+
+ assert(file_sp && "invalid FileSP");
+
+ AddSourceFileImpl(file_spec, file_sp);
+ const FileSpec &resolved_file_spec = file_sp->GetFileSpec();
+ if (file_spec != resolved_file_spec)
+ AddSourceFileImpl(file_sp->GetFileSpec(), file_sp);
+}
+
+void SourceManager::SourceFileCache::RemoveSourceFile(const FileSP &file_sp) {
+ llvm::sys::ScopedWriter guard(m_mutex);
+
+ assert(file_sp && "invalid FileSP");
+
+ // Iterate over all the elements in the cache.
+ // This is expensive but a relatively uncommon operation.
+ auto it = m_file_cache.begin();
+ while (it != m_file_cache.end()) {
+ if (it->second == file_sp)
+ it = m_file_cache.erase(it);
+ else
+ it++;
+ }
+}
+
+void SourceManager::SourceFileCache::AddSourceFileImpl(
+ const FileSpec &file_spec, FileSP file_sp) {
FileCache::iterator pos = m_file_cache.find(file_spec);
- if (pos == m_file_cache.end())
+ if (pos == m_file_cache.end()) {
m_file_cache[file_spec] = file_sp;
- else {
+ } else {
if (file_sp != pos->second)
m_file_cache[file_spec] = file_sp;
}
@@ -726,9 +812,22 @@ void SourceManager::SourceFileCache::AddSourceFile(const FileSP &file_sp) {
SourceManager::FileSP SourceManager::SourceFileCache::FindSourceFile(
const FileSpec &file_spec) const {
- FileSP file_sp;
+ llvm::sys::ScopedReader guard(m_mutex);
+
FileCache::const_iterator pos = m_file_cache.find(file_spec);
if (pos != m_file_cache.end())
- file_sp = pos->second;
- return file_sp;
+ return pos->second;
+ return {};
+}
+
+void SourceManager::SourceFileCache::Dump(Stream &stream) const {
+ stream << "Modification time Lines Path\n";
+ stream << "------------------- -------- --------------------------------\n";
+ for (auto &entry : m_file_cache) {
+ if (!entry.second)
+ continue;
+ FileSP file = entry.second;
+ stream.Format("{0:%Y-%m-%d %H:%M:%S} {1,8:d} {2}\n", file->GetTimestamp(),
+ file->GetNumLines(), entry.first.GetPath());
+ }
}