LLDB mainline
SymbolLocator.cpp
Go to the documentation of this file.
1//===-- symbolLocator.cpp -------------------------------------------------===//
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
10
11#include "lldb/Core/Debugger.h"
13#include "lldb/Core/Progress.h"
15#include "lldb/Host/Host.h"
17
18#include "llvm/ADT/STLExtras.h"
19#include "llvm/ADT/SmallSet.h"
20#include "llvm/Support/ThreadPool.h"
21
22using namespace lldb;
23using namespace lldb_private;
24
26
27void SymbolLocator::NotFound::log(llvm::raw_ostream &os) const {
28 os << "binary not found";
29}
30
32 return std::make_error_code(std::errc::no_such_file_or_directory);
33}
34
35llvm::Expected<SymbolLocator::Result>
37 const FileSpecList &search_paths) {
39 Result result;
40 ModuleSpec &module_spec = result.module_spec;
41 module_spec = request.module_spec;
42
43 // Can lldb's symbol and executable location schemes find them locally?
45 module_spec, search_paths, result.statistics);
46 module_spec.GetFileSpec() =
48 .GetFileSpec();
49
50 // If we're still missing either file, see if an external symbol server can
51 // provide it.
52 if (!fs.Exists(module_spec.GetFileSpec()) ||
53 !fs.Exists(module_spec.GetSymbolFileSpec())) {
55 const bool downloaded = PluginManager::DownloadObjectAndSymbolFile(
56 module_spec, error, request.external_lookup);
57 // The plugins share one Status, so a failure recorded along the way says
58 // nothing about a search that ended in a download.
59 if (!downloaded && error.Fail() && request.external_lookup)
60 result.symbol_error.emplace(error.takeError());
61 }
62
63 // Not finding the binary is the one hard failure. Whatever a symbol server
64 // had to say is the best explanation available for it. Without one there is
65 // nothing to add beyond the fact of the miss.
66 if (!fs.Exists(module_spec.GetFileSpec())) {
67 if (result.symbol_error)
68 return std::move(*result.symbol_error);
69 return llvm::make_error<NotFound>();
70 }
71
72 return result;
73}
74
75static std::optional<SymbolLocator::Result>
77 const FileSpecList &search_paths) {
78 if (!request.platform)
79 return std::nullopt;
80
82 std::optional<ModuleSpec> found = request.platform->FindModuleFiles(
83 request.module_spec, search_paths, result.statistics);
84 if (!found)
85 return std::nullopt;
86
87 result.module_spec = *found;
88 return result;
89}
90
91llvm::Expected<SymbolLocator::Result>
93 const FileSpecList &search_paths) {
94 if (std::optional<Result> answer = AskPlatform(request, search_paths))
95 return std::move(*answer);
96 return LocateWithPlugins(request, search_paths);
97}
98
99std::vector<llvm::Expected<SymbolLocator::Result>>
100SymbolLocator::Locate(llvm::ArrayRef<Request> requests,
101 const FileSpecList &search_paths, bool parallel) {
102 // One slot per request, so concurrent searches never contend.
103 std::vector<std::optional<llvm::Expected<Result>>> slots(requests.size());
104 std::vector<size_t> remaining;
105
106 if (!requests.empty()) {
107 // Throttled because every search reports through this from its own thread.
108 Progress progress("Locating binaries", "", requests.size(),
109 /*debugger=*/nullptr,
111
112 for (auto [i, request] : llvm::enumerate(requests)) {
113 if (std::optional<Result> answer = AskPlatform(request, search_paths)) {
114 slots[i] = std::move(*answer);
115 progress.Increment(1, request.description);
116 } else {
117 remaining.push_back(i);
118 }
119 }
120
121 auto locate = [&](size_t i) {
122 slots[i] = LocateWithPlugins(requests[i], search_paths);
123 progress.Increment(1, requests[i].description);
124 };
125
126 // One search has nothing to overlap with.
127 if (parallel && remaining.size() > 1) {
128 llvm::ThreadPoolTaskGroup task_group(Debugger::GetThreadPool());
129 for (size_t i : remaining)
130 task_group.async(locate, i);
131 task_group.wait();
132 } else {
133 for (size_t i : remaining)
134 locate(i);
135 }
136 }
137
138 std::vector<llvm::Expected<Result>> results;
139 results.reserve(slots.size());
140 for (std::optional<llvm::Expected<Result>> &slot : slots) {
141 assert(slot && "every request has a result");
142 results.emplace_back(std::move(*slot));
143 }
144 return results;
145}
146
148 static llvm::SmallSet<UUID, 8> g_seen_uuids;
149 static std::mutex g_mutex;
150
151 auto lookup = [=]() {
152 {
153 std::lock_guard<std::mutex> guard(g_mutex);
154 if (g_seen_uuids.count(uuid))
155 return;
156 g_seen_uuids.insert(uuid);
157 }
158
160 ModuleSpec module_spec;
161 module_spec.GetUUID() = uuid;
163 /*force_lookup=*/true,
164 /*copy_executable=*/true))
165 return;
166
167 if (error.Fail())
168 return;
169
170 Debugger::ReportSymbolChange(module_spec);
171 };
172
173 switch (ModuleList::GetGlobalModuleListProperties().GetSymbolAutoDownload()) {
175 break;
177 Debugger::GetThreadPool().async(lookup);
178 break;
180 lookup();
181 break;
182 };
183}
static llvm::raw_ostream & error(Stream &strm)
static std::optional< SymbolLocator::Result > AskPlatform(const SymbolLocator::Request &request, const FileSpecList &search_paths)
static llvm::ThreadPoolInterface & GetThreadPool()
Shared thread pool. Use only with ThreadPoolTaskGroup.
static void ReportSymbolChange(const ModuleSpec &module_spec)
A file collection class.
bool Exists(const FileSpec &file_spec) const
Returns whether the given file exists.
static FileSystem & Instance()
static ModuleListProperties & GetGlobalModuleListProperties()
FileSpec & GetFileSpec()
Definition ModuleSpec.h:57
FileSpec & GetSymbolFileSpec()
Definition ModuleSpec.h:81
static bool DownloadObjectAndSymbolFile(ModuleSpec &module_spec, Status &error, bool force_lookup=true, bool copy_executable=true)
static FileSpec LocateExecutableSymbolFile(const ModuleSpec &module_spec, const FileSpecList &default_search_paths, StatisticsMap &map)
static ModuleSpec LocateExecutableObjectFile(const ModuleSpec &module_spec, StatisticsMap &map)
A Progress indicator helper class.
Definition Progress.h:60
void Increment(uint64_t amount=1, std::optional< std::string > updated_detail={})
Increment the progress and send a notification to the installed callback.
Definition Progress.cpp:62
static constexpr std::chrono::milliseconds kDefaultHighFrequencyReportTime
The default report time for high frequency progress reports.
Definition Progress.h:119
An error handling class.
Definition Status.h:118
std::error_code convertToErrorCode() const override
void log(llvm::raw_ostream &os) const override
static void DownloadSymbolFileAsync(const UUID &uuid)
Locate the symbol file for the given UUID on a background thread.
static llvm::Expected< Result > Locate(const Request &request, const FileSpecList &search_paths)
Find a binary and, if possible, its symbols.
static llvm::Expected< Result > LocateWithPlugins(const Request &request, const FileSpecList &search_paths)
Must stay callable concurrently.
Represents UUID's of various sizes.
Definition UUID.h:27
A class that represents a running process on the host machine.
@ eSymbolDownloadBackground
@ eSymbolDownloadForeground
One binary to search for.
lldb::PlatformSP platform
A platform that may know where the binary is.
ModuleSpec module_spec
What to look for.
bool external_lookup
Allow contacting an external symbol server when the local searches come up empty.
std::optional< llvm::Error > symbol_error
What an external symbol server had to say about the symbols, even though the binary itself was found.
StatisticsMap statistics
Where the time went, to be merged into the Module once it exists.
ModuleSpec module_spec
The binary, and its symbol file if there is one to be had.