262 lines · cpp
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-exception6//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#endif42 43// From MacOSX system header "mach/machine.h"44typedef int cpu_type_t;45typedef int cpu_subtype_t;46 47using namespace lldb;48using namespace lldb_private;49 50LLDB_PLUGIN_DEFINE(SymbolLocatorDefault)51 52SymbolLocatorDefault::SymbolLocatorDefault() : SymbolLocator() {}53 54void SymbolLocatorDefault::Initialize() {55 PluginManager::RegisterPlugin(56 GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance,57 LocateExecutableObjectFile, LocateExecutableSymbolFile,58 DownloadObjectAndSymbolFile);59}60 61void SymbolLocatorDefault::Terminate() {62 PluginManager::UnregisterPlugin(CreateInstance);63}64 65llvm::StringRef SymbolLocatorDefault::GetPluginDescriptionStatic() {66 return "Default symbol locator.";67}68 69SymbolLocator *SymbolLocatorDefault::CreateInstance() {70 return new SymbolLocatorDefault();71}72 73std::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.97std::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 _WIN32134#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#else142 // 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 is150 // 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#endif167#endif // _WIN32168 }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.debug175 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.debug202 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 ObjectFilePECOFF225 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-dwp245 // 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 256bool SymbolLocatorDefault::DownloadObjectAndSymbolFile(ModuleSpec &module_spec,257 Status &error,258 bool force_lookup,259 bool copy_executable) {260 return false;261}262