xref: /freebsd/contrib/llvm-project/lldb/source/Plugins/SymbolLocator/Default/SymbolLocatorDefault.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1 //===-- SymbolLocatorDefault.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 "SymbolLocatorDefault.h"
10 
11 #include <cstring>
12 #include <optional>
13 
14 #include "Plugins/ObjectFile/wasm/ObjectFileWasm.h"
15 #include "lldb/Core/Debugger.h"
16 #include "lldb/Core/Module.h"
17 #include "lldb/Core/ModuleList.h"
18 #include "lldb/Core/ModuleSpec.h"
19 #include "lldb/Core/PluginManager.h"
20 #include "lldb/Core/Progress.h"
21 #include "lldb/Core/Section.h"
22 #include "lldb/Host/FileSystem.h"
23 #include "lldb/Host/Host.h"
24 #include "lldb/Symbol/ObjectFile.h"
25 #include "lldb/Target/Target.h"
26 #include "lldb/Utility/ArchSpec.h"
27 #include "lldb/Utility/DataBuffer.h"
28 #include "lldb/Utility/DataExtractor.h"
29 #include "lldb/Utility/LLDBLog.h"
30 #include "lldb/Utility/Log.h"
31 #include "lldb/Utility/StreamString.h"
32 #include "lldb/Utility/Timer.h"
33 #include "lldb/Utility/UUID.h"
34 
35 #include "llvm/ADT/SmallSet.h"
36 #include "llvm/Support/FileSystem.h"
37 #include "llvm/Support/ThreadPool.h"
38 
39 #if defined(__FreeBSD__)
40 #include <sys/sysctl.h>
41 #endif
42 
43 // From MacOSX system header "mach/machine.h"
44 typedef int cpu_type_t;
45 typedef int cpu_subtype_t;
46 
47 using namespace lldb;
48 using namespace lldb_private;
49 
LLDB_PLUGIN_DEFINE(SymbolLocatorDefault)50 LLDB_PLUGIN_DEFINE(SymbolLocatorDefault)
51 
52 SymbolLocatorDefault::SymbolLocatorDefault() : SymbolLocator() {}
53 
Initialize()54 void SymbolLocatorDefault::Initialize() {
55   PluginManager::RegisterPlugin(
56       GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance,
57       LocateExecutableObjectFile, LocateExecutableSymbolFile,
58       DownloadObjectAndSymbolFile);
59 }
60 
Terminate()61 void SymbolLocatorDefault::Terminate() {
62   PluginManager::UnregisterPlugin(CreateInstance);
63 }
64 
GetPluginDescriptionStatic()65 llvm::StringRef SymbolLocatorDefault::GetPluginDescriptionStatic() {
66   return "Default symbol locator.";
67 }
68 
CreateInstance()69 SymbolLocator *SymbolLocatorDefault::CreateInstance() {
70   return new SymbolLocatorDefault();
71 }
72 
LocateExecutableObjectFile(const ModuleSpec & module_spec)73 std::optional<ModuleSpec> SymbolLocatorDefault::LocateExecutableObjectFile(
74     const ModuleSpec &module_spec) {
75   const FileSpec &exec_fspec = module_spec.GetFileSpec();
76   const ArchSpec *arch = module_spec.GetArchitecturePtr();
77   const UUID *uuid = module_spec.GetUUIDPtr();
78   LLDB_SCOPED_TIMERF(
79       "LocateExecutableObjectFile (file = %s, arch = %s, uuid = %p)",
80       exec_fspec ? exec_fspec.GetFilename().AsCString("<NULL>") : "<NULL>",
81       arch ? arch->GetArchitectureName() : "<NULL>", (const void *)uuid);
82 
83   ModuleSpecList module_specs;
84   ModuleSpec matched_module_spec;
85   if (exec_fspec &&
86       ObjectFile::GetModuleSpecifications(exec_fspec, 0, 0, module_specs) &&
87       module_specs.FindMatchingModuleSpec(module_spec, matched_module_spec)) {
88     ModuleSpec result;
89     result.GetFileSpec() = exec_fspec;
90     return result;
91   }
92 
93   return {};
94 }
95 
96 // Keep "symbols.enable-external-lookup" description in sync with this function.
LocateExecutableSymbolFile(const ModuleSpec & module_spec,const FileSpecList & default_search_paths)97 std::optional<FileSpec> SymbolLocatorDefault::LocateExecutableSymbolFile(
98     const ModuleSpec &module_spec, const FileSpecList &default_search_paths) {
99 
100   FileSpec symbol_file_spec = module_spec.GetSymbolFileSpec();
101   if (symbol_file_spec.IsAbsolute() &&
102       FileSystem::Instance().Exists(symbol_file_spec))
103     return symbol_file_spec;
104 
105   Progress progress(
106       "Locating external symbol file",
107       module_spec.GetFileSpec().GetFilename().AsCString("<Unknown>"));
108 
109   FileSpecList debug_file_search_paths = default_search_paths;
110 
111   // Add module directory.
112   FileSpec module_file_spec = module_spec.GetFileSpec();
113   // We keep the unresolved pathname if it fails.
114   FileSystem::Instance().ResolveSymbolicLink(module_file_spec,
115                                              module_file_spec);
116 
117   ConstString file_dir = module_file_spec.GetDirectory();
118   {
119     FileSpec file_spec(file_dir.AsCString("."));
120     FileSystem::Instance().Resolve(file_spec);
121     debug_file_search_paths.AppendIfUnique(file_spec);
122   }
123 
124   if (ModuleList::GetGlobalModuleListProperties().GetEnableExternalLookup()) {
125 
126     // Add current working directory.
127     {
128       FileSpec file_spec(".");
129       FileSystem::Instance().Resolve(file_spec);
130       debug_file_search_paths.AppendIfUnique(file_spec);
131     }
132 
133 #ifndef _WIN32
134 #if defined(__NetBSD__)
135     // Add /usr/libdata/debug directory.
136     {
137       FileSpec file_spec("/usr/libdata/debug");
138       FileSystem::Instance().Resolve(file_spec);
139       debug_file_search_paths.AppendIfUnique(file_spec);
140     }
141 #else
142     // Add /usr/lib/debug directory.
143     {
144       FileSpec file_spec("/usr/lib/debug");
145       FileSystem::Instance().Resolve(file_spec);
146       debug_file_search_paths.AppendIfUnique(file_spec);
147     }
148 #if defined(__FreeBSD__)
149     // Add $LOCALBASE/lib/debug directory, where LOCALBASE is
150     // usually /usr/local, but may be adjusted by the end user.
151     {
152       int mib[2];
153       char buf[PATH_MAX];
154       size_t len = PATH_MAX;
155 
156       mib[0] = CTL_USER;
157       mib[1] = USER_LOCALBASE;
158       if (::sysctl(mib, 2, buf, &len, NULL, 0) == 0) {
159         FileSpec file_spec("/lib/debug");
160         file_spec.PrependPathComponent(llvm::StringRef(buf));
161         FileSystem::Instance().Resolve(file_spec);
162         debug_file_search_paths.AppendIfUnique(file_spec);
163       }
164     }
165 #endif // __FreeBSD__
166 #endif
167 #endif // _WIN32
168   }
169 
170   std::string uuid_str;
171   const UUID &module_uuid = module_spec.GetUUID();
172   if (module_uuid.IsValid()) {
173     // Some debug files are stored in the .build-id directory like this:
174     //   /usr/lib/debug/.build-id/ff/e7fe727889ad82bb153de2ad065b2189693315.debug
175     uuid_str = module_uuid.GetAsString("");
176     std::transform(uuid_str.begin(), uuid_str.end(), uuid_str.begin(),
177                    ::tolower);
178     uuid_str.insert(2, 1, '/');
179     uuid_str = uuid_str + ".debug";
180   }
181 
182   size_t num_directories = debug_file_search_paths.GetSize();
183   for (size_t idx = 0; idx < num_directories; ++idx) {
184     FileSpec dirspec = debug_file_search_paths.GetFileSpecAtIndex(idx);
185     FileSystem::Instance().Resolve(dirspec);
186     if (!FileSystem::Instance().IsDirectory(dirspec))
187       continue;
188 
189     std::vector<std::string> files;
190     std::string dirname = dirspec.GetPath();
191 
192     if (!uuid_str.empty())
193       files.push_back(dirname + "/.build-id/" + uuid_str);
194     if (symbol_file_spec.GetFilename()) {
195       files.push_back(dirname + "/" +
196                       symbol_file_spec.GetFilename().GetCString());
197       files.push_back(dirname + "/.debug/" +
198                       symbol_file_spec.GetFilename().GetCString());
199 
200       // Some debug files may stored in the module directory like this:
201       //   /usr/lib/debug/usr/lib/library.so.debug
202       if (!file_dir.IsEmpty())
203         files.push_back(dirname + file_dir.AsCString() + "/" +
204                         symbol_file_spec.GetFilename().GetCString());
205     }
206 
207     const uint32_t num_files = files.size();
208     for (size_t idx_file = 0; idx_file < num_files; ++idx_file) {
209       const std::string &filename = files[idx_file];
210       FileSpec file_spec(filename);
211       FileSystem::Instance().Resolve(file_spec);
212 
213       if (llvm::sys::fs::equivalent(file_spec.GetPath(),
214                                     module_file_spec.GetPath()))
215         continue;
216 
217       if (FileSystem::Instance().Exists(file_spec)) {
218         lldb_private::ModuleSpecList specs;
219         const size_t num_specs =
220             ObjectFile::GetModuleSpecifications(file_spec, 0, 0, specs);
221         ModuleSpec mspec;
222         bool valid_mspec = false;
223         if (num_specs == 2) {
224           // Special case to handle both i386 and i686 from ObjectFilePECOFF
225           ModuleSpec mspec2;
226           if (specs.GetModuleSpecAtIndex(0, mspec) &&
227               specs.GetModuleSpecAtIndex(1, mspec2) &&
228               mspec.GetArchitecture().GetTriple().isCompatibleWith(
229                   mspec2.GetArchitecture().GetTriple())) {
230             valid_mspec = true;
231           }
232         }
233         if (!valid_mspec) {
234           assert(num_specs <= 1 &&
235                  "Symbol Vendor supports only a single architecture");
236           if (num_specs == 1) {
237             if (specs.GetModuleSpecAtIndex(0, mspec)) {
238               valid_mspec = true;
239             }
240           }
241         }
242         if (valid_mspec) {
243           // Skip the uuids check if module_uuid is invalid. For example,
244           // this happens for *.dwp files since at the moment llvm-dwp
245           // doesn't output build ids, nor does binutils dwp.
246           if (!module_uuid.IsValid() || module_uuid == mspec.GetUUID())
247             return file_spec;
248         }
249       }
250     }
251   }
252 
253   return {};
254 }
255 
DownloadObjectAndSymbolFile(ModuleSpec & module_spec,Status & error,bool force_lookup,bool copy_executable)256 bool SymbolLocatorDefault::DownloadObjectAndSymbolFile(ModuleSpec &module_spec,
257                                                        Status &error,
258                                                        bool force_lookup,
259                                                        bool copy_executable) {
260   return false;
261 }
262