Skip to content

[lldb] Realpath symlinks for breakpoints #102223

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Aug 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion lldb/include/lldb/Symbol/CompileUnit.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@
#include "lldb/Utility/Stream.h"
#include "lldb/Utility/UserID.h"
#include "lldb/lldb-enumerations.h"
#include "lldb/lldb-forward.h"

#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"

namespace lldb_private {

/// \class CompileUnit CompileUnit.h "lldb/Symbol/CompileUnit.h"
/// A class that describes a compilation unit.
///
Expand Down Expand Up @@ -389,10 +391,15 @@ class CompileUnit : public std::enable_shared_from_this<CompileUnit>,
/// A SymbolContext list class that will get any matching
/// entries appended to.
///
/// \param[in] realpath_prefixes
/// Paths that start with one of the prefixes in this list will be
/// realpath'ed to resolve any symlinks.
///
/// \see enum SymbolContext::Scope
void ResolveSymbolContext(const SourceLocationSpec &src_location_spec,
lldb::SymbolContextItem resolve_scope,
SymbolContextList &sc_list);
SymbolContextList &sc_list,
RealpathPrefixes *realpath_prefixes = nullptr);

/// Get whether compiler optimizations were enabled for this compile unit
///
Expand Down
5 changes: 5 additions & 0 deletions lldb/include/lldb/Target/Statistics.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#define LLDB_TARGET_STATISTICS_H

