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 50 LLDB_PLUGIN_DEFINE(SymbolLocatorDefault) 51 52 SymbolLocatorDefault::SymbolLocatorDefault() : SymbolLocator() {} 53 54 void SymbolLocatorDefault::Initialize() { 55 PluginManager::RegisterPlugin( 56 GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance, 57 LocateExecutableObjectFile, LocateExecutableSymbolFile, 58 DownloadObjectAndSymbolFile); 59 } 60 61 void SymbolLocatorDefault::Terminate() { 62 PluginManager::UnregisterPlugin(CreateInstance); 63 } 64 65 llvm::StringRef SymbolLocatorDefault::GetPluginDescriptionStatic() { 66 return "Default symbol locator."; 67 } 68 69 SymbolLocator *SymbolLocatorDefault::CreateInstance() { 70 return new SymbolLocatorDefault(); 71 } 72 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. 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 256 bool SymbolLocatorDefault::DownloadObjectAndSymbolFile(ModuleSpec &module_spec, 257 Status &error, 258 bool force_lookup, 259 bool copy_executable) { 260 return false; 261 } 262