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// From MacOSX system header "mach/machine.h"
40typedef int cpu_type_t;
41typedef int cpu_subtype_t;
42
43using namespace lldb;
44using namespace lldb_private;
45
46LLDB_PLUGIN_DEFINE(SymbolLocatorDefault)
47
48SymbolLocatorDefault::SymbolLocatorDefault() : SymbolLocator() {}
49
50void SymbolLocatorDefault::Initialize() {
51 PluginManager::RegisterPlugin(
52 name: GetPluginNameStatic(), description: GetPluginDescriptionStatic(), create_callback: CreateInstance,
53 locate_executable_object_file: LocateExecutableObjectFile, locate_executable_symbol_file: LocateExecutableSymbolFile,
54 download_object_symbol_file: DownloadObjectAndSymbolFile);
55}
56
57void SymbolLocatorDefault::Terminate() {
58 PluginManager::UnregisterPlugin(create_callback: CreateInstance);
59}
60
61llvm::StringRef SymbolLocatorDefault::GetPluginDescriptionStatic() {
62 return "Default symbol locator.";
63}
64
65SymbolLocator *SymbolLocatorDefault::CreateInstance() {
66 return new SymbolLocatorDefault();
67}
68
69std::optional<ModuleSpec> SymbolLocatorDefault::LocateExecutableObjectFile(
70 const ModuleSpec &module_spec) {
71 const FileSpec &exec_fspec = module_spec.GetFileSpec();
72 const ArchSpec *arch = module_spec.GetArchitecturePtr();
73 const UUID *uuid = module_spec.GetUUIDPtr();
74 LLDB_SCOPED_TIMERF(
75 "LocateExecutableObjectFile (file = %s, arch = %s, uuid = %p)",
76 exec_fspec ? exec_fspec.GetFilename().AsCString("<NULL>") : "<NULL>",
77 arch ? arch->GetArchitectureName() : "<NULL>", (const void *)uuid);
78
79 ModuleSpecList module_specs;
80 ModuleSpec matched_module_spec;
81 if (exec_fspec &&
82 ObjectFile::GetModuleSpecifications(file: exec_fspec, file_offset: 0, file_size: 0, specs&: module_specs) &&
83 module_specs.FindMatchingModuleSpec(module_spec, match_module_spec&: matched_module_spec)) {
84 ModuleSpec result;
85 result.GetFileSpec() = exec_fspec;
86 return result;
87 }
88
89 return {};
90}
91
92// Keep "symbols.enable-external-lookup" description in sync with this function.
93std::optional<FileSpec> SymbolLocatorDefault::LocateExecutableSymbolFile(
94 const ModuleSpec &module_spec, const FileSpecList &default_search_paths) {
95
96 FileSpec symbol_file_spec = module_spec.GetSymbolFileSpec();
97 if (symbol_file_spec.IsAbsolute() &&
98 FileSystem::Instance().Exists(file_spec: symbol_file_spec))
99 return symbol_file_spec;
100
101 Progress progress(
102 "Locating external symbol file",
103 module_spec.GetFileSpec().GetFilename().AsCString(value_if_empty: "<Unknown>"));
104
105 FileSpecList debug_file_search_paths = default_search_paths;
106
107 // Add module directory.
108 FileSpec module_file_spec = module_spec.GetFileSpec();
109 // We keep the unresolved pathname if it fails.
110 FileSystem::Instance().ResolveSymbolicLink(src: module_file_spec,
111 dst&: module_file_spec);
112
113 ConstString file_dir = module_file_spec.GetDirectory();
114 {
115 FileSpec file_spec(file_dir.AsCString(value_if_empty: "."));
116 FileSystem::Instance().Resolve(file_spec);
117 debug_file_search_paths.AppendIfUnique(file: file_spec);
118 }
119
120 if (ModuleList::GetGlobalModuleListProperties().GetEnableExternalLookup()) {
121
122 // Add current working directory.
123 {
124 FileSpec file_spec(".");
125 FileSystem::Instance().Resolve(file_spec);
126 debug_file_search_paths.AppendIfUnique(file: file_spec);
127 }
128
129#ifndef _WIN32
130#if defined(__NetBSD__)
131 // Add /usr/libdata/debug directory.
132 {
133 FileSpec file_spec("/usr/libdata/debug");
134 FileSystem::Instance().Resolve(file_spec);
135 debug_file_search_paths.AppendIfUnique(file_spec);
136 }
137#else
138 // Add /usr/lib/debug directory.
139 {
140 FileSpec file_spec("/usr/lib/debug");
141 FileSystem::Instance().Resolve(file_spec);
142 debug_file_search_paths.AppendIfUnique(file: file_spec);
143 }
144#endif
145#endif // _WIN32
146 }
147
148 std::string uuid_str;
149 const UUID &module_uuid = module_spec.GetUUID();
150 if (module_uuid.IsValid()) {
151 // Some debug files are stored in the .build-id directory like this:
152 // /usr/lib/debug/.build-id/ff/e7fe727889ad82bb153de2ad065b2189693315.debug
153 uuid_str = module_uuid.GetAsString(separator: "");
154 std::transform(first: uuid_str.begin(), last: uuid_str.end(), result: uuid_str.begin(),
155 unary_op: ::tolower);
156 uuid_str.insert(pos: 2, n: 1, c: '/');
157 uuid_str = uuid_str + ".debug";
158 }
159
160 size_t num_directories = debug_file_search_paths.GetSize();
161 for (size_t idx = 0; idx < num_directories; ++idx) {
162 FileSpec dirspec = debug_file_search_paths.GetFileSpecAtIndex(idx);
163 FileSystem::Instance().Resolve(file_spec&: dirspec);
164 if (!FileSystem::Instance().IsDirectory(file_spec: dirspec))
165 continue;
166
167 std::vector<std::string> files;
168 std::string dirname = dirspec.GetPath();
169
170 if (!uuid_str.empty())
171 files.push_back(x: dirname + "/.build-id/" + uuid_str);
172 if (symbol_file_spec.GetFilename()) {
173 files.push_back(x: dirname + "/" +
174 symbol_file_spec.GetFilename().GetCString());
175 files.push_back(x: dirname + "/.debug/" +
176 symbol_file_spec.GetFilename().GetCString());
177
178 // Some debug files may stored in the module directory like this:
179 // /usr/lib/debug/usr/lib/library.so.debug
180 if (!file_dir.IsEmpty())
181 files.push_back(x: dirname + file_dir.AsCString() + "/" +
182 symbol_file_spec.GetFilename().GetCString());
183 }
184
185 const uint32_t num_files = files.size();
186 for (size_t idx_file = 0; idx_file < num_files; ++idx_file) {
187 const std::string &filename = files[idx_file];
188 FileSpec file_spec(filename);
189 FileSystem::Instance().Resolve(file_spec);
190
191 if (llvm::sys::fs::equivalent(A: file_spec.GetPath(),
192 B: module_file_spec.GetPath()))
193 continue;
194
195 if (FileSystem::Instance().Exists(file_spec)) {
196 lldb_private::ModuleSpecList specs;
197 const size_t num_specs =
198 ObjectFile::GetModuleSpecifications(file: file_spec, file_offset: 0, file_size: 0, specs);
199 ModuleSpec mspec;
200 bool valid_mspec = false;
201 if (num_specs == 2) {
202 // Special case to handle both i386 and i686 from ObjectFilePECOFF
203 ModuleSpec mspec2;
204 if (specs.GetModuleSpecAtIndex(i: 0, module_spec&: mspec) &&
205 specs.GetModuleSpecAtIndex(i: 1, module_spec&: mspec2) &&
206 mspec.GetArchitecture().GetTriple().isCompatibleWith(
207 Other: mspec2.GetArchitecture().GetTriple())) {
208 valid_mspec = true;
209 }
210 }
211 if (!valid_mspec) {
212 assert(num_specs <= 1 &&
213 "Symbol Vendor supports only a single architecture");
214 if (num_specs == 1) {
215 if (specs.GetModuleSpecAtIndex(i: 0, module_spec&: mspec)) {
216 valid_mspec = true;
217 }
218 }
219 }
220 if (valid_mspec) {
221 // Skip the uuids check if module_uuid is invalid. For example,
222 // this happens for *.dwp files since at the moment llvm-dwp
223 // doesn't output build ids, nor does binutils dwp.
224 if (!module_uuid.IsValid() || module_uuid == mspec.GetUUID())
225 return file_spec;
226 }
227 }
228 }
229 }
230
231 return {};
232}
233
234bool SymbolLocatorDefault::DownloadObjectAndSymbolFile(ModuleSpec &module_spec,
235 Status &error,
236 bool force_lookup,
237 bool copy_executable) {
238 return false;
239}
240

source code of lldb/source/Plugins/SymbolLocator/Default/SymbolLocatorDefault.cpp