xref: /freebsd-src/contrib/llvm-project/lldb/source/Plugins/SymbolLocator/Default/SymbolLocatorDefault.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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