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 4 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
14 changes: 11 additions & 3 deletions lldb/include/lldb/Symbol/CompileUnit.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
#include "llvm/ADT/DenseSet.h"

namespace lldb_private {
class RealpathPrefixes;

/// \class CompileUnit CompileUnit.h "lldb/Symbol/CompileUnit.h"
/// A class that describes a compilation unit.
///
Expand Down Expand Up @@ -389,10 +391,16 @@ 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);
void
ResolveSymbolContext(const SourceLocationSpec &src_location_spec,
lldb::SymbolContextItem resolve_scope,
SymbolContextList &sc_list,
const RealpathPrefixes *realpath_prefixes = nullptr);

/// Get whether compiler optimizations were enabled for this compile unit
///
Expand Down
4 changes: 4 additions & 0 deletions lldb/include/lldb/Target/Statistics.h
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,8 @@ class TargetStats {
void SetFirstPrivateStopTime();
void SetFirstPublicStopTime();
void IncreaseSourceMapDeduceCount();
void IncreaseSourceRealpathAttemptCount();
void IncreaseSourceRealpathCompatibleCount();

StatsDuration &GetCreateTime() { return m_create_time; }
StatsSuccessFail &GetExpressionStats() { return m_expr_eval; }
Expand All @@ -198,6 +200,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
9 changes: 8 additions & 1 deletion lldb/include/lldb/Utility/FileSpecList.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <vector>

namespace lldb_private {
class RealpathPrefixes;
class Stream;

/// A list of support files for a CompileUnit.
Expand Down Expand Up @@ -64,10 +65,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,
const RealpathPrefixes *realpath_prefixes = nullptr) const;

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

#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/Support/VirtualFileSystem.h"

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

namespace lldb_private {
class FileSpec;
class FileSpecList;
class Target;
} // namespace lldb_private

namespace lldb_private {

class RealpathPrefixes {
public:
// Prefixes are obtained from FileSpecList, through FileSpec::GetPath(), which
// ensures that the paths are normalized. For example:
// "./foo/.." -> ""
// "./foo/../bar" -> "bar"
explicit RealpathPrefixes(const FileSpecList &file_spec_list);

// Sets an optional filesystem to use for realpath'ing. If not set, the real
// filesystem will be used.
void SetFileSystem(llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs);

// Sets an optional Target instance to gather statistics.
void SetTarget(Target *target) { m_target = target; }
Target *GetTarget() const { return m_target; }

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

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.
Target *m_target;
};

} // namespace lldb_private

#endif // LLDB_CORE_REALPATHPREFIXES_H
6 changes: 5 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,13 +291,16 @@ 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();

RealpathPrefixes realpath_prefixes =
GetBreakpoint()->GetTarget().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);
}
}

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,
const 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,
const 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() {
++m_source_realpath_attempt_count;
}

void TargetStats::IncreaseSourceRealpathCompatibleCount() {
++m_source_realpath_compatible_count;
}

bool DebuggerStats::g_collecting_stats = false;

llvm::json::Value DebuggerStats::ReportStatistics(
Expand Down
10 changes: 10 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,15 @@ 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;
auto prefixes = RealpathPrefixes(GetPropertyAtIndexAs<FileSpecList>(idx, {}));
prefixes.SetTarget(this->m_target);
return prefixes;
}

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 that don't match the original source file locations that the user will use to set breakpoints, then this setting can help resolve breakpoints correctly.">;
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
Loading