15f757f3fSDimitry Andric //===-- SymbolLocatorDefault.cpp ------------------------------------------===// 25f757f3fSDimitry Andric // 35f757f3fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 45f757f3fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 55f757f3fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 65f757f3fSDimitry Andric // 75f757f3fSDimitry Andric //===----------------------------------------------------------------------===// 85f757f3fSDimitry Andric 95f757f3fSDimitry Andric #include "SymbolLocatorDefault.h" 105f757f3fSDimitry Andric 115f757f3fSDimitry Andric #include <cstring> 125f757f3fSDimitry Andric #include <optional> 135f757f3fSDimitry Andric 145f757f3fSDimitry Andric #include "Plugins/ObjectFile/wasm/ObjectFileWasm.h" 155f757f3fSDimitry Andric #include "lldb/Core/Debugger.h" 165f757f3fSDimitry Andric #include "lldb/Core/Module.h" 175f757f3fSDimitry Andric #include "lldb/Core/ModuleList.h" 185f757f3fSDimitry Andric #include "lldb/Core/ModuleSpec.h" 195f757f3fSDimitry Andric #include "lldb/Core/PluginManager.h" 205f757f3fSDimitry Andric #include "lldb/Core/Progress.h" 215f757f3fSDimitry Andric #include "lldb/Core/Section.h" 225f757f3fSDimitry Andric #include "lldb/Host/FileSystem.h" 235f757f3fSDimitry Andric #include "lldb/Host/Host.h" 245f757f3fSDimitry Andric #include "lldb/Symbol/ObjectFile.h" 255f757f3fSDimitry Andric #include "lldb/Target/Target.h" 265f757f3fSDimitry Andric #include "lldb/Utility/ArchSpec.h" 275f757f3fSDimitry Andric #include "lldb/Utility/DataBuffer.h" 285f757f3fSDimitry Andric #include "lldb/Utility/DataExtractor.h" 295f757f3fSDimitry Andric #include "lldb/Utility/LLDBLog.h" 305f757f3fSDimitry Andric #include "lldb/Utility/Log.h" 315f757f3fSDimitry Andric #include "lldb/Utility/StreamString.h" 325f757f3fSDimitry Andric #include "lldb/Utility/Timer.h" 335f757f3fSDimitry Andric #include "lldb/Utility/UUID.h" 345f757f3fSDimitry Andric 355f757f3fSDimitry Andric #include "llvm/ADT/SmallSet.h" 365f757f3fSDimitry Andric #include "llvm/Support/FileSystem.h" 375f757f3fSDimitry Andric #include "llvm/Support/ThreadPool.h" 385f757f3fSDimitry Andric 39*0fca6ea1SDimitry Andric #if defined(__FreeBSD__) 40*0fca6ea1SDimitry Andric #include <sys/sysctl.h> 41*0fca6ea1SDimitry Andric #endif 42*0fca6ea1SDimitry Andric 435f757f3fSDimitry Andric // From MacOSX system header "mach/machine.h" 445f757f3fSDimitry Andric typedef int cpu_type_t; 455f757f3fSDimitry Andric typedef int cpu_subtype_t; 465f757f3fSDimitry Andric 475f757f3fSDimitry Andric using namespace lldb; 485f757f3fSDimitry Andric using namespace lldb_private; 495f757f3fSDimitry Andric 505f757f3fSDimitry Andric LLDB_PLUGIN_DEFINE(SymbolLocatorDefault) 515f757f3fSDimitry Andric 525f757f3fSDimitry Andric SymbolLocatorDefault::SymbolLocatorDefault() : SymbolLocator() {} 535f757f3fSDimitry Andric 545f757f3fSDimitry Andric void SymbolLocatorDefault::Initialize() { 555f757f3fSDimitry Andric PluginManager::RegisterPlugin( 565f757f3fSDimitry Andric GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance, 575f757f3fSDimitry Andric LocateExecutableObjectFile, LocateExecutableSymbolFile, 585f757f3fSDimitry Andric DownloadObjectAndSymbolFile); 595f757f3fSDimitry Andric } 605f757f3fSDimitry Andric 615f757f3fSDimitry Andric void SymbolLocatorDefault::Terminate() { 625f757f3fSDimitry Andric PluginManager::UnregisterPlugin(CreateInstance); 635f757f3fSDimitry Andric } 645f757f3fSDimitry Andric 655f757f3fSDimitry Andric llvm::StringRef SymbolLocatorDefault::GetPluginDescriptionStatic() { 665f757f3fSDimitry Andric return "Default symbol locator."; 675f757f3fSDimitry Andric } 685f757f3fSDimitry Andric 695f757f3fSDimitry Andric SymbolLocator *SymbolLocatorDefault::CreateInstance() { 705f757f3fSDimitry Andric return new SymbolLocatorDefault(); 715f757f3fSDimitry Andric } 725f757f3fSDimitry Andric 735f757f3fSDimitry Andric std::optional<ModuleSpec> SymbolLocatorDefault::LocateExecutableObjectFile( 745f757f3fSDimitry Andric const ModuleSpec &module_spec) { 755f757f3fSDimitry Andric const FileSpec &exec_fspec = module_spec.GetFileSpec(); 765f757f3fSDimitry Andric const ArchSpec *arch = module_spec.GetArchitecturePtr(); 775f757f3fSDimitry Andric const UUID *uuid = module_spec.GetUUIDPtr(); 785f757f3fSDimitry Andric LLDB_SCOPED_TIMERF( 795f757f3fSDimitry Andric "LocateExecutableObjectFile (file = %s, arch = %s, uuid = %p)", 805f757f3fSDimitry Andric exec_fspec ? exec_fspec.GetFilename().AsCString("<NULL>") : "<NULL>", 815f757f3fSDimitry Andric arch ? arch->GetArchitectureName() : "<NULL>", (const void *)uuid); 825f757f3fSDimitry Andric 835f757f3fSDimitry Andric ModuleSpecList module_specs; 845f757f3fSDimitry Andric ModuleSpec matched_module_spec; 855f757f3fSDimitry Andric if (exec_fspec && 865f757f3fSDimitry Andric ObjectFile::GetModuleSpecifications(exec_fspec, 0, 0, module_specs) && 875f757f3fSDimitry Andric module_specs.FindMatchingModuleSpec(module_spec, matched_module_spec)) { 885f757f3fSDimitry Andric ModuleSpec result; 895f757f3fSDimitry Andric result.GetFileSpec() = exec_fspec; 905f757f3fSDimitry Andric return result; 915f757f3fSDimitry Andric } 925f757f3fSDimitry Andric 935f757f3fSDimitry Andric return {}; 945f757f3fSDimitry Andric } 955f757f3fSDimitry Andric 965f757f3fSDimitry Andric // Keep "symbols.enable-external-lookup" description in sync with this function. 975f757f3fSDimitry Andric std::optional<FileSpec> SymbolLocatorDefault::LocateExecutableSymbolFile( 985f757f3fSDimitry Andric const ModuleSpec &module_spec, const FileSpecList &default_search_paths) { 995f757f3fSDimitry Andric 1005f757f3fSDimitry Andric FileSpec symbol_file_spec = module_spec.GetSymbolFileSpec(); 1015f757f3fSDimitry Andric if (symbol_file_spec.IsAbsolute() && 1025f757f3fSDimitry Andric FileSystem::Instance().Exists(symbol_file_spec)) 1035f757f3fSDimitry Andric return symbol_file_spec; 1045f757f3fSDimitry Andric 1057a6dacacSDimitry Andric Progress progress( 1067a6dacacSDimitry Andric "Locating external symbol file", 1077a6dacacSDimitry Andric module_spec.GetFileSpec().GetFilename().AsCString("<Unknown>")); 1085f757f3fSDimitry Andric 1095f757f3fSDimitry Andric FileSpecList debug_file_search_paths = default_search_paths; 1105f757f3fSDimitry Andric 1115f757f3fSDimitry Andric // Add module directory. 1125f757f3fSDimitry Andric FileSpec module_file_spec = module_spec.GetFileSpec(); 1135f757f3fSDimitry Andric // We keep the unresolved pathname if it fails. 1145f757f3fSDimitry Andric FileSystem::Instance().ResolveSymbolicLink(module_file_spec, 1155f757f3fSDimitry Andric module_file_spec); 1165f757f3fSDimitry Andric 1175f757f3fSDimitry Andric ConstString file_dir = module_file_spec.GetDirectory(); 1185f757f3fSDimitry Andric { 1195f757f3fSDimitry Andric FileSpec file_spec(file_dir.AsCString(".")); 1205f757f3fSDimitry Andric FileSystem::Instance().Resolve(file_spec); 1215f757f3fSDimitry Andric debug_file_search_paths.AppendIfUnique(file_spec); 1225f757f3fSDimitry Andric } 1235f757f3fSDimitry Andric 1245f757f3fSDimitry Andric if (ModuleList::GetGlobalModuleListProperties().GetEnableExternalLookup()) { 1255f757f3fSDimitry Andric 1265f757f3fSDimitry Andric // Add current working directory. 1275f757f3fSDimitry Andric { 1285f757f3fSDimitry Andric FileSpec file_spec("."); 1295f757f3fSDimitry Andric FileSystem::Instance().Resolve(file_spec); 1305f757f3fSDimitry Andric debug_file_search_paths.AppendIfUnique(file_spec); 1315f757f3fSDimitry Andric } 1325f757f3fSDimitry Andric 1335f757f3fSDimitry Andric #ifndef _WIN32 1345f757f3fSDimitry Andric #if defined(__NetBSD__) 1355f757f3fSDimitry Andric // Add /usr/libdata/debug directory. 1365f757f3fSDimitry Andric { 1375f757f3fSDimitry Andric FileSpec file_spec("/usr/libdata/debug"); 1385f757f3fSDimitry Andric FileSystem::Instance().Resolve(file_spec); 1395f757f3fSDimitry Andric debug_file_search_paths.AppendIfUnique(file_spec); 1405f757f3fSDimitry Andric } 1415f757f3fSDimitry Andric #else 1425f757f3fSDimitry Andric // Add /usr/lib/debug directory. 1435f757f3fSDimitry Andric { 1445f757f3fSDimitry Andric FileSpec file_spec("/usr/lib/debug"); 1455f757f3fSDimitry Andric FileSystem::Instance().Resolve(file_spec); 1465f757f3fSDimitry Andric debug_file_search_paths.AppendIfUnique(file_spec); 1475f757f3fSDimitry Andric } 148*0fca6ea1SDimitry Andric #if defined(__FreeBSD__) 149*0fca6ea1SDimitry Andric // Add $LOCALBASE/lib/debug directory, where LOCALBASE is 150*0fca6ea1SDimitry Andric // usually /usr/local, but may be adjusted by the end user. 151*0fca6ea1SDimitry Andric { 152*0fca6ea1SDimitry Andric int mib[2]; 153*0fca6ea1SDimitry Andric char buf[PATH_MAX]; 154*0fca6ea1SDimitry Andric size_t len = PATH_MAX; 155*0fca6ea1SDimitry Andric 156*0fca6ea1SDimitry Andric mib[0] = CTL_USER; 157*0fca6ea1SDimitry Andric mib[1] = USER_LOCALBASE; 158*0fca6ea1SDimitry Andric if (::sysctl(mib, 2, buf, &len, NULL, 0) == 0) { 159*0fca6ea1SDimitry Andric FileSpec file_spec("/lib/debug"); 160*0fca6ea1SDimitry Andric file_spec.PrependPathComponent(llvm::StringRef(buf)); 161*0fca6ea1SDimitry Andric FileSystem::Instance().Resolve(file_spec); 162*0fca6ea1SDimitry Andric debug_file_search_paths.AppendIfUnique(file_spec); 163*0fca6ea1SDimitry Andric } 164*0fca6ea1SDimitry Andric } 165*0fca6ea1SDimitry Andric #endif // __FreeBSD__ 1665f757f3fSDimitry Andric #endif 1675f757f3fSDimitry Andric #endif // _WIN32 1685f757f3fSDimitry Andric } 1695f757f3fSDimitry Andric 1705f757f3fSDimitry Andric std::string uuid_str; 1715f757f3fSDimitry Andric const UUID &module_uuid = module_spec.GetUUID(); 1725f757f3fSDimitry Andric if (module_uuid.IsValid()) { 1735f757f3fSDimitry Andric // Some debug files are stored in the .build-id directory like this: 1745f757f3fSDimitry Andric // /usr/lib/debug/.build-id/ff/e7fe727889ad82bb153de2ad065b2189693315.debug 1755f757f3fSDimitry Andric uuid_str = module_uuid.GetAsString(""); 1765f757f3fSDimitry Andric std::transform(uuid_str.begin(), uuid_str.end(), uuid_str.begin(), 1775f757f3fSDimitry Andric ::tolower); 1785f757f3fSDimitry Andric uuid_str.insert(2, 1, '/'); 1795f757f3fSDimitry Andric uuid_str = uuid_str + ".debug"; 1805f757f3fSDimitry Andric } 1815f757f3fSDimitry Andric 1825f757f3fSDimitry Andric size_t num_directories = debug_file_search_paths.GetSize(); 1835f757f3fSDimitry Andric for (size_t idx = 0; idx < num_directories; ++idx) { 1845f757f3fSDimitry Andric FileSpec dirspec = debug_file_search_paths.GetFileSpecAtIndex(idx); 1855f757f3fSDimitry Andric FileSystem::Instance().Resolve(dirspec); 1865f757f3fSDimitry Andric if (!FileSystem::Instance().IsDirectory(dirspec)) 1875f757f3fSDimitry Andric continue; 1885f757f3fSDimitry Andric 1895f757f3fSDimitry Andric std::vector<std::string> files; 1905f757f3fSDimitry Andric std::string dirname = dirspec.GetPath(); 1915f757f3fSDimitry Andric 1925f757f3fSDimitry Andric if (!uuid_str.empty()) 1935f757f3fSDimitry Andric files.push_back(dirname + "/.build-id/" + uuid_str); 1945f757f3fSDimitry Andric if (symbol_file_spec.GetFilename()) { 1955f757f3fSDimitry Andric files.push_back(dirname + "/" + 1965f757f3fSDimitry Andric symbol_file_spec.GetFilename().GetCString()); 1975f757f3fSDimitry Andric files.push_back(dirname + "/.debug/" + 1985f757f3fSDimitry Andric symbol_file_spec.GetFilename().GetCString()); 1995f757f3fSDimitry Andric 2005f757f3fSDimitry Andric // Some debug files may stored in the module directory like this: 2015f757f3fSDimitry Andric // /usr/lib/debug/usr/lib/library.so.debug 2025f757f3fSDimitry Andric if (!file_dir.IsEmpty()) 2035f757f3fSDimitry Andric files.push_back(dirname + file_dir.AsCString() + "/" + 2045f757f3fSDimitry Andric symbol_file_spec.GetFilename().GetCString()); 2055f757f3fSDimitry Andric } 2065f757f3fSDimitry Andric 2075f757f3fSDimitry Andric const uint32_t num_files = files.size(); 2085f757f3fSDimitry Andric for (size_t idx_file = 0; idx_file < num_files; ++idx_file) { 2095f757f3fSDimitry Andric const std::string &filename = files[idx_file]; 2105f757f3fSDimitry Andric FileSpec file_spec(filename); 2115f757f3fSDimitry Andric FileSystem::Instance().Resolve(file_spec); 2125f757f3fSDimitry Andric 2135f757f3fSDimitry Andric if (llvm::sys::fs::equivalent(file_spec.GetPath(), 2145f757f3fSDimitry Andric module_file_spec.GetPath())) 2155f757f3fSDimitry Andric continue; 2165f757f3fSDimitry Andric 2175f757f3fSDimitry Andric if (FileSystem::Instance().Exists(file_spec)) { 2185f757f3fSDimitry Andric lldb_private::ModuleSpecList specs; 2195f757f3fSDimitry Andric const size_t num_specs = 2205f757f3fSDimitry Andric ObjectFile::GetModuleSpecifications(file_spec, 0, 0, specs); 2215f757f3fSDimitry Andric ModuleSpec mspec; 2225f757f3fSDimitry Andric bool valid_mspec = false; 2235f757f3fSDimitry Andric if (num_specs == 2) { 2245f757f3fSDimitry Andric // Special case to handle both i386 and i686 from ObjectFilePECOFF 2255f757f3fSDimitry Andric ModuleSpec mspec2; 2265f757f3fSDimitry Andric if (specs.GetModuleSpecAtIndex(0, mspec) && 2275f757f3fSDimitry Andric specs.GetModuleSpecAtIndex(1, mspec2) && 2285f757f3fSDimitry Andric mspec.GetArchitecture().GetTriple().isCompatibleWith( 2295f757f3fSDimitry Andric mspec2.GetArchitecture().GetTriple())) { 2305f757f3fSDimitry Andric valid_mspec = true; 2315f757f3fSDimitry Andric } 2325f757f3fSDimitry Andric } 2335f757f3fSDimitry Andric if (!valid_mspec) { 2345f757f3fSDimitry Andric assert(num_specs <= 1 && 2355f757f3fSDimitry Andric "Symbol Vendor supports only a single architecture"); 2365f757f3fSDimitry Andric if (num_specs == 1) { 2375f757f3fSDimitry Andric if (specs.GetModuleSpecAtIndex(0, mspec)) { 2385f757f3fSDimitry Andric valid_mspec = true; 2395f757f3fSDimitry Andric } 2405f757f3fSDimitry Andric } 2415f757f3fSDimitry Andric } 2425f757f3fSDimitry Andric if (valid_mspec) { 2435f757f3fSDimitry Andric // Skip the uuids check if module_uuid is invalid. For example, 2445f757f3fSDimitry Andric // this happens for *.dwp files since at the moment llvm-dwp 2455f757f3fSDimitry Andric // doesn't output build ids, nor does binutils dwp. 2465f757f3fSDimitry Andric if (!module_uuid.IsValid() || module_uuid == mspec.GetUUID()) 2475f757f3fSDimitry Andric return file_spec; 2485f757f3fSDimitry Andric } 2495f757f3fSDimitry Andric } 2505f757f3fSDimitry Andric } 2515f757f3fSDimitry Andric } 2525f757f3fSDimitry Andric 2535f757f3fSDimitry Andric return {}; 2545f757f3fSDimitry Andric } 2555f757f3fSDimitry Andric 2565f757f3fSDimitry Andric bool SymbolLocatorDefault::DownloadObjectAndSymbolFile(ModuleSpec &module_spec, 2575f757f3fSDimitry Andric Status &error, 2585f757f3fSDimitry Andric bool force_lookup, 2595f757f3fSDimitry Andric bool copy_executable) { 2605f757f3fSDimitry Andric return false; 2615f757f3fSDimitry Andric } 262