This completes the conversion of LocateSymbolFile into a SymbolLocator plugin. The only remaining function is DownloadSymbolFileAsync which doesn't really fit into the plugin model, and therefore moves into the SymbolLocator class, while still relying on the plugins to do the underlying work.
240 lines
8.2 KiB
C++
240 lines
8.2 KiB
C++
//===-- SymbolLocatorDefault.cpp ------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "SymbolLocatorDefault.h"
|
|
|
|
#include <cstring>
|
|
#include <optional>
|
|
|
|
#include "Plugins/ObjectFile/wasm/ObjectFileWasm.h"
|
|
#include "lldb/Core/Debugger.h"
|
|
#include "lldb/Core/Module.h"
|
|
#include "lldb/Core/ModuleList.h"
|
|
#include "lldb/Core/ModuleSpec.h"
|
|
#include "lldb/Core/PluginManager.h"
|
|
#include "lldb/Core/Progress.h"
|
|
#include "lldb/Core/Section.h"
|
|
#include "lldb/Host/FileSystem.h"
|
|
#include "lldb/Host/Host.h"
|
|
#include "lldb/Symbol/ObjectFile.h"
|
|
#include "lldb/Target/Target.h"
|
|
#include "lldb/Utility/ArchSpec.h"
|
|
#include "lldb/Utility/DataBuffer.h"
|
|
#include "lldb/Utility/DataExtractor.h"
|
|
#include "lldb/Utility/LLDBLog.h"
|
|
#include "lldb/Utility/Log.h"
|
|
#include "lldb/Utility/StreamString.h"
|
|
#include "lldb/Utility/Timer.h"
|
|
#include "lldb/Utility/UUID.h"
|
|
|
|
#include "llvm/ADT/SmallSet.h"
|
|
#include "llvm/Support/FileSystem.h"
|
|
#include "llvm/Support/ThreadPool.h"
|
|
|
|
// From MacOSX system header "mach/machine.h"
|
|
typedef int cpu_type_t;
|
|
typedef int cpu_subtype_t;
|
|
|
|
using namespace lldb;
|
|
using namespace lldb_private;
|
|
|
|
LLDB_PLUGIN_DEFINE(SymbolLocatorDefault)
|
|
|
|
SymbolLocatorDefault::SymbolLocatorDefault() : SymbolLocator() {}
|
|
|
|
void SymbolLocatorDefault::Initialize() {
|
|
PluginManager::RegisterPlugin(
|
|
GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance,
|
|
LocateExecutableObjectFile, LocateExecutableSymbolFile,
|
|
DownloadObjectAndSymbolFile);
|
|
}
|
|
|
|
void SymbolLocatorDefault::Terminate() {
|
|
PluginManager::UnregisterPlugin(CreateInstance);
|
|
}
|
|
|
|
llvm::StringRef SymbolLocatorDefault::GetPluginDescriptionStatic() {
|
|
return "Default symbol locator.";
|
|
}
|
|
|
|
SymbolLocator *SymbolLocatorDefault::CreateInstance() {
|
|
return new SymbolLocatorDefault();
|
|
}
|
|
|
|
std::optional<ModuleSpec> SymbolLocatorDefault::LocateExecutableObjectFile(
|
|
const ModuleSpec &module_spec) {
|
|
const FileSpec &exec_fspec = module_spec.GetFileSpec();
|
|
const ArchSpec *arch = module_spec.GetArchitecturePtr();
|
|
const UUID *uuid = module_spec.GetUUIDPtr();
|
|
LLDB_SCOPED_TIMERF(
|
|
"LocateExecutableObjectFile (file = %s, arch = %s, uuid = %p)",
|
|
exec_fspec ? exec_fspec.GetFilename().AsCString("<NULL>") : "<NULL>",
|
|
arch ? arch->GetArchitectureName() : "<NULL>", (const void *)uuid);
|
|
|
|
ModuleSpecList module_specs;
|
|
ModuleSpec matched_module_spec;
|
|
if (exec_fspec &&
|
|
ObjectFile::GetModuleSpecifications(exec_fspec, 0, 0, module_specs) &&
|
|
module_specs.FindMatchingModuleSpec(module_spec, matched_module_spec)) {
|
|
ModuleSpec result;
|
|
result.GetFileSpec() = exec_fspec;
|
|
return result;
|
|
}
|
|
|
|
return {};
|
|
}
|
|
|
|
// Keep "symbols.enable-external-lookup" description in sync with this function.
|
|
std::optional<FileSpec> SymbolLocatorDefault::LocateExecutableSymbolFile(
|
|
const ModuleSpec &module_spec, const FileSpecList &default_search_paths) {
|
|
|
|
FileSpec symbol_file_spec = module_spec.GetSymbolFileSpec();
|
|
if (symbol_file_spec.IsAbsolute() &&
|
|
FileSystem::Instance().Exists(symbol_file_spec))
|
|
return symbol_file_spec;
|
|
|
|
Progress progress(llvm::formatv(
|
|
"Locating external symbol file for {0}",
|
|
module_spec.GetFileSpec().GetFilename().AsCString("<Unknown>")));
|
|
|
|
FileSpecList debug_file_search_paths = default_search_paths;
|
|
|
|
// Add module directory.
|
|
FileSpec module_file_spec = module_spec.GetFileSpec();
|
|
// We keep the unresolved pathname if it fails.
|
|
FileSystem::Instance().ResolveSymbolicLink(module_file_spec,
|
|
module_file_spec);
|
|
|
|
ConstString file_dir = module_file_spec.GetDirectory();
|
|
{
|
|
FileSpec file_spec(file_dir.AsCString("."));
|
|
FileSystem::Instance().Resolve(file_spec);
|
|
debug_file_search_paths.AppendIfUnique(file_spec);
|
|
}
|
|
|
|
if (ModuleList::GetGlobalModuleListProperties().GetEnableExternalLookup()) {
|
|
|
|
// Add current working directory.
|
|
{
|
|
FileSpec file_spec(".");
|
|
FileSystem::Instance().Resolve(file_spec);
|
|
debug_file_search_paths.AppendIfUnique(file_spec);
|
|
}
|
|
|
|
#ifndef _WIN32
|
|
#if defined(__NetBSD__)
|
|
// Add /usr/libdata/debug directory.
|
|
{
|
|
FileSpec file_spec("/usr/libdata/debug");
|
|
FileSystem::Instance().Resolve(file_spec);
|
|
debug_file_search_paths.AppendIfUnique(file_spec);
|
|
}
|
|
#else
|
|
// Add /usr/lib/debug directory.
|
|
{
|
|
FileSpec file_spec("/usr/lib/debug");
|
|
FileSystem::Instance().Resolve(file_spec);
|
|
debug_file_search_paths.AppendIfUnique(file_spec);
|
|
}
|
|
#endif
|
|
#endif // _WIN32
|
|
}
|
|
|
|
std::string uuid_str;
|
|
const UUID &module_uuid = module_spec.GetUUID();
|
|
if (module_uuid.IsValid()) {
|
|
// Some debug files are stored in the .build-id directory like this:
|
|
// /usr/lib/debug/.build-id/ff/e7fe727889ad82bb153de2ad065b2189693315.debug
|
|
uuid_str = module_uuid.GetAsString("");
|
|
std::transform(uuid_str.begin(), uuid_str.end(), uuid_str.begin(),
|
|
::tolower);
|
|
uuid_str.insert(2, 1, '/');
|
|
uuid_str = uuid_str + ".debug";
|
|
}
|
|
|
|
size_t num_directories = debug_file_search_paths.GetSize();
|
|
for (size_t idx = 0; idx < num_directories; ++idx) {
|
|
FileSpec dirspec = debug_file_search_paths.GetFileSpecAtIndex(idx);
|
|
FileSystem::Instance().Resolve(dirspec);
|
|
if (!FileSystem::Instance().IsDirectory(dirspec))
|
|
continue;
|
|
|
|
std::vector<std::string> files;
|
|
std::string dirname = dirspec.GetPath();
|
|
|
|
if (!uuid_str.empty())
|
|
files.push_back(dirname + "/.build-id/" + uuid_str);
|
|
if (symbol_file_spec.GetFilename()) {
|
|
files.push_back(dirname + "/" +
|
|
symbol_file_spec.GetFilename().GetCString());
|
|
files.push_back(dirname + "/.debug/" +
|
|
symbol_file_spec.GetFilename().GetCString());
|
|
|
|
// Some debug files may stored in the module directory like this:
|
|
// /usr/lib/debug/usr/lib/library.so.debug
|
|
if (!file_dir.IsEmpty())
|
|
files.push_back(dirname + file_dir.AsCString() + "/" +
|
|
symbol_file_spec.GetFilename().GetCString());
|
|
}
|
|
|
|
const uint32_t num_files = files.size();
|
|
for (size_t idx_file = 0; idx_file < num_files; ++idx_file) {
|
|
const std::string &filename = files[idx_file];
|
|
FileSpec file_spec(filename);
|
|
FileSystem::Instance().Resolve(file_spec);
|
|
|
|
if (llvm::sys::fs::equivalent(file_spec.GetPath(),
|
|
module_file_spec.GetPath()))
|
|
continue;
|
|
|
|
if (FileSystem::Instance().Exists(file_spec)) {
|
|
lldb_private::ModuleSpecList specs;
|
|
const size_t num_specs =
|
|
ObjectFile::GetModuleSpecifications(file_spec, 0, 0, specs);
|
|
ModuleSpec mspec;
|
|
bool valid_mspec = false;
|
|
if (num_specs == 2) {
|
|
// Special case to handle both i386 and i686 from ObjectFilePECOFF
|
|
ModuleSpec mspec2;
|
|
if (specs.GetModuleSpecAtIndex(0, mspec) &&
|
|
specs.GetModuleSpecAtIndex(1, mspec2) &&
|
|
mspec.GetArchitecture().GetTriple().isCompatibleWith(
|
|
mspec2.GetArchitecture().GetTriple())) {
|
|
valid_mspec = true;
|
|
}
|
|
}
|
|
if (!valid_mspec) {
|
|
assert(num_specs <= 1 &&
|
|
"Symbol Vendor supports only a single architecture");
|
|
if (num_specs == 1) {
|
|
if (specs.GetModuleSpecAtIndex(0, mspec)) {
|
|
valid_mspec = true;
|
|
}
|
|
}
|
|
}
|
|
if (valid_mspec) {
|
|
// Skip the uuids check if module_uuid is invalid. For example,
|
|
// this happens for *.dwp files since at the moment llvm-dwp
|
|
// doesn't output build ids, nor does binutils dwp.
|
|
if (!module_uuid.IsValid() || module_uuid == mspec.GetUUID())
|
|
return file_spec;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return {};
|
|
}
|
|
|
|
bool SymbolLocatorDefault::DownloadObjectAndSymbolFile(ModuleSpec &module_spec,
|
|
Status &error,
|
|
bool force_lookup,
|
|
bool copy_executable) {
|
|
return false;
|
|
}
|