Skip to content

Commit 188bfd2

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 (cherry picked from commit 11f45f3)
1 parent 62a362b commit 188bfd2

File tree

12 files changed

+169
-24
lines changed

12 files changed

+169
-24
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();
@@ -438,6 +439,8 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
438439
llvm::Optional<lldb::user_id_t> debugger_id = llvm::None,
439440
std::once_flag *once = nullptr);
440441

442+
static void ReportSymbolChange(const ModuleSpec &module_spec);
443+
441444
protected:
442445
friend class CommandInterpreter;
443446
friend class SwiftREPL;

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
@@ -71,6 +71,7 @@ class ModuleListProperties : public Properties {
7171
bool SetClangModulesCachePath(const FileSpec &path);
7272
bool GetEnableExternalLookup() const;
7373
bool SetEnableExternalLookup(bool new_value);
74+
bool GetEnableBackgroundLookup() const;
7475
bool GetEnableLLDBIndexCache() const;
7576
bool SetEnableLLDBIndexCache(bool new_value);
7677
uint64_t GetLLDBIndexCacheMaxByteSize();
@@ -466,6 +467,8 @@ class ModuleList {
466467
static void FindSharedModules(const ModuleSpec &module_spec,
467468
ModuleList &matching_module_list);
468469

470+
static lldb::ModuleSP FindSharedModule(const UUID &uuid);
471+
469472
static size_t RemoveOrphanSharedModules(bool mandatory);
470473

471474
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
@@ -207,7 +207,7 @@ class TargetProperties : public Properties {
207207
bool GetEnableNotifyAboutFixIts() const;
208208

209209
FileSpec GetSaveJITObjectsDir() const;
210-
210+
211211
bool GetEnableSyntheticValue() const;
212212

213213
uint32_t GetMaxZeroPaddingInFloatFormat() const;
@@ -305,7 +305,7 @@ class TargetProperties : public Properties {
305305
void DisableASLRValueChangedCallback();
306306
void InheritTCCValueChangedCallback();
307307
void DisableSTDIOValueChangedCallback();
308-
308+
309309
// Settings checker for target.jit-save-objects-dir:
310310
void CheckJITObjectsDir();
311311

@@ -543,7 +543,8 @@ class Target : public std::enable_shared_from_this<Target>,
543543
eBroadcastBitModulesLoaded = (1 << 1),
544544
eBroadcastBitModulesUnloaded = (1 << 2),
545545
eBroadcastBitWatchpointChanged = (1 << 3),
546-
eBroadcastBitSymbolsLoaded = (1 << 4)
546+
eBroadcastBitSymbolsLoaded = (1 << 4),
547+
eBroadcastBitSymbolsChanged = (1 << 5),
547548
};
548549

549550
// These two functions fill out the Broadcaster interface:
@@ -1045,7 +1046,7 @@ class Target : public std::enable_shared_from_this<Target>,
10451046
ModuleIsExcludedForUnconstrainedSearches(const lldb::ModuleSP &module_sp);
10461047

10471048
const ArchSpec &GetArchitecture() const { return m_arch.GetSpec(); }
1048-
1049+
10491050
/// Returns the name of the target's ABI plugin.
10501051
llvm::StringRef GetABIName() const;
10511052

@@ -1535,30 +1536,30 @@ class Target : public std::enable_shared_from_this<Target>,
15351536
LazyBool pass = eLazyBoolCalculate;
15361537
LazyBool notify = eLazyBoolCalculate;
15371538
LazyBool stop = eLazyBoolCalculate;
1538-
DummySignalValues(LazyBool pass, LazyBool notify, LazyBool stop) :
1539-
pass(pass), notify(notify), stop(stop) {}
1539+
DummySignalValues(LazyBool pass, LazyBool notify, LazyBool stop)
1540+
: pass(pass), notify(notify), stop(stop) {}
15401541
DummySignalValues() = default;
15411542
};
15421543
using DummySignalElement = llvm::StringMapEntry<DummySignalValues>;
1543-
static bool UpdateSignalFromDummy(lldb::UnixSignalsSP signals_sp,
1544-
const DummySignalElement &element);
1545-
static bool ResetSignalFromDummy(lldb::UnixSignalsSP signals_sp,
1546-
const DummySignalElement &element);
1544+
static bool UpdateSignalFromDummy(lldb::UnixSignalsSP signals_sp,
1545+
const DummySignalElement &element);
1546+
static bool ResetSignalFromDummy(lldb::UnixSignalsSP signals_sp,
1547+
const DummySignalElement &element);
15471548

15481549
public:
15491550
/// Add a signal to the Target's list of stored signals/actions. These
15501551
/// values will get copied into any processes launched from
15511552
/// this target.
1552-
void AddDummySignal(llvm::StringRef name, LazyBool pass, LazyBool print,
1553+
void AddDummySignal(llvm::StringRef name, LazyBool pass, LazyBool print,
15531554
LazyBool stop);
15541555
/// Updates the signals in signals_sp using the stored dummy signals.
15551556
/// If warning_stream_sp is not null, if any stored signals are not found in
15561557
/// the current process, a warning will be emitted here.
1557-
void UpdateSignalsFromDummy(lldb::UnixSignalsSP signals_sp,
1558+
void UpdateSignalsFromDummy(lldb::UnixSignalsSP signals_sp,
15581559
lldb::StreamSP warning_stream_sp);
15591560
/// Clear the dummy signals in signal_names from the target, or all signals
15601561
/// if signal_names is empty. Also remove the behaviors they set from the
1561-
/// process's signals if it exists.
1562+
/// process's signals if it exists.
15621563
void ClearDummySignals(Args &signal_names);
15631564
/// Print all the signals set in this target.
15641565
void PrintDummySignals(Stream &strm, Args &signals);
@@ -1644,7 +1645,7 @@ class Target : public std::enable_shared_from_this<Target>,
16441645
lldb::TraceSP m_trace_sp;
16451646
/// Stores the frame recognizers of this target.
16461647
lldb::StackFrameRecognizerManagerUP m_frame_recognizer_manager_up;
1647-
/// These are used to set the signal state when you don't have a process and
1648+
/// These are used to set the signal state when you don't have a process and
16481649
/// more usefully in the Dummy target where you can't know exactly what
16491650
/// signals you will have.
16501651
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"
@@ -1452,6 +1453,18 @@ void Debugger::ReportError(std::string message,
14521453
debugger_id, once);
14531454
}
14541455

1456+
void Debugger::ReportSymbolChange(const ModuleSpec &module_spec) {
1457+
if (g_debugger_list_ptr && g_debugger_list_mutex_ptr) {
1458+
std::lock_guard<std::recursive_mutex> guard(*g_debugger_list_mutex_ptr);
1459+
for (DebuggerSP debugger_sp : *g_debugger_list_ptr) {
1460+
EventSP event_sp = std::make_shared<Event>(
1461+
Debugger::eBroadcastSymbolChange,
1462+
new SymbolChangeEventData(debugger_sp, module_spec));
1463+
debugger_sp->GetBroadcaster().BroadcastEvent(event_sp);
1464+
}
1465+
}
1466+
}
1467+
14551468
static std::shared_ptr<LogHandler>
14561469
CreateLogHandler(LogHandlerKind log_handler_kind, int fd, bool should_close,
14571470
size_t buffer_size) {
@@ -1761,8 +1774,8 @@ lldb::thread_result_t Debugger::DefaultEventHandler() {
17611774
CommandInterpreter::eBroadcastBitAsynchronousErrorData);
17621775

17631776
listener_sp->StartListeningForEvents(
1764-
&m_broadcaster,
1765-
eBroadcastBitProgress | eBroadcastBitWarning | eBroadcastBitError);
1777+
&m_broadcaster, eBroadcastBitProgress | eBroadcastBitWarning |
1778+
eBroadcastBitError | eBroadcastSymbolChange);
17661779

17671780
// Let the thread that spawned us know that we have started up and that we
17681781
// 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: 5 additions & 1 deletion
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"
@@ -1362,8 +1363,11 @@ void Module::SectionFileAddressesChanged() {
13621363
}
13631364

13641365
UnwindTable &Module::GetUnwindTable() {
1365-
if (!m_unwind_table)
1366+
if (!m_unwind_table) {
13661367
m_unwind_table.emplace(*this);
1368+
if (!m_symfile_spec)
1369+
Symbols::DownloadSymbolFileAsync(GetUUID());
1370+
}
13671371
return *m_unwind_table;
13681372
}
13691373

lldb/source/Core/ModuleList.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,12 @@ bool ModuleListProperties::SetEnableExternalLookup(bool new_value) {
130130
nullptr, ePropertyEnableExternalLookup, new_value);
131131
}
132132

133+
bool ModuleListProperties::GetEnableBackgroundLookup() const {
134+
const uint32_t idx = ePropertyEnableBackgroundLookup;
135+
return m_collection_sp->GetPropertyAtIndexAsBoolean(
136+
nullptr, idx, g_modulelist_properties[idx].default_uint_value != 0);
137+
}
138+
133139
FileSpec ModuleListProperties::GetClangModulesCachePath() const {
134140
return m_collection_sp
135141
->GetPropertyAtIndexAsOptionValueFileSpec(nullptr, false,
@@ -925,6 +931,10 @@ void ModuleList::FindSharedModules(const ModuleSpec &module_spec,
925931
GetSharedModuleList().FindModules(module_spec, matching_module_list);
926932
}
927933

934+
lldb::ModuleSP ModuleList::FindSharedModule(const UUID &uuid) {
935+
return GetSharedModuleList().FindModule(uuid);
936+
}
937+
928938
size_t ModuleList::RemoveOrphanSharedModules(bool mandatory) {
929939
return GetSharedModuleList().RemoveOrphans(mandatory);
930940
}

lldb/source/Symbol/LocateSymbolFile.cpp

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
#include "lldb/Symbol/LocateSymbolFile.h"
1010

11+
#include "lldb/Core/Debugger.h"
12+
#include "lldb/Core/Module.h"
1113
#include "lldb/Core/ModuleList.h"
1214
#include "lldb/Core/ModuleSpec.h"
1315
#include "lldb/Core/Progress.h"
@@ -23,7 +25,9 @@
2325
#include "lldb/Utility/Timer.h"
2426
#include "lldb/Utility/UUID.h"
2527

28+
#include "llvm/ADT/SmallSet.h"
2629
#include "llvm/Support/FileSystem.h"
30+
#include "llvm/Support/ThreadPool.h"
2731

2832
// From MacOSX system header "mach/machine.h"
2933
typedef int cpu_type_t;
@@ -381,6 +385,35 @@ Symbols::LocateExecutableSymbolFile(const ModuleSpec &module_spec,
381385
return LocateExecutableSymbolFileDsym(module_spec);
382386
}
383387

388+
void Symbols::DownloadSymbolFileAsync(const UUID &uuid) {
389+
if (!ModuleList::GetGlobalModuleListProperties().GetEnableBackgroundLookup())
390+
return;
391+
392+
static llvm::SmallSet<UUID, 8> g_seen_uuids;
393+
static std::mutex g_mutex;
394+
Debugger::GetThreadPool().async([=]() {
395+
{
396+
std::lock_guard<std::mutex> guard(g_mutex);
397+
if (g_seen_uuids.count(uuid))
398+
return;
399+
g_seen_uuids.insert(uuid);
400+
}
401+
402+
Status error;
403+
ModuleSpec module_spec;
404+
module_spec.GetUUID() = uuid;
405+
if (!Symbols::DownloadObjectAndSymbolFile(module_spec, error,
406+
/*force_lookup=*/true,
407+
/*copy_executable=*/false))
408+
return;
409+
410+
if (error.Fail())
411+
return;
412+
413+
Debugger::ReportSymbolChange(module_spec);
414+
});
415+
}
416+
384417
#if !defined(__APPLE__)
385418

386419
FileSpec Symbols::FindSymbolFileInBundle(const FileSpec &symfile_bundle,
@@ -391,7 +424,8 @@ FileSpec Symbols::FindSymbolFileInBundle(const FileSpec &symfile_bundle,
391424
}
392425

393426
bool Symbols::DownloadObjectAndSymbolFile(ModuleSpec &module_spec,
394-
Status &error, bool force_lookup) {
427+
Status &error, bool force_lookup,
428+
bool copy_executable) {
395429
// Fill in the module_spec.GetFileSpec() for the object file and/or the
396430
// module_spec.GetSymbolFileSpec() for the debug symbols file.
397431
return false;

0 commit comments

Comments
 (0)