//===-- SymbolLocatorDebuginfod.cpp ---------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "SymbolLocatorDebuginfod.h" #include "lldb/Core/PluginManager.h" #include "lldb/Interpreter/OptionValueString.h" #include "lldb/Utility/Args.h" #include "lldb/Utility/LLDBLog.h" #include "lldb/Utility/Log.h" #include "llvm/Debuginfod/Debuginfod.h" #include "llvm/Debuginfod/HTTPClient.h" using namespace lldb; using namespace lldb_private; LLDB_PLUGIN_DEFINE(SymbolLocatorDebuginfod) namespace { #define LLDB_PROPERTIES_symbollocatordebuginfod #include "SymbolLocatorDebuginfodProperties.inc" enum { #define LLDB_PROPERTIES_symbollocatordebuginfod #include "SymbolLocatorDebuginfodPropertiesEnum.inc" }; class PluginProperties : public Properties { public: static llvm::StringRef GetSettingName() { return SymbolLocatorDebuginfod::GetPluginNameStatic(); } PluginProperties() { m_collection_sp = std::make_shared(GetSettingName()); m_collection_sp->Initialize(g_symbollocatordebuginfod_properties); // We need to read the default value first to read the environment variable. llvm::SmallVector urls = llvm::getDefaultDebuginfodUrls(); Args arg_urls{urls}; m_collection_sp->SetPropertyAtIndexFromArgs(ePropertyServerURLs, arg_urls); m_collection_sp->SetValueChangedCallback( ePropertyServerURLs, [this] { ServerURLsChangedCallback(); }); } Args GetDebugInfoDURLs() const { Args urls; m_collection_sp->GetPropertyAtIndexAsArgs(ePropertyServerURLs, urls); return urls; } llvm::Expected GetCachePath() { OptionValueString *s = m_collection_sp->GetPropertyAtIndexAsOptionValueString( ePropertySymbolCachePath); // If we don't have a valid cache location, use the default one. if (!s || !s->GetCurrentValueAsRef().size()) { llvm::Expected maybeCachePath = llvm::getDefaultDebuginfodCacheDirectory(); if (!maybeCachePath) return maybeCachePath; return *maybeCachePath; } return s->GetCurrentValue(); } std::chrono::milliseconds GetTimeout() const { std::optional seconds = m_collection_sp->GetPropertyAtIndexAs(ePropertyTimeout); if (seconds && *seconds != 0) { return std::chrono::duration_cast( std::chrono::seconds(*seconds)); } else { return llvm::getDefaultDebuginfodTimeout(); } } private: void ServerURLsChangedCallback() { m_server_urls = GetDebugInfoDURLs(); llvm::SmallVector dbginfod_urls; llvm::for_each(m_server_urls, [&](const auto &obj) { dbginfod_urls.push_back(obj.ref()); }); llvm::setDefaultDebuginfodUrls(dbginfod_urls); } // Storage for the StringRef's used within the Debuginfod library. Args m_server_urls; }; } // namespace static PluginProperties &GetGlobalPluginProperties() { static PluginProperties g_settings; return g_settings; } SymbolLocatorDebuginfod::SymbolLocatorDebuginfod() : SymbolLocator() {} void SymbolLocatorDebuginfod::Initialize() { static llvm::once_flag g_once_flag; llvm::call_once(g_once_flag, []() { PluginManager::RegisterPlugin( GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance, LocateExecutableObjectFile, LocateExecutableSymbolFile, nullptr, nullptr, SymbolLocatorDebuginfod::DebuggerInitialize); llvm::HTTPClient::initialize(); }); } void SymbolLocatorDebuginfod::DebuggerInitialize(Debugger &debugger) { if (!PluginManager::GetSettingForSymbolLocatorPlugin( debugger, PluginProperties::GetSettingName())) { const bool is_global_setting = true; PluginManager::CreateSettingForSymbolLocatorPlugin( debugger, GetGlobalPluginProperties().GetValueProperties(), "Properties for the Debuginfod Symbol Locator plug-in.", is_global_setting); } } void SymbolLocatorDebuginfod::Terminate() { PluginManager::UnregisterPlugin(CreateInstance); llvm::HTTPClient::cleanup(); } llvm::StringRef SymbolLocatorDebuginfod::GetPluginDescriptionStatic() { return "Debuginfod symbol locator."; } SymbolLocator *SymbolLocatorDebuginfod::CreateInstance() { return new SymbolLocatorDebuginfod(); } static std::optional GetFileForModule(const ModuleSpec &module_spec, std::function UrlBuilder) { const UUID &module_uuid = module_spec.GetUUID(); // Don't bother if we don't have a valid UUID, Debuginfod isn't available, // or if the 'symbols.enable-external-lookup' setting is false. if (!module_uuid.IsValid() || !llvm::canUseDebuginfod() || !ModuleList::GetGlobalModuleListProperties().GetEnableExternalLookup()) return {}; // Grab LLDB's Debuginfod overrides from the // plugin.symbol-locator.debuginfod.* settings. PluginProperties &plugin_props = GetGlobalPluginProperties(); llvm::Expected cache_path_or_err = plugin_props.GetCachePath(); // A cache location is *required*. if (!cache_path_or_err) return {}; std::string cache_path = *cache_path_or_err; llvm::SmallVector debuginfod_urls = llvm::getDefaultDebuginfodUrls(); std::chrono::milliseconds timeout = plugin_props.GetTimeout(); // We're ready to ask the Debuginfod library to find our file. llvm::object::BuildID build_id(module_uuid.GetBytes()); std::string url_path = UrlBuilder(build_id); std::string cache_key = llvm::getDebuginfodCacheKey(url_path); llvm::Expected result = llvm::getCachedOrDownloadArtifact( cache_key, url_path, cache_path, debuginfod_urls, timeout); if (result) return FileSpec(*result); Log *log = GetLog(LLDBLog::Symbols); auto err_message = llvm::toString(result.takeError()); LLDB_LOGV(log, "Debuginfod failed to download symbol artifact {0} with error {1}", url_path, err_message); return {}; } std::optional SymbolLocatorDebuginfod::LocateExecutableObjectFile( const ModuleSpec &module_spec) { return GetFileForModule(module_spec, llvm::getDebuginfodExecutableUrlPath); } std::optional SymbolLocatorDebuginfod::LocateExecutableSymbolFile( const ModuleSpec &module_spec, const FileSpecList &default_search_paths) { return GetFileForModule(module_spec, llvm::getDebuginfodDebuginfoUrlPath); }