1 //===-- SymbolLocatorDebuginfod.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 
9 #include "SymbolLocatorDebuginfod.h"
10 
11 #include "lldb/Core/PluginManager.h"
12 #include "lldb/Utility/Args.h"
13 
14 #include "llvm/Debuginfod/Debuginfod.h"
15 #include "llvm/Debuginfod/HTTPClient.h"
16 
17 using namespace lldb;
18 using namespace lldb_private;
19 
20 LLDB_PLUGIN_DEFINE(SymbolLocatorDebuginfod)
21 
22 namespace {
23 
24 #define LLDB_PROPERTIES_symbollocatordebuginfod
25 #include "SymbolLocatorDebuginfodProperties.inc"
26 
27 enum {
28 #define LLDB_PROPERTIES_symbollocatordebuginfod
29 #include "SymbolLocatorDebuginfodPropertiesEnum.inc"
30 };
31 
32 class PluginProperties : public Properties {
33 public:
34   static llvm::StringRef GetSettingName() {
35     return SymbolLocatorDebuginfod::GetPluginNameStatic();
36   }
37 
38   PluginProperties() {
39     m_collection_sp = std::make_shared<OptionValueProperties>(GetSettingName());
40     m_collection_sp->Initialize(g_symbollocatordebuginfod_properties);
41 
42     // We need to read the default value first to read the environment variable.
43     llvm::SmallVector<llvm::StringRef> urls = llvm::getDefaultDebuginfodUrls();
44     Args arg_urls{urls};
45     m_collection_sp->SetPropertyAtIndexFromArgs(ePropertyServerURLs, arg_urls);
46 
47     m_collection_sp->SetValueChangedCallback(
48         ePropertyServerURLs, [this] { ServerURLsChangedCallback(); });
49   }
50 
51   Args GetDebugInfoDURLs() const {
52     Args urls;
53     m_collection_sp->GetPropertyAtIndexAsArgs(ePropertyServerURLs, urls);
54     return urls;
55   }
56 
57 private:
58   void ServerURLsChangedCallback() {
59     m_server_urls = GetDebugInfoDURLs();
60     llvm::SmallVector<llvm::StringRef> dbginfod_urls;
61     llvm::for_each(m_server_urls, [&](const auto &obj) {
62       dbginfod_urls.push_back(obj.ref());
63     });
64     llvm::setDefaultDebuginfodUrls(dbginfod_urls);
65   }
66   // Storage for the StringRef's used within the Debuginfod library.
67   Args m_server_urls;
68 };
69 
70 } // namespace
71 
72 static PluginProperties &GetGlobalPluginProperties() {
73   static PluginProperties g_settings;
74   return g_settings;
75 }
76 
77 SymbolLocatorDebuginfod::SymbolLocatorDebuginfod() : SymbolLocator() {}
78 
79 void SymbolLocatorDebuginfod::Initialize() {
80   static llvm::once_flag g_once_flag;
81 
82   llvm::call_once(g_once_flag, []() {
83     PluginManager::RegisterPlugin(
84         GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance,
85         LocateExecutableObjectFile, LocateExecutableSymbolFile, nullptr,
86         nullptr, SymbolLocatorDebuginfod::DebuggerInitialize);
87     llvm::HTTPClient::initialize();
88   });
89 }
90 
91 void SymbolLocatorDebuginfod::DebuggerInitialize(Debugger &debugger) {
92   if (!PluginManager::GetSettingForSymbolLocatorPlugin(
93           debugger, PluginProperties::GetSettingName())) {
94     const bool is_global_setting = true;
95     PluginManager::CreateSettingForSymbolLocatorPlugin(
96         debugger, GetGlobalPluginProperties().GetValueProperties(),
97         "Properties for the Debuginfod Symbol Locator plug-in.",
98         is_global_setting);
99   }
100 }
101 
102 void SymbolLocatorDebuginfod::Terminate() {
103   PluginManager::UnregisterPlugin(CreateInstance);
104   llvm::HTTPClient::cleanup();
105 }
106 
107 llvm::StringRef SymbolLocatorDebuginfod::GetPluginDescriptionStatic() {
108   return "Debuginfod symbol locator.";
109 }
110 
111 SymbolLocator *SymbolLocatorDebuginfod::CreateInstance() {
112   return new SymbolLocatorDebuginfod();
113 }
114 
115 static std::optional<FileSpec> GetFileForModule(
116     const ModuleSpec &module_spec,
117     std::function<llvm::Expected<std::string>(llvm::object::BuildIDRef)>
118         PullFromServer) {
119   if (!ModuleList::GetGlobalModuleListProperties().GetEnableExternalLookup())
120     return {};
121   const UUID &module_uuid = module_spec.GetUUID();
122   if (module_uuid.IsValid() && llvm::canUseDebuginfod()) {
123     llvm::object::BuildID build_id(module_uuid.GetBytes());
124     llvm::Expected<std::string> result = PullFromServer(build_id);
125     if (result)
126       return FileSpec(*result);
127     // An error here should be logged as a failure in the Debuginfod library,
128     // so just consume it here
129     consumeError(result.takeError());
130   }
131   return {};
132 }
133 
134 std::optional<ModuleSpec> SymbolLocatorDebuginfod::LocateExecutableObjectFile(
135     const ModuleSpec &module_spec) {
136   return GetFileForModule(module_spec, llvm::getCachedOrDownloadExecutable);
137 }
138 
139 std::optional<FileSpec> SymbolLocatorDebuginfod::LocateExecutableSymbolFile(
140     const ModuleSpec &module_spec, const FileSpecList &default_search_paths) {
141   return GetFileForModule(module_spec, llvm::getCachedOrDownloadDebuginfo);
142 }
143