#include "lldb/Utility/ConstString.h"
#include "lldb/Utility/RealpathPrefixes.h"
#include "lldb/Utility/Stream.h"
#include "lldb/lldb-forward.h"
#include "llvm/ADT/StringMap.h"
Expand Down Expand Up @@ -184,6 +185,8 @@ class TargetStats {
void SetFirstPrivateStopTime();
void SetFirstPublicStopTime();
void IncreaseSourceMapDeduceCount();
void IncreaseSourceRealpathAttemptCount(uint32_t count);
void IncreaseSourceRealpathCompatibleCount(uint32_t count);

StatsDuration &GetCreateTime() { return m_create_time; }
StatsSuccessFail &GetExpressionStats() { return m_expr_eval; }
Expand All @@ -198,6 +201,8 @@ class TargetStats {
StatsSuccessFail m_frame_var{"frameVariable"};
std::vector<intptr_t> m_module_identifiers;
uint32_t m_source_map_deduce_count = 0;
uint32_t m_source_realpath_attempt_count = 0;
uint32_t m_source_realpath_compatible_count = 0;
void CollectStats(Target &target);
};

Expand Down
3 changes: 3 additions & 0 deletions lldb/include/lldb/Target/Target.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include "lldb/Utility/ArchSpec.h"
#include "lldb/Utility/Broadcaster.h"
#include "lldb/Utility/LLDBAssert.h"
#include "lldb/Utility/RealpathPrefixes.h"
#include "lldb/Utility/Timeout.h"
#include "lldb/lldb-public.h"

Expand Down Expand Up @@ -117,6 +118,8 @@ class TargetProperties : public Properties {

InlineStrategy GetInlineStrategy() const;

RealpathPrefixes GetSourceRealpathPrefixes() const;

llvm::StringRef GetArg0() const;

void SetArg0(llvm::StringRef arg);
Expand Down
8 changes: 7 additions & 1 deletion lldb/include/lldb/Utility/FileSpecList.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,16 @@ class SupportFileList {
/// \param[in] file
/// The file specification to search for.
///
/// \param[in] realpath_prefixes
/// Paths that start with one of the prefixes in this list will be
/// realpath'ed to resolve any symlinks.
///
/// \return
/// The index of the file that matches \a file if it is found,
/// else UINT32_MAX is returned.
size_t FindCompatibleIndex(size_t idx, const FileSpec &file) const;
size_t
FindCompatibleIndex(size_t idx, const FileSpec &file,
RealpathPrefixes *realpath_prefixes = nullptr) const;

template <class... Args> void EmplaceBack(Args &&...args) {
m_files.push_back(
Expand Down
77 changes: 77 additions & 0 deletions lldb/include/lldb/Utility/RealpathPrefixes.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
//===-- RealpathPrefixes.h --------------------------------------*- C++ -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//

#ifndef LLDB_UTILITY_REALPATHPREFIXES_H
#define LLDB_UTILITY_REALPATHPREFIXES_H

#include "lldb/lldb-forward.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/Support/VirtualFileSystem.h"

#include <optional>
#include <string>
#include <vector>

namespace lldb_private {

class RealpathPrefixes {
public:
/// \param[in] file_spec_list
/// Prefixes are obtained from FileSpecList, through FileSpec::GetPath(),
/// which ensures that the paths are normalized. For example:
/// "./foo/.." -> ""
/// "./foo/../bar" -> "bar"
///
/// \param[in] fs
/// An optional filesystem to use for realpath'ing. If not set, the real
/// filesystem will be used.
explicit RealpathPrefixes(const FileSpecList &file_spec_list,
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs =
llvm::vfs::getRealFileSystem());

std::optional<FileSpec> ResolveSymlinks(const FileSpec &file_spec);

// If/when Statistics.h/cpp is moved into Utility, we can remove these
// methods, hold a (weak) pointer to `TargetStats` and directly increment
// on that object.
void IncreaseSourceRealpathAttemptCount() {
++m_source_realpath_attempt_count;
}
uint32_t GetSourceRealpathAttemptCount() const {
return m_source_realpath_attempt_count;
}
void IncreaseSourceRealpathCompatibleCount() {
++m_source_realpath_compatible_count;
}
uint32_t GetSourceRealpathCompatibleCount() const {
return m_source_realpath_compatible_count;
}

private:
// Paths that start with one of the prefixes in this list will be realpath'ed
// to resolve any symlinks.
//
// Wildcard prefixes:
// - "" (empty string) will match all paths.
// - "/" will match all absolute paths.
std::vector<std::string> m_prefixes;

// The filesystem to use for realpath'ing.
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> m_fs;

// The optional Target instance to gather statistics.
lldb::TargetWP m_target;

// Statistics that we temprarily hold here, to be gathered into TargetStats
uint32_t m_source_realpath_attempt_count = 0;
uint32_t m_source_realpath_compatible_count = 0;
};

} // namespace lldb_private

#endif // LLDB_UTILITY_REALPATHPREFIXES_H
1 change: 1 addition & 0 deletions lldb/include/lldb/lldb-forward.h
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ class Queue;
class QueueImpl;
class QueueItem;
class REPL;
class RealpathPrefixes;
class RecognizedStackFrame;
class RegisterCheckpoint;
class RegisterContext;
Expand Down
12 changes: 11 additions & 1 deletion lldb/source/Breakpoint/BreakpointResolverFileLine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "lldb/Target/Target.h"
#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/RealpathPrefixes.h"
#include "lldb/Utility/StreamString.h"
#include <optional>

Expand Down Expand Up @@ -290,16 +291,25 @@ Searcher::CallbackReturn BreakpointResolverFileLine::SearchCallback(
const uint32_t line = m_location_spec.GetLine().value_or(0);
const std::optional<uint16_t> column = m_location_spec.GetColumn();

Target &target = GetBreakpoint()->GetTarget();
RealpathPrefixes realpath_prefixes = target.GetSourceRealpathPrefixes();

const size_t num_comp_units = context.module_sp->GetNumCompileUnits();
for (size_t i = 0; i < num_comp_units; i++) {
CompUnitSP cu_sp(context.module_sp->GetCompileUnitAtIndex(i));
if (cu_sp) {
if (filter.CompUnitPasses(*cu_sp))
cu_sp->ResolveSymbolContext(m_location_spec, eSymbolContextEverything,
sc_list);
sc_list, &realpath_prefixes);
}
}

// Gather stats into the Target
target.GetStatistics().IncreaseSourceRealpathAttemptCount(
realpath_prefixes.GetSourceRealpathAttemptCount());
target.GetStatistics().IncreaseSourceRealpathCompatibleCount(
realpath_prefixes.GetSourceRealpathCompatibleCount());

FilterContexts(sc_list);

DeduceSourceMapping(sc_list);
Expand Down
14 changes: 8 additions & 6 deletions lldb/source/Symbol/CompileUnit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -213,11 +213,12 @@ VariableListSP CompileUnit::GetVariableList(bool can_create) {
return m_variables;
}

std::vector<uint32_t> FindFileIndexes(const SupportFileList &files,
const FileSpec &file) {
std::vector<uint32_t>
FindFileIndexes(const SupportFileList &files, const FileSpec &file,
RealpathPrefixes *realpath_prefixes = nullptr) {
std::vector<uint32_t> result;
uint32_t idx = -1;
while ((idx = files.FindCompatibleIndex(idx + 1, file)) !=
while ((idx = files.FindCompatibleIndex(idx + 1, file, realpath_prefixes)) !=
UINT32_MAX)
result.push_back(idx);
return result;
Expand Down Expand Up @@ -247,7 +248,8 @@ uint32_t CompileUnit::FindLineEntry(uint32_t start_idx, uint32_t line,

void CompileUnit::ResolveSymbolContext(
const SourceLocationSpec &src_location_spec,
SymbolContextItem resolve_scope, SymbolContextList &sc_list) {
SymbolContextItem resolve_scope, SymbolContextList &sc_list,
RealpathPrefixes *realpath_prefixes) {
const FileSpec file_spec = src_location_spec.GetFileSpec();
const uint32_t line = src_location_spec.GetLine().value_or(0);
const bool check_inlines = src_location_spec.GetCheckInlines();
Expand Down Expand Up @@ -275,8 +277,8 @@ void CompileUnit::ResolveSymbolContext(
return;
}

std::vector<uint32_t> file_indexes = FindFileIndexes(GetSupportFiles(),
file_spec);
std::vector<uint32_t> file_indexes =
FindFileIndexes(GetSupportFiles(), file_spec, realpath_prefixes);
const size_t num_file_indexes = file_indexes.size();
if (num_file_indexes == 0)
return;
Expand Down
12 changes: 12 additions & 0 deletions lldb/source/Target/Statistics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,10 @@ TargetStats::ToJSON(Target &target,
}
target_metrics_json.try_emplace("sourceMapDeduceCount",
m_source_map_deduce_count);
target_metrics_json.try_emplace("sourceRealpathAttemptCount",
m_source_realpath_attempt_count);
target_metrics_json.try_emplace("sourceRealpathCompatibleCount",
m_source_realpath_compatible_count);
return target_metrics_json;
}

Expand Down Expand Up @@ -220,6 +224,14 @@ void TargetStats::IncreaseSourceMapDeduceCount() {
++m_source_map_deduce_count;
}

void TargetStats::IncreaseSourceRealpathAttemptCount(uint32_t count) {
m_source_realpath_attempt_count += count;
}

void TargetStats::IncreaseSourceRealpathCompatibleCount(uint32_t count) {
m_source_realpath_compatible_count += count;
}

bool DebuggerStats::g_collecting_stats = false;

llvm::json::Value DebuggerStats::ReportStatistics(
Expand Down
8 changes: 8 additions & 0 deletions lldb/source/Target/Target.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
#include "lldb/Utility/LLDBAssert.h"
#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/RealpathPrefixes.h"
#include "lldb/Utility/State.h"
#include "lldb/Utility/StreamString.h"
#include "lldb/Utility/Timer.h"
Expand Down Expand Up @@ -4354,6 +4355,13 @@ InlineStrategy TargetProperties::GetInlineStrategy() const {
static_cast<InlineStrategy>(g_target_properties[idx].default_uint_value));
}

// Returning RealpathPrefixes, but the setting's type is FileSpecList. We do
// this because we want the FileSpecList to normalize the file paths for us.
RealpathPrefixes TargetProperties::GetSourceRealpathPrefixes() const {
const uint32_t idx = ePropertySourceRealpathPrefixes;
return RealpathPrefixes(GetPropertyAtIndexAs<FileSpecList>(idx, {}));
}

llvm::StringRef TargetProperties::GetArg0() const {
const uint32_t idx = ePropertyArg0;
return GetPropertyAtIndexAs<llvm::StringRef>(
Expand Down
3 changes: 3 additions & 0 deletions lldb/source/Target/TargetProperties.td
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,9 @@ let Definition = "target" in {
DefaultEnumValue<"eInlineBreakpointsAlways">,
EnumValues<"OptionEnumValues(g_inline_breakpoint_enums)">,
Desc<"The strategy to use when settings breakpoints by file and line. Breakpoint locations can end up being inlined by the compiler, so that a compile unit 'a.c' might contain an inlined function from another source file. Usually this is limited to breakpoint locations from inlined functions from header or other include files, or more accurately non-implementation source files. Sometimes code might #include implementation files and cause inlined breakpoint locations in inlined implementation files. Always checking for inlined breakpoint locations can be expensive (memory and time), so if you have a project with many headers and find that setting breakpoints is slow, then you can change this setting to headers. This setting allows you to control exactly which strategy is used when setting file and line breakpoints.">;
def SourceRealpathPrefixes: Property<"source-realpath-prefixes", "FileSpecList">,
DefaultStringValue<"">,
Desc<"Realpath any source paths that start with one of these prefixes. If the debug info contains symlinks which match the original source file's basename but don't match its location that the user will use to set breakpoints, then this setting can help resolve breakpoints correctly. This handles both symlinked files and directories. Wild card prefixes: An empty string matches all paths. A forward slash matches absolute paths.">;
def DisassemblyFlavor: Property<"x86-disassembly-flavor", "Enum">,
DefaultEnumValue<"eX86DisFlavorDefault">,
EnumValues<"OptionEnumValues(g_x86_dis_flavor_value_types)">,
Expand Down
1 change: 1 addition & 0 deletions lldb/source/Utility/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ add_lldb_library(lldbUtility NO_INTERNAL_DEPENDENCIES
Log.cpp
NameMatches.cpp
ProcessInfo.cpp
RealpathPrefixes.cpp
RegisterValue.cpp
RegularExpression.cpp
Instrumentation.cpp
Expand Down
Loading