1 //===-- SymbolLocatorDefault.cpp ------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "SymbolLocatorDefault.h"
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"
35 #include "llvm/ADT/SmallSet.h"
36 #include "llvm/Support/FileSystem.h"
37 #include "llvm/Support/ThreadPool.h"
39 #if defined(__FreeBSD__)
40 #include <sys/sysctl.h>
43 // From MacOSX system header "mach/machine.h"
44 typedef int cpu_type_t
;
45 typedef int cpu_subtype_t
;
48 using namespace lldb_private
;
50 LLDB_PLUGIN_DEFINE(SymbolLocatorDefault
)
52 SymbolLocatorDefault::SymbolLocatorDefault() : SymbolLocator() {}
54 void SymbolLocatorDefault::Initialize() {
55 PluginManager::RegisterPlugin(
56 GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance
,
57 LocateExecutableObjectFile
, LocateExecutableSymbolFile
,
58 DownloadObjectAndSymbolFile
);
61 void SymbolLocatorDefault::Terminate() {
62 PluginManager::UnregisterPlugin(CreateInstance
);
65 llvm::StringRef
SymbolLocatorDefault::GetPluginDescriptionStatic() {
66 return "Default symbol locator.";
69 SymbolLocator
*SymbolLocatorDefault::CreateInstance() {
70 return new SymbolLocatorDefault();
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();
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
);
83 ModuleSpecList module_specs
;
84 ModuleSpec matched_module_spec
;
86 ObjectFile::GetModuleSpecifications(exec_fspec
, 0, 0, module_specs
) &&
87 module_specs
.FindMatchingModuleSpec(module_spec
, matched_module_spec
)) {
89 result
.GetFileSpec() = exec_fspec
;
96 // Keep "symbols.enable-external-lookup" description in sync with this function.
97 std::optional
<FileSpec
> SymbolLocatorDefault::LocateExecutableSymbolFile(
98 const ModuleSpec
&module_spec
, const FileSpecList
&default_search_paths
) {
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
;
106 "Locating external symbol file",
107 module_spec
.GetFileSpec().GetFilename().AsCString("<Unknown>"));
109 FileSpecList debug_file_search_paths
= default_search_paths
;
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
,
117 ConstString file_dir
= module_file_spec
.GetDirectory();
119 FileSpec
file_spec(file_dir
.AsCString("."));
120 FileSystem::Instance().Resolve(file_spec
);
121 debug_file_search_paths
.AppendIfUnique(file_spec
);
124 if (ModuleList::GetGlobalModuleListProperties().GetEnableExternalLookup()) {
126 // Add current working directory.
128 FileSpec
file_spec(".");
129 FileSystem::Instance().Resolve(file_spec
);
130 debug_file_search_paths
.AppendIfUnique(file_spec
);
134 #if defined(__NetBSD__)
135 // Add /usr/libdata/debug directory.
137 FileSpec
file_spec("/usr/libdata/debug");
138 FileSystem::Instance().Resolve(file_spec
);
139 debug_file_search_paths
.AppendIfUnique(file_spec
);
142 // Add /usr/lib/debug directory.
144 FileSpec
file_spec("/usr/lib/debug");
145 FileSystem::Instance().Resolve(file_spec
);
146 debug_file_search_paths
.AppendIfUnique(file_spec
);
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.
154 size_t len
= PATH_MAX
;
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
);
165 #endif // __FreeBSD__
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(),
178 uuid_str
.insert(2, 1, '/');
179 uuid_str
= uuid_str
+ ".debug";
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
))
189 std::vector
<std::string
> files
;
190 std::string dirname
= dirspec
.GetPath();
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());
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());
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
);
213 if (llvm::sys::fs::equivalent(file_spec
.GetPath(),
214 module_file_spec
.GetPath()))
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
);
222 bool valid_mspec
= false;
223 if (num_specs
== 2) {
224 // Special case to handle both i386 and i686 from ObjectFilePECOFF
226 if (specs
.GetModuleSpecAtIndex(0, mspec
) &&
227 specs
.GetModuleSpecAtIndex(1, mspec2
) &&
228 mspec
.GetArchitecture().GetTriple().isCompatibleWith(
229 mspec2
.GetArchitecture().GetTriple())) {
234 assert(num_specs
<= 1 &&
235 "Symbol Vendor supports only a single architecture");
236 if (num_specs
== 1) {
237 if (specs
.GetModuleSpecAtIndex(0, 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())
256 bool SymbolLocatorDefault::DownloadObjectAndSymbolFile(ModuleSpec
&module_spec
,
259 bool copy_executable
) {