Skip to content

Commit 11f45f3

Browse files
committed
[lldb] Fetching symbols in the background with dsymForUUID
On macOS, LLDB uses the DebugSymbols.framework to locate symbol rich dSYM bundles. [1] The framework uses a variety of methods, one of them calling into a binary or shell script to locate (and download) dSYMs. Internally at Apple, that tool is called dsymForUUID and for simplicity I'm just going to refer to it that way here too, even though it can be be an arbitrary executable. The most common use case for dsymForUUID is to fetch symbols from the network. This can take a long time, and because the calls to the DebugSymbols.framework are blocking, it takes a while to launch the process. This is expected and therefore many people don't use this functionality, but instead use add-dsym when they want symbols for a given frame, backtrace or module. This is a little faster because you're only fetching symbols for the module you care about, but it's still a slow, blocking operation. This patch introduces a hybrid approach between the two. When symbols.enable-background-lookup is enabled, lldb will do the equivalent of add-dsym in the background for every module that shows up in the backtrace but doesn't have symbols for. From the user's perspective there is no slowdown, because the process launches immediately, with whatever symbols are available. Meanwhile, more symbol information is added over time as the background fetching completes. [1] https://lldb.llvm.org/use/symbols.html rdar://76241471 Differential revision: https://reviews.llvm.org/D131328
1 parent 8d36a82 commit 11f45f3

File tree

12 files changed

+170
-25
lines changed

12 files changed

+170
-25
lines changed

lldb/include/lldb/Core/Debugger.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
8282
eBroadcastBitProgress = (1 << 0),
8383
eBroadcastBitWarning = (1 << 1),
8484
eBroadcastBitError = (1 << 2),
85+
eBroadcastSymbolChange = (1 << 3),
8586
};
8687

8788
static ConstString GetStaticBroadcasterClass();
@@ -430,6 +431,8 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
430431
llvm::Optional<lldb::user_id_t> debugger_id = llvm::None,
431432
std::once_flag *once = nullptr);
432433

434+
static void ReportSymbolChange(const ModuleSpec &module_spec);
435+
433436
protected:
434437
friend class CommandInterpreter;
435438
friend class REPL;

lldb/include/lldb/Core/DebuggerEvents.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
//
77
//===----------------------------------------------------------------------===//
88

9+
#include "lldb/Core/ModuleSpec.h"
910
#include "lldb/Utility/ConstString.h"
1011
#include "lldb/Utility/Event.h"
1112

@@ -82,6 +83,28 @@ class DiagnosticEventData : public EventData {
8283
const DiagnosticEventData &operator=(const DiagnosticEventData &) = delete;
8384
};
8485

86+
class SymbolChangeEventData : public EventData {
87+
public:
88+
SymbolChangeEventData(lldb::DebuggerWP debugger_wp, ModuleSpec module_spec)
89+
: m_debugger_wp(debugger_wp), m_module_spec(std::move(module_spec)) {}
90+
91+
static ConstString GetFlavorString();
92+
ConstString GetFlavor() const override;
93+
94+
static const SymbolChangeEventData *
95+
GetEventDataFromEvent(const Event *event_ptr);
96+
97+
void DoOnRemoval(Event *event_ptr) override;
98+
99+
private:
100+
lldb::DebuggerWP m_debugger_wp;
101+
ModuleSpec m_module_spec;
102+
103+
SymbolChangeEventData(const SymbolChangeEventData &) = delete;
104+
const SymbolChangeEventData &
105+
operator=(const SymbolChangeEventData &) = delete;
106+
};
107+
85108
} // namespace lldb_private
86109

87110
#endif // LLDB_CORE_DEBUGGER_EVENTS_H

