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" 40 typedef int cpu_type_t; 41 typedef int cpu_subtype_t; 42 43 using namespace lldb; 44 using namespace lldb_private; 45 46 LLDB_PLUGIN_DEFINE(SymbolLocatorDefault) 47 48 SymbolLocatorDefault::SymbolLocatorDefault() : SymbolLocator() {} 49 50 void SymbolLocatorDefault::Initialize() { 51 PluginManager::RegisterPlugin( 52 GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance, 53 LocateExecutableObjectFile, LocateExecutableSymbolFile, 54 DownloadObjectAndSymbolFile); 55 } 56 57 void SymbolLocatorDefault::Terminate() { 58 PluginManager::UnregisterPlugin(CreateInstance); 59 } 60 61 llvm::StringRef SymbolLocatorDefault::GetPluginDescriptionStatic() { 62 return "Default symbol locator."; 63 } 64 65 SymbolLocator *SymbolLocatorDefault::CreateInstance() { 66 return new SymbolLocatorDefault(); 67 } 68 69 std::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(exec_fspec, 0, 0, module_specs) && 83 module_specs.FindMatchingModuleSpec(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. 93 std::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(symbol_file_spec)) 99 return symbol_file_spec; 100 101 Progress progress(llvm::formatv( 102 "Locating external symbol file for {0}", 103 module_spec.GetFileSpec().GetFilename().AsCString("<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(module_file_spec, 111 module_file_spec); 112 113 ConstString file_dir = module_file_spec.GetDirectory(); 114 { 115 FileSpec file_spec(file_dir.AsCString(".")); 116 FileSystem::Instance().Resolve(file_spec); 117 debug_file_search_paths.AppendIfUnique(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_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_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(""); 154 std::transform(uuid_str.begin(), uuid_str.end(), uuid_str.begin(), 155 ::tolower); 156 uuid_str.insert(2, 1, '/'); 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(dirspec); 164 if (!FileSystem::Instance().IsDirectory(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(dirname + "/.build-id/" + uuid_str); 172 if (symbol_file_spec.GetFilename()) { 173 files.push_back(dirname + "/" + 174 symbol_file_spec.GetFilename().GetCString()); 175 files.push_back(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(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(file_spec.GetPath(), 192 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_spec, 0, 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(0, mspec) && 205 specs.GetModuleSpecAtIndex(1, mspec2) && 206 mspec.GetArchitecture().GetTriple().isCompatibleWith( 207 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(0, 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 234 bool SymbolLocatorDefault::DownloadObjectAndSymbolFile(ModuleSpec &module_spec, 235 Status &error, 236 bool force_lookup, 237 bool copy_executable) { 238 return false; 239 } 240