Skip to content

Commit 47721d4

Browse files
authored
[lldb] Realpath symlinks for breakpoints (#102223)
Improve the chance of resolving file/line breakpoints by realpath'ing the support files before doing a second match attempt, with some conditions applied. A working [hello-world example](https://github.com/royitaqi/lldb_demos/blob/main/realpath/README.md). See [patch](#102223) for more info about problem/motivation, details of the feature, new settings, telemetries and tests.
1 parent 52337d5 commit 47721d4

File tree

29 files changed

+1002
-170
lines changed

29 files changed

+1002
-170
lines changed

lldb/include/lldb/Symbol/CompileUnit.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,13 @@
1919
#include "lldb/Utility/Stream.h"
2020
#include "lldb/Utility/UserID.h"
2121
#include "lldb/lldb-enumerations.h"
22+
#include "lldb/lldb-forward.h"
2223

2324
#include "llvm/ADT/DenseMap.h"
2425
#include "llvm/ADT/DenseSet.h"
2526

2627
namespace lldb_private {
28+
2729
/// \class CompileUnit CompileUnit.h "lldb/Symbol/CompileUnit.h"
2830
/// A class that describes a compilation unit.
2931
///
@@ -389,10 +391,15 @@ class CompileUnit : public std::enable_shared_from_this<CompileUnit>,
389391
/// A SymbolContext list class that will get any matching
390392
/// entries appended to.
391393
///
394+
/// \param[in] realpath_prefixes
395+
/// Paths that start with one of the prefixes in this list will be
396+
/// realpath'ed to resolve any symlinks.
397+
///
392398
/// \see enum SymbolContext::Scope
393399
void ResolveSymbolContext(const SourceLocationSpec &src_location_spec,
394400
lldb::SymbolContextItem resolve_scope,
395-
SymbolContextList &sc_list);
401+
SymbolContextList &sc_list,
402+
RealpathPrefixes *realpath_prefixes = nullptr);
396403

397404
/// Get whether compiler optimizations were enabled for this compile unit
398405
///

lldb/include/lldb/Target/Statistics.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#define LLDB_TARGET_STATISTICS_H
1111

1212
#include "lldb/Utility/ConstString.h"
13+
#include "lldb/Utility/RealpathPrefixes.h"
1314
#include "lldb/Utility/Stream.h"
1415
#include "lldb/lldb-forward.h"
1516
#include "llvm/ADT/StringMap.h"
@@ -184,6 +185,8 @@ class TargetStats {
184185
void SetFirstPrivateStopTime();
185186
void SetFirstPublicStopTime();
186187
void IncreaseSourceMapDeduceCount();
188+
void IncreaseSourceRealpathAttemptCount(uint32_t count);
189+
void IncreaseSourceRealpathCompatibleCount(uint32_t count);
187190

188191
StatsDuration &GetCreateTime() { return m_create_time; }
189192
StatsSuccessFail &GetExpressionStats() { return m_expr_eval; }
@@ -198,6 +201,8 @@ class TargetStats {
198201
StatsSuccessFail m_frame_var{"frameVariable"};
199202
std::vector<intptr_t> m_module_identifiers;
200203
uint32_t m_source_map_deduce_count = 0;
204+
uint32_t m_source_realpath_attempt_count = 0;
205+
uint32_t m_source_realpath_compatible_count = 0;
201206
void CollectStats(Target &target);
202207
};
203208

lldb/include/lldb/Target/Target.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include "lldb/Utility/ArchSpec.h"
3535
#include "lldb/Utility/Broadcaster.h"
3636
#include "lldb/Utility/LLDBAssert.h"
37+
#include "lldb/Utility/RealpathPrefixes.h"
3738
#include "lldb/Utility/Timeout.h"
3839
#include "lldb/lldb-public.h"
3940

@@ -117,6 +118,8 @@ class TargetProperties : public Properties {
117118

118119
InlineStrategy GetInlineStrategy() const;
119120

121+
RealpathPrefixes GetSourceRealpathPrefixes() const;
122+
120123
llvm::StringRef GetArg0() const;
121124

122125
void SetArg0(llvm::StringRef arg);

lldb/include/lldb/Utility/FileSpecList.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,16 @@ class SupportFileList {
6464
/// \param[in] file
6565
/// The file specification to search for.
6666
///
67+
/// \param[in] realpath_prefixes
68+
/// Paths that start with one of the prefixes in this list will be
69+
/// realpath'ed to resolve any symlinks.
70+
///
6771
/// \return
6872
/// The index of the file that matches \a file if it is found,
6973
/// else UINT32_MAX is returned.
70-
size_t FindCompatibleIndex(size_t idx, const FileSpec &file) const;
74+
size_t
75+
FindCompatibleIndex(size_t idx, const FileSpec &file,
76+
RealpathPrefixes *realpath_prefixes = nullptr) const;
7177

7278
template <class... Args> void EmplaceBack(Args &&...args) {
7379
m_files.push_back(
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
//===-- RealpathPrefixes.h --------------------------------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef LLDB_UTILITY_REALPATHPREFIXES_H
10+
#define LLDB_UTILITY_REALPATHPREFIXES_H
11+
12+
#include "lldb/lldb-forward.h"
13+
#include "llvm/ADT/IntrusiveRefCntPtr.h"
14+
#include "llvm/Support/VirtualFileSystem.h"
15+
16+
#include <optional>
17+
#include <string>
18+
#include <vector>
19+
20+
namespace lldb_private {
21+
22+
class RealpathPrefixes {
23+
public:
24+
/// \param[in] file_spec_list
25+
/// Prefixes are obtained from FileSpecList, through FileSpec::GetPath(),
26+
/// which ensures that the paths are normalized. For example:
27+
/// "./foo/.." -> ""
28+
/// "./foo/../bar" -> "bar"
29+
///
30+
/// \param[in] fs
31+
/// An optional filesystem to use for realpath'ing. If not set, the real
32+
/// filesystem will be used.
33+
explicit RealpathPrefixes(const FileSpecList &file_spec_list,
34+
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> fs =
35+
llvm::vfs::getRealFileSystem());
36+
37+
std::optional<FileSpec> ResolveSymlinks(const FileSpec &file_spec);
38+
39+
// If/when Statistics.h/cpp is moved into Utility, we can remove these
40+
// methods, hold a (weak) pointer to `TargetStats` and directly increment
41+
// on that object.
42+
void IncreaseSourceRealpathAttemptCount() {
43+
++m_source_realpath_attempt_count;
44+
}
45+
uint32_t GetSourceRealpathAttemptCount() const {
46+
return m_source_realpath_attempt_count;
47+
}
48+
void IncreaseSourceRealpathCompatibleCount() {
49+
++m_source_realpath_compatible_count;
50+
}
51+
uint32_t GetSourceRealpathCompatibleCount() const {
52+
return m_source_realpath_compatible_count;
53+
}
54+
55+
private:
56+
// Paths that start with one of the prefixes in this list will be realpath'ed
57+
// to resolve any symlinks.
58+
//
59+
// Wildcard prefixes:
60+
// - "" (empty string) will match all paths.
61+
// - "/" will match all absolute paths.
62+
std::vector<std::string> m_prefixes;
63+
64+
// The filesystem to use for realpath'ing.
65+
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> m_fs;
66+
67+
// The optional Target instance to gather statistics.
68+
lldb::TargetWP m_target;
69+
70+
// Statistics that we temprarily hold here, to be gathered into TargetStats
71+
uint32_t m_source_realpath_attempt_count = 0;
72+
uint32_t m_source_realpath_compatible_count = 0;
73+
};
74+
75+
} // namespace lldb_private
76+
77+
#endif // LLDB_UTILITY_REALPATHPREFIXES_H

lldb/include/lldb/lldb-forward.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ class Queue;
175175
class QueueImpl;
176176
class QueueItem;
177177
class REPL;
178+
class RealpathPrefixes;
178179
class RecognizedStackFrame;
179180
class RegisterCheckpoint;
180181
class RegisterContext;

lldb/source/Breakpoint/BreakpointResolverFileLine.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "lldb/Target/Target.h"
1616
#include "lldb/Utility/LLDBLog.h"
1717
#include "lldb/Utility/Log.h"
18+
#include "lldb/Utility/RealpathPrefixes.h"
1819
#include "lldb/Utility/StreamString.h"
1920
#include <optional>
2021

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

294+
Target &target = GetBreakpoint()->GetTarget();
295+
RealpathPrefixes realpath_prefixes = target.GetSourceRealpathPrefixes();
296+
293297
const size_t num_comp_units = context.module_sp->GetNumCompileUnits();
294298
for (size_t i = 0; i < num_comp_units; i++) {
295299
CompUnitSP cu_sp(context.module_sp->GetCompileUnitAtIndex(i));
296300
if (cu_sp) {
297301
if (filter.CompUnitPasses(*cu_sp))
298302
cu_sp->ResolveSymbolContext(m_location_spec, eSymbolContextEverything,
299-
sc_list);
303+
sc_list, &realpath_prefixes);
300304
}
301305
}
302306

307+
// Gather stats into the Target
308+
target.GetStatistics().IncreaseSourceRealpathAttemptCount(
309+
realpath_prefixes.GetSourceRealpathAttemptCount());
310+
target.GetStatistics().IncreaseSourceRealpathCompatibleCount(
311+
realpath_prefixes.GetSourceRealpathCompatibleCount());
312+
303313
FilterContexts(sc_list);
304314

305315
DeduceSourceMapping(sc_list);

lldb/source/Symbol/CompileUnit.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -213,11 +213,12 @@ VariableListSP CompileUnit::GetVariableList(bool can_create) {
213213
return m_variables;
214214
}
215215

216-
std::vector<uint32_t> FindFileIndexes(const SupportFileList &files,
217-
const FileSpec &file) {
216+
std::vector<uint32_t>
217+
FindFileIndexes(const SupportFileList &files, const FileSpec &file,
218+
RealpathPrefixes *realpath_prefixes = nullptr) {
218219
std::vector<uint32_t> result;
219220
uint32_t idx = -1;
220-
while ((idx = files.FindCompatibleIndex(idx + 1, file)) !=
221+
while ((idx = files.FindCompatibleIndex(idx + 1, file, realpath_prefixes)) !=
221222
UINT32_MAX)
222223
result.push_back(idx);
223224
return result;
@@ -247,7 +248,8 @@ uint32_t CompileUnit::FindLineEntry(uint32_t start_idx, uint32_t line,
247248

248249
void CompileUnit::ResolveSymbolContext(
249250
const SourceLocationSpec &src_location_spec,
250-
SymbolContextItem resolve_scope, SymbolContextList &sc_list) {
251+
SymbolContextItem resolve_scope, SymbolContextList &sc_list,
252+
RealpathPrefixes *realpath_prefixes) {
251253
const FileSpec file_spec = src_location_spec.GetFileSpec();
252254
const uint32_t line = src_location_spec.GetLine().value_or(0);
253255
const bool check_inlines = src_location_spec.GetCheckInlines();
@@ -275,8 +277,8 @@ void CompileUnit::ResolveSymbolContext(
275277
return;
276278
}
277279

278-
std::vector<uint32_t> file_indexes = FindFileIndexes(GetSupportFiles(),
279-
file_spec);
280+
std::vector<uint32_t> file_indexes =
281+
FindFileIndexes(GetSupportFiles(), file_spec, realpath_prefixes);
280282
const size_t num_file_indexes = file_indexes.size();
281283
if (num_file_indexes == 0)
282284
return;

lldb/source/Target/Statistics.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,10 @@ TargetStats::ToJSON(Target &target,
192192
}
193193
target_metrics_json.try_emplace("sourceMapDeduceCount",
194194
m_source_map_deduce_count);
195+
target_metrics_json.try_emplace("sourceRealpathAttemptCount",
196+
m_source_realpath_attempt_count);
197+
target_metrics_json.try_emplace("sourceRealpathCompatibleCount",
198+
m_source_realpath_compatible_count);
195199
return target_metrics_json;
196200
}
197201

@@ -220,6 +224,14 @@ void TargetStats::IncreaseSourceMapDeduceCount() {
220224
++m_source_map_deduce_count;
221225
}
222226

227+
void TargetStats::IncreaseSourceRealpathAttemptCount(uint32_t count) {
228+
m_source_realpath_attempt_count += count;
229+
}
230+
231+
void TargetStats::IncreaseSourceRealpathCompatibleCount(uint32_t count) {
232+
m_source_realpath_compatible_count += count;
233+
}
234+
223235
bool DebuggerStats::g_collecting_stats = false;
224236

225237
llvm::json::Value DebuggerStats::ReportStatistics(

lldb/source/Target/Target.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
#include "lldb/Utility/LLDBAssert.h"
6161
#include "lldb/Utility/LLDBLog.h"
6262
#include "lldb/Utility/Log.h"
63+
#include "lldb/Utility/RealpathPrefixes.h"
6364
#include "lldb/Utility/State.h"
6465
#include "lldb/Utility/StreamString.h"
6566
#include "lldb/Utility/Timer.h"
@@ -4354,6 +4355,13 @@ InlineStrategy TargetProperties::GetInlineStrategy() const {
43544355
static_cast<InlineStrategy>(g_target_properties[idx].default_uint_value));
43554356
}
43564357

4358+
// Returning RealpathPrefixes, but the setting's type is FileSpecList. We do
4359+
// this because we want the FileSpecList to normalize the file paths for us.
4360+
RealpathPrefixes TargetProperties::GetSourceRealpathPrefixes() const {
4361+
const uint32_t idx = ePropertySourceRealpathPrefixes;
4362+
return RealpathPrefixes(GetPropertyAtIndexAs<FileSpecList>(idx, {}));
4363+
}
4364+
43574365
llvm::StringRef TargetProperties::GetArg0() const {
43584366
const uint32_t idx = ePropertyArg0;
43594367
return GetPropertyAtIndexAs<llvm::StringRef>(

0 commit comments

Comments
 (0)