lldb/include/lldb/Core/ModuleList.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ class ModuleListProperties : public Properties {
6060
bool SetClangModulesCachePath(const FileSpec &path);
6161
bool GetEnableExternalLookup() const;
6262
bool SetEnableExternalLookup(bool new_value);
63+
bool GetEnableBackgroundLookup() const;
6364
bool GetEnableLLDBIndexCache() const;
6465
bool SetEnableLLDBIndexCache(bool new_value);
6566
uint64_t GetLLDBIndexCacheMaxByteSize();
@@ -457,6 +458,8 @@ class ModuleList {
457458
static void FindSharedModules(const ModuleSpec &module_spec,
458459
ModuleList &matching_module_list);
459460

461+
static lldb::ModuleSP FindSharedModule(const UUID &uuid);
462+
460463
static size_t RemoveOrphanSharedModules(bool mandatory);
461464

462465
static bool RemoveSharedModuleIfOrphaned(const Module *module_ptr);

lldb/include/lldb/Symbol/LocateSymbolFile.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "lldb/Core/FileSpecList.h"
1515
#include "lldb/Utility/FileSpec.h"
1616
#include "lldb/Utility/Status.h"
17+
#include "lldb/lldb-forward.h"
1718

1819
namespace lldb_private {
1920

@@ -52,7 +53,15 @@ class Symbols {
5253
//
5354
static bool DownloadObjectAndSymbolFile(ModuleSpec &module_spec,
5455
Status &error,
55-
bool force_lookup = true);
56+
bool force_lookup = true,
57+
bool copy_executable = true);
58+
59+
/// Locate the symbol file for the given UUID on a background thread. This
60+
/// function returns immediately. Under the hood it uses the debugger's
61+
/// thread pool to call DownloadObjectAndSymbolFile. If a symbol file is
62+
/// found, this will notify all target which contain the module with the
63+
/// given UUID.
64+
static void DownloadSymbolFileAsync(const UUID &uuid);
5665
};
5766

5867
} // namespace lldb_private

lldb/include/lldb/Target/Target.h

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ class TargetProperties : public Properties {
162162
bool GetEnableNotifyAboutFixIts() const;
163163

164164
FileSpec GetSaveJITObjectsDir() const;
165-
165+
166166
bool GetEnableSyntheticValue() const;
167167

168168
uint32_t GetMaxZeroPaddingInFloatFormat() const;
@@ -260,7 +260,7 @@ class TargetProperties : public Properties {
260260
void DisableASLRValueChangedCallback();
261261
void InheritTCCValueChangedCallback();
262262
void DisableSTDIOValueChangedCallback();
263-
263+
264264
// Settings checker for target.jit-save-objects-dir:
265265
void CheckJITObjectsDir();
266266

@@ -479,7 +479,8 @@ class Target : public std::enable_shared_from_this<Target>,
479479
eBroadcastBitModulesLoaded = (1 << 1),
480480
eBroadcastBitModulesUnloaded = (1 << 2),
481481
eBroadcastBitWatchpointChanged = (1 << 3),
482-
eBroadcastBitSymbolsLoaded = (1 << 4)
482+
eBroadcastBitSymbolsLoaded = (1 << 4),
483+
eBroadcastBitSymbolsChanged = (1 << 5),
483484
};
484485

485486
// These two functions fill out the Broadcaster interface:
@@ -981,7 +982,7 @@ class Target : public std::enable_shared_from_this<Target>,
981982
ModuleIsExcludedForUnconstrainedSearches(const lldb::ModuleSP &module_sp);
982983

983984
const ArchSpec &GetArchitecture() const { return m_arch.GetSpec(); }
984-
985+
985986
/// Returns the name of the target's ABI plugin.
986987
llvm::StringRef GetABIName() const;
987988

@@ -1425,30 +1426,30 @@ class Target : public std::enable_shared_from_this<Target>,
14251426
LazyBool pass = eLazyBoolCalculate;
14261427
LazyBool notify = eLazyBoolCalculate;
14271428
LazyBool stop = eLazyBoolCalculate;
1428-
DummySignalValues(LazyBool pass, LazyBool notify, LazyBool stop) :
1429-
pass(pass), notify(notify), stop(stop) {}
1429+
DummySignalValues(LazyBool pass, LazyBool notify, LazyBool stop)
1430+
: pass(pass), notify(notify), stop(stop) {}
14301431
DummySignalValues() = default;
14311432
};
14321433
using DummySignalElement = llvm::StringMapEntry<DummySignalValues>;
1433-
static bool UpdateSignalFromDummy(lldb::UnixSignalsSP signals_sp,
1434-
const DummySignalElement &element);
1435-
static bool ResetSignalFromDummy(lldb::UnixSignalsSP signals_sp,
1436-
const DummySignalElement &element);
1434+
static bool UpdateSignalFromDummy(lldb::UnixSignalsSP signals_sp,
1435+
const DummySignalElement &element);
1436+
static bool ResetSignalFromDummy(lldb::UnixSignalsSP signals_sp,
1437+
const DummySignalElement &element);
14371438

14381439
public:
14391440
/// Add a signal to the Target's list of stored signals/actions. These
14401441
/// values will get copied into any processes launched from
14411442
/// this target.
1442-
void AddDummySignal(llvm::StringRef name, LazyBool pass, LazyBool print,
1443+
void AddDummySignal(llvm::StringRef name, LazyBool pass, LazyBool print,
14431444
LazyBool stop);
14441445
/// Updates the signals in signals_sp using the stored dummy signals.
14451446
/// If warning_stream_sp is not null, if any stored signals are not found in
14461447
/// the current process, a warning will be emitted here.
1447-
void UpdateSignalsFromDummy(lldb::UnixSignalsSP signals_sp,
1448+
void UpdateSignalsFromDummy(lldb::UnixSignalsSP signals_sp,
14481449
lldb::StreamSP warning_stream_sp);
14491450
/// Clear the dummy signals in signal_names from the target, or all signals
14501451
/// if signal_names is empty. Also remove the behaviors they set from the
1451-
/// process's signals if it exists.
1452+
/// process's signals if it exists.
14521453
void ClearDummySignals(Args &signal_names);
14531454
/// Print all the signals set in this target.
14541455
void PrintDummySignals(Stream &strm, Args &signals);
@@ -1533,7 +1534,7 @@ class Target : public std::enable_shared_from_this<Target>,
15331534
lldb::TraceSP m_trace_sp;
15341535
/// Stores the frame recognizers of this target.
15351536
lldb::StackFrameRecognizerManagerUP m_frame_recognizer_manager_up;
1536-
/// These are used to set the signal state when you don't have a process and
1537+
/// These are used to set the signal state when you don't have a process and
15371538
/// more usefully in the Dummy target where you can't know exactly what
15381539
/// signals you will have.
15391540
llvm::StringMap<DummySignalValues> m_dummy_signals;

lldb/source/Core/CoreProperties.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ let Definition = "modulelist" in {
55
Global,
66
DefaultTrue,
77
Desc<"Control the use of external tools and repositories to locate symbol files. Directories listed in target.debug-file-search-paths and directory of the executable are always checked first for separate debug info files. Then depending on this setting: On macOS, Spotlight would be also used to locate a matching .dSYM bundle based on the UUID of the executable. On NetBSD, directory /usr/libdata/debug would be also searched. On platforms other than NetBSD directory /usr/lib/debug would be also searched.">;
8+
def EnableBackgroundLookup: Property<"enable-background-lookup", "Boolean">,
9+
Global,
10+
DefaultFalse,
11+
Desc<"On macOS, enable calling dsymForUUID (or an equivalent script/binary) in the background to locate symbol files that weren't found.">;
812
def ClangModulesCachePath: Property<"clang-modules-cache-path", "FileSpec">,
913
Global,
1014
DefaultStringValue<"">,

lldb/source/Core/Debugger.cpp

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "lldb/Core/FormatEntity.h"
1414
#include "lldb/Core/Mangled.h"
1515
#include "lldb/Core/ModuleList.h"
16+
#include "lldb/Core/ModuleSpec.h"
1617
#include "lldb/Core/PluginManager.h"
1718
#include "lldb/Core/StreamAsynchronousIO.h"
1819
#include "lldb/Core/StreamFile.h"
@@ -1413,6 +1414,18 @@ void Debugger::ReportError(std::string message,
14131414
debugger_id, once);
14141415
}
14151416

1417+
void Debugger::ReportSymbolChange(const ModuleSpec &module_spec) {
1418+
if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) {
1419+
std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr);
1420+
for (DebuggerSP debugger_sp : *g_debugger_list_ptr) {
1421+
EventSP event_sp = std::make_shared<Event>(
1422+
Debugger::eBroadcastSymbolChange,
1423+
new SymbolChangeEventData(debugger_sp, module_spec));
1424+
debugger_sp->GetBroadcaster().BroadcastEvent(event_sp);
1425+
}
1426+
}
1427+
}
1428+
14161429
static std::shared_ptr<LogHandler>
14171430
CreateLogHandler(LogHandlerKind log_handler_kind, int fd, bool should_close,
14181431
size_t buffer_size) {
@@ -1709,8 +1722,8 @@ lldb::thread_result_t Debugger::DefaultEventHandler() {
17091722
CommandInterpreter::eBroadcastBitAsynchronousErrorData);
17101723

17111724
listener_sp->StartListeningForEvents(
1712-
&m_broadcaster,
1713-
eBroadcastBitProgress | eBroadcastBitWarning | eBroadcastBitError);
1725+
&m_broadcaster, eBroadcastBitProgress | eBroadcastBitWarning |
1726+
eBroadcastBitError | eBroadcastSymbolChange);
17141727

17151728
// Let the thread that spawned us know that we have started up and that we
17161729
// are now listening to all required events so no events get missed

lldb/source/Core/DebuggerEvents.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,12 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "lldb/Core/DebuggerEvents.h"
10+
#include "lldb/Core/Debugger.h"
11+
#include "lldb/Core/Module.h"
1012
#include "llvm/Support/WithColor.h"
1113

1214
using namespace lldb_private;
15+
using namespace lldb;
1316

1417
template <typename T>
1518
static const T *GetEventDataFromEventImpl(const Event *event_ptr) {
@@ -79,3 +82,37 @@ const DiagnosticEventData *
7982
DiagnosticEventData::GetEventDataFromEvent(const Event *event_ptr) {
8083
return GetEventDataFromEventImpl<DiagnosticEventData>(event_ptr);
8184
}
85+
86+
ConstString SymbolChangeEventData::GetFlavorString() {
87+
static ConstString g_flavor("SymbolChangeEventData");
88+
return g_flavor;
89+
}
90+
91+
ConstString SymbolChangeEventData::GetFlavor() const {
92+
return SymbolChangeEventData::GetFlavorString();
93+
}
94+
95+
const SymbolChangeEventData *
96+
SymbolChangeEventData::GetEventDataFromEvent(const Event *event_ptr) {
97+
return GetEventDataFromEventImpl<SymbolChangeEventData>(event_ptr);
98+
}
99+
100+
void SymbolChangeEventData::DoOnRemoval(Event *event_ptr) {
101+
DebuggerSP debugger_sp(m_debugger_wp.lock());
102+
if (!debugger_sp)
103+
return;
104+
105+
for (TargetSP target_sp : debugger_sp->GetTargetList().Targets()) {
106+
if (ModuleSP module_sp =
107+
target_sp->GetImages().FindModule(m_module_spec.GetUUID())) {
108+
{
109+
std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
110+
if (!module_sp->GetSymbolFileFileSpec())
111+
module_sp->SetSymbolFileFileSpec(m_module_spec.GetSymbolFileSpec());
112+
}
113+
ModuleList module_list;
114+
module_list.Append(module_sp);
115+
target_sp->SymbolsDidLoad(module_list);
116+
}
117+
}
118+
}

lldb/source/Core/Module.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "lldb/Interpreter/ScriptInterpreter.h"
2525
#include "lldb/Symbol/CompileUnit.h"
2626
#include "lldb/Symbol/Function.h"
27+
#include "lldb/Symbol/LocateSymbolFile.h"
2728
#include "lldb/Symbol/ObjectFile.h"
2829
#include "lldb/Symbol/Symbol.h"
2930
#include "lldb/Symbol/SymbolContext.h"
@@ -770,7 +771,7 @@ void Module::LookupInfo::Prune(SymbolContextList &sc_list,
770771
while (i < sc_list.GetSize()) {
771772
if (!sc_list.GetContextAtIndex(i, sc))
772773
break;
773-
774+
774775
bool keep_it =
775776
NameMatchesLookupInfo(sc.GetFunctionName(), sc.GetLanguage());
776777
if (keep_it)
@@ -1317,8 +1318,11 @@ void Module::SectionFileAddressesChanged() {
13171318
}
13181319

13191320
UnwindTable &Module::GetUnwindTable() {
1320-
if (!m_unwind_table)
1321+
if (!m_unwind_table) {
13211322
m_unwind_table.emplace(*this);
1323+
if (!m_symfile_spec)
1324+
Symbols::DownloadSymbolFileAsync(GetUUID());
1325+
}
13221326
return *m_unwind_table;
13231327
}
13241328

lldb/source/Core/ModuleList.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,12 @@ bool ModuleListProperties::SetEnableExternalLookup(bool new_value) {
106106
nullptr, ePropertyEnableExternalLookup, new_value);
107107
}
108108

109+
bool ModuleListProperties::GetEnableBackgroundLookup() const {
110+
const uint32_t idx = ePropertyEnableBackgroundLookup;
111+
return m_collection_sp->GetPropertyAtIndexAsBoolean(
112+
nullptr, idx, g_modulelist_properties[idx].default_uint_value != 0);
113+
}
114+
109115
FileSpec ModuleListProperties::GetClangModulesCachePath() const {
110116
return m_collection_sp
111117
->GetPropertyAtIndexAsOptionValueFileSpec(nullptr, false,
@@ -768,6 +774,10 @@ void ModuleList::FindSharedModules(const ModuleSpec &module_spec,
768774
GetSharedModuleList().FindModules(module_spec, matching_module_list);
769775
}
770776

777+
lldb::ModuleSP ModuleList::FindSharedModule(const UUID &uuid) {
778+
return GetSharedModuleList().FindModule(uuid);
779+
}
780+
771781
size_t ModuleList::RemoveOrphanSharedModules(bool mandatory) {
772782
return GetSharedModuleList().RemoveOrphans(mandatory);
773783
}

0 commit comments

Comments
 (0)