15f757f3fSDimitry Andric //===-- SymbolLocatorDebuginfod.cpp ---------------------------------------===//
25f757f3fSDimitry Andric //
35f757f3fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45f757f3fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55f757f3fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65f757f3fSDimitry Andric //
75f757f3fSDimitry Andric //===----------------------------------------------------------------------===//
85f757f3fSDimitry Andric
95f757f3fSDimitry Andric #include "SymbolLocatorDebuginfod.h"
105f757f3fSDimitry Andric
115f757f3fSDimitry Andric #include "lldb/Core/PluginManager.h"
12*7a6dacacSDimitry Andric #include "lldb/Interpreter/OptionValueString.h"
135f757f3fSDimitry Andric #include "lldb/Utility/Args.h"
14*7a6dacacSDimitry Andric #include "lldb/Utility/LLDBLog.h"
15*7a6dacacSDimitry Andric #include "lldb/Utility/Log.h"
165f757f3fSDimitry Andric
175f757f3fSDimitry Andric #include "llvm/Debuginfod/Debuginfod.h"
185f757f3fSDimitry Andric #include "llvm/Debuginfod/HTTPClient.h"
195f757f3fSDimitry Andric
205f757f3fSDimitry Andric using namespace lldb;
215f757f3fSDimitry Andric using namespace lldb_private;
225f757f3fSDimitry Andric
235f757f3fSDimitry Andric LLDB_PLUGIN_DEFINE(SymbolLocatorDebuginfod)
245f757f3fSDimitry Andric
255f757f3fSDimitry Andric namespace {
265f757f3fSDimitry Andric
275f757f3fSDimitry Andric #define LLDB_PROPERTIES_symbollocatordebuginfod
285f757f3fSDimitry Andric #include "SymbolLocatorDebuginfodProperties.inc"
295f757f3fSDimitry Andric
305f757f3fSDimitry Andric enum {
315f757f3fSDimitry Andric #define LLDB_PROPERTIES_symbollocatordebuginfod
325f757f3fSDimitry Andric #include "SymbolLocatorDebuginfodPropertiesEnum.inc"
335f757f3fSDimitry Andric };
345f757f3fSDimitry Andric
355f757f3fSDimitry Andric class PluginProperties : public Properties {
365f757f3fSDimitry Andric public:
GetSettingName()375f757f3fSDimitry Andric static llvm::StringRef GetSettingName() {
385f757f3fSDimitry Andric return SymbolLocatorDebuginfod::GetPluginNameStatic();
395f757f3fSDimitry Andric }
405f757f3fSDimitry Andric
PluginProperties()415f757f3fSDimitry Andric PluginProperties() {
425f757f3fSDimitry Andric m_collection_sp = std::make_shared<OptionValueProperties>(GetSettingName());
435f757f3fSDimitry Andric m_collection_sp->Initialize(g_symbollocatordebuginfod_properties);
445f757f3fSDimitry Andric
455f757f3fSDimitry Andric // We need to read the default value first to read the environment variable.
465f757f3fSDimitry Andric llvm::SmallVector<llvm::StringRef> urls = llvm::getDefaultDebuginfodUrls();
475f757f3fSDimitry Andric Args arg_urls{urls};
485f757f3fSDimitry Andric m_collection_sp->SetPropertyAtIndexFromArgs(ePropertyServerURLs, arg_urls);
495f757f3fSDimitry Andric
505f757f3fSDimitry Andric m_collection_sp->SetValueChangedCallback(
515f757f3fSDimitry Andric ePropertyServerURLs, [this] { ServerURLsChangedCallback(); });
525f757f3fSDimitry Andric }
535f757f3fSDimitry Andric
GetDebugInfoDURLs() const545f757f3fSDimitry Andric Args GetDebugInfoDURLs() const {
555f757f3fSDimitry Andric Args urls;
565f757f3fSDimitry Andric m_collection_sp->GetPropertyAtIndexAsArgs(ePropertyServerURLs, urls);
575f757f3fSDimitry Andric return urls;
585f757f3fSDimitry Andric }
595f757f3fSDimitry Andric
GetCachePath()60*7a6dacacSDimitry Andric llvm::Expected<std::string> GetCachePath() {
61*7a6dacacSDimitry Andric OptionValueString *s =
62*7a6dacacSDimitry Andric m_collection_sp->GetPropertyAtIndexAsOptionValueString(
63*7a6dacacSDimitry Andric ePropertySymbolCachePath);
64*7a6dacacSDimitry Andric // If we don't have a valid cache location, use the default one.
65*7a6dacacSDimitry Andric if (!s || !s->GetCurrentValueAsRef().size()) {
66*7a6dacacSDimitry Andric llvm::Expected<std::string> maybeCachePath =
67*7a6dacacSDimitry Andric llvm::getDefaultDebuginfodCacheDirectory();
68*7a6dacacSDimitry Andric if (!maybeCachePath)
69*7a6dacacSDimitry Andric return maybeCachePath;
70*7a6dacacSDimitry Andric return *maybeCachePath;
71*7a6dacacSDimitry Andric }
72*7a6dacacSDimitry Andric return s->GetCurrentValue();
73*7a6dacacSDimitry Andric }
74*7a6dacacSDimitry Andric
GetTimeout() const75*7a6dacacSDimitry Andric std::chrono::milliseconds GetTimeout() const {
76*7a6dacacSDimitry Andric std::optional<uint64_t> seconds =
77*7a6dacacSDimitry Andric m_collection_sp->GetPropertyAtIndexAs<uint64_t>(ePropertyTimeout);
78*7a6dacacSDimitry Andric if (seconds && *seconds != 0) {
79*7a6dacacSDimitry Andric return std::chrono::duration_cast<std::chrono::milliseconds>(
80*7a6dacacSDimitry Andric std::chrono::seconds(*seconds));
81*7a6dacacSDimitry Andric } else {
82*7a6dacacSDimitry Andric return llvm::getDefaultDebuginfodTimeout();
83*7a6dacacSDimitry Andric }
84*7a6dacacSDimitry Andric }
85*7a6dacacSDimitry Andric
865f757f3fSDimitry Andric private:
ServerURLsChangedCallback()875f757f3fSDimitry Andric void ServerURLsChangedCallback() {
885f757f3fSDimitry Andric m_server_urls = GetDebugInfoDURLs();
895f757f3fSDimitry Andric llvm::SmallVector<llvm::StringRef> dbginfod_urls;
905f757f3fSDimitry Andric llvm::for_each(m_server_urls, [&](const auto &obj) {
915f757f3fSDimitry Andric dbginfod_urls.push_back(obj.ref());
925f757f3fSDimitry Andric });
935f757f3fSDimitry Andric llvm::setDefaultDebuginfodUrls(dbginfod_urls);
945f757f3fSDimitry Andric }
955f757f3fSDimitry Andric // Storage for the StringRef's used within the Debuginfod library.
965f757f3fSDimitry Andric Args m_server_urls;
975f757f3fSDimitry Andric };
985f757f3fSDimitry Andric
995f757f3fSDimitry Andric } // namespace
1005f757f3fSDimitry Andric
GetGlobalPluginProperties()1015f757f3fSDimitry Andric static PluginProperties &GetGlobalPluginProperties() {
1025f757f3fSDimitry Andric static PluginProperties g_settings;
1035f757f3fSDimitry Andric return g_settings;
1045f757f3fSDimitry Andric }
1055f757f3fSDimitry Andric
SymbolLocatorDebuginfod()1065f757f3fSDimitry Andric SymbolLocatorDebuginfod::SymbolLocatorDebuginfod() : SymbolLocator() {}
1075f757f3fSDimitry Andric
Initialize()1085f757f3fSDimitry Andric void SymbolLocatorDebuginfod::Initialize() {
1095f757f3fSDimitry Andric static llvm::once_flag g_once_flag;
1105f757f3fSDimitry Andric
1115f757f3fSDimitry Andric llvm::call_once(g_once_flag, []() {
1125f757f3fSDimitry Andric PluginManager::RegisterPlugin(
1135f757f3fSDimitry Andric GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance,
1145f757f3fSDimitry Andric LocateExecutableObjectFile, LocateExecutableSymbolFile, nullptr,
1155f757f3fSDimitry Andric nullptr, SymbolLocatorDebuginfod::DebuggerInitialize);
1165f757f3fSDimitry Andric llvm::HTTPClient::initialize();
1175f757f3fSDimitry Andric });
1185f757f3fSDimitry Andric }
1195f757f3fSDimitry Andric
DebuggerInitialize(Debugger & debugger)1205f757f3fSDimitry Andric void SymbolLocatorDebuginfod::DebuggerInitialize(Debugger &debugger) {
1215f757f3fSDimitry Andric if (!PluginManager::GetSettingForSymbolLocatorPlugin(
1225f757f3fSDimitry Andric debugger, PluginProperties::GetSettingName())) {
1235f757f3fSDimitry Andric const bool is_global_setting = true;
1245f757f3fSDimitry Andric PluginManager::CreateSettingForSymbolLocatorPlugin(
1255f757f3fSDimitry Andric debugger, GetGlobalPluginProperties().GetValueProperties(),
1265f757f3fSDimitry Andric "Properties for the Debuginfod Symbol Locator plug-in.",
1275f757f3fSDimitry Andric is_global_setting);
1285f757f3fSDimitry Andric }
1295f757f3fSDimitry Andric }
1305f757f3fSDimitry Andric
Terminate()1315f757f3fSDimitry Andric void SymbolLocatorDebuginfod::Terminate() {
1325f757f3fSDimitry Andric PluginManager::UnregisterPlugin(CreateInstance);
1335f757f3fSDimitry Andric llvm::HTTPClient::cleanup();
1345f757f3fSDimitry Andric }
1355f757f3fSDimitry Andric
GetPluginDescriptionStatic()1365f757f3fSDimitry Andric llvm::StringRef SymbolLocatorDebuginfod::GetPluginDescriptionStatic() {
1375f757f3fSDimitry Andric return "Debuginfod symbol locator.";
1385f757f3fSDimitry Andric }
1395f757f3fSDimitry Andric
CreateInstance()1405f757f3fSDimitry Andric SymbolLocator *SymbolLocatorDebuginfod::CreateInstance() {
1415f757f3fSDimitry Andric return new SymbolLocatorDebuginfod();
1425f757f3fSDimitry Andric }
1435f757f3fSDimitry Andric
144*7a6dacacSDimitry Andric static std::optional<FileSpec>
GetFileForModule(const ModuleSpec & module_spec,std::function<std::string (llvm::object::BuildID)> UrlBuilder)145*7a6dacacSDimitry Andric GetFileForModule(const ModuleSpec &module_spec,
146*7a6dacacSDimitry Andric std::function<std::string(llvm::object::BuildID)> UrlBuilder) {
1475f757f3fSDimitry Andric const UUID &module_uuid = module_spec.GetUUID();
148*7a6dacacSDimitry Andric // Don't bother if we don't have a valid UUID, Debuginfod isn't available,
149*7a6dacacSDimitry Andric // or if the 'symbols.enable-external-lookup' setting is false.
150*7a6dacacSDimitry Andric if (!module_uuid.IsValid() || !llvm::canUseDebuginfod() ||
151*7a6dacacSDimitry Andric !ModuleList::GetGlobalModuleListProperties().GetEnableExternalLookup())
152*7a6dacacSDimitry Andric return {};
153*7a6dacacSDimitry Andric
154*7a6dacacSDimitry Andric // Grab LLDB's Debuginfod overrides from the
155*7a6dacacSDimitry Andric // plugin.symbol-locator.debuginfod.* settings.
156*7a6dacacSDimitry Andric PluginProperties &plugin_props = GetGlobalPluginProperties();
157*7a6dacacSDimitry Andric llvm::Expected<std::string> cache_path_or_err = plugin_props.GetCachePath();
158*7a6dacacSDimitry Andric // A cache location is *required*.
159*7a6dacacSDimitry Andric if (!cache_path_or_err)
160*7a6dacacSDimitry Andric return {};
161*7a6dacacSDimitry Andric std::string cache_path = *cache_path_or_err;
162*7a6dacacSDimitry Andric llvm::SmallVector<llvm::StringRef> debuginfod_urls =
163*7a6dacacSDimitry Andric llvm::getDefaultDebuginfodUrls();
164*7a6dacacSDimitry Andric std::chrono::milliseconds timeout = plugin_props.GetTimeout();
165*7a6dacacSDimitry Andric
166*7a6dacacSDimitry Andric // We're ready to ask the Debuginfod library to find our file.
1675f757f3fSDimitry Andric llvm::object::BuildID build_id(module_uuid.GetBytes());
168*7a6dacacSDimitry Andric std::string url_path = UrlBuilder(build_id);
169*7a6dacacSDimitry Andric std::string cache_key = llvm::getDebuginfodCacheKey(url_path);
170*7a6dacacSDimitry Andric llvm::Expected<std::string> result = llvm::getCachedOrDownloadArtifact(
171*7a6dacacSDimitry Andric cache_key, url_path, cache_path, debuginfod_urls, timeout);
1725f757f3fSDimitry Andric if (result)
1735f757f3fSDimitry Andric return FileSpec(*result);
174*7a6dacacSDimitry Andric
175*7a6dacacSDimitry Andric Log *log = GetLog(LLDBLog::Symbols);
176*7a6dacacSDimitry Andric auto err_message = llvm::toString(result.takeError());
177*7a6dacacSDimitry Andric LLDB_LOGV(log,
178*7a6dacacSDimitry Andric "Debuginfod failed to download symbol artifact {0} with error {1}",
179*7a6dacacSDimitry Andric url_path, err_message);
1805f757f3fSDimitry Andric return {};
1815f757f3fSDimitry Andric }
1825f757f3fSDimitry Andric
LocateExecutableObjectFile(const ModuleSpec & module_spec)1835f757f3fSDimitry Andric std::optional<ModuleSpec> SymbolLocatorDebuginfod::LocateExecutableObjectFile(
1845f757f3fSDimitry Andric const ModuleSpec &module_spec) {
185*7a6dacacSDimitry Andric return GetFileForModule(module_spec, llvm::getDebuginfodExecutableUrlPath);
1865f757f3fSDimitry Andric }
1875f757f3fSDimitry Andric
LocateExecutableSymbolFile(const ModuleSpec & module_spec,const FileSpecList & default_search_paths)1885f757f3fSDimitry Andric std::optional<FileSpec> SymbolLocatorDebuginfod::LocateExecutableSymbolFile(
1895f757f3fSDimitry Andric const ModuleSpec &module_spec, const FileSpecList &default_search_paths) {
190*7a6dacacSDimitry Andric return GetFileForModule(module_spec, llvm::getDebuginfodDebuginfoUrlPath);
1915f757f3fSDimitry Andric }
192