blob: b149b511bfde2f70e6c4fdeae0d3e6eef968aabc [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "garnet/bin/zxdb/symbols/system_symbols.h"
#include "garnet/bin/zxdb/common/file_util.h"
#include "garnet/bin/zxdb/common/host_util.h"
#include "garnet/bin/zxdb/symbols/module_symbols_impl.h"
#include "garnet/public/lib/fxl/strings/string_printf.h"
namespace zxdb {
namespace {
// TODO(brettw) this is hardcoded and will only work in a full local build.
// We will need a more flexible way to do handle this, and also a way to
// explicitly specify a location for the mapping file.
std::string GetBuildDir() {
// Expect the debugger to be in "<build>/host_x64/zxdb" and the build dir
// to be one directory up.
std::string path = GetSelfPath();
if (path.empty())
return path;
// Trim off the last two slash-separated components ("host_x64/zxdb").
size_t last_slash = path.rfind('/');
if (last_slash != std::string::npos) {
path.resize(last_slash);
last_slash = path.rfind('/');
if (last_slash != std::string::npos)
path.resize(last_slash + 1); // + 1 means keep the last slash.
}
return path;
}
} // namespace
// SystemSymbols::ModuleRef ----------------------------------------------------
SystemSymbols::ModuleRef::ModuleRef(
SystemSymbols* system_symbols,
std::unique_ptr<ModuleSymbols> module_symbols)
: system_symbols_(system_symbols),
module_symbols_(std::move(module_symbols)) {}
SystemSymbols::ModuleRef::~ModuleRef() {
if (system_symbols_)
system_symbols_->WillDeleteModule(this);
}
void SystemSymbols::ModuleRef::SystemSymbolsDeleting() {
system_symbols_ = nullptr;
}
// SystemSymbols ---------------------------------------------------------------
SystemSymbols::SystemSymbols() : build_dir_(GetBuildDir()) {
// Add the system build ID file to the index. This will only exist in this
// location when running in-tree.
build_id_index_.AddBuildIDMappingFile(
CatPathComponents(build_dir_, "ids.txt"));
}
SystemSymbols::~SystemSymbols() {
// Disown any remaining ModuleRefs so they don't call us back.
for (auto& pair : modules_)
pair.second->SystemSymbolsDeleting();
modules_.clear();
}
fxl::RefPtr<SystemSymbols::ModuleRef> SystemSymbols::InjectModuleForTesting(
const std::string& build_id, std::unique_ptr<ModuleSymbols> module) {
// Can't inject a module that already exists.
FXL_DCHECK(modules_.find(build_id) == modules_.end());
fxl::RefPtr<ModuleRef> result =
fxl::MakeRefCounted<ModuleRef>(this, std::move(module));
modules_[build_id] = result.get();
return result;
}
Err SystemSymbols::GetModule(const std::string& name_for_msg,
const std::string& build_id,
fxl::RefPtr<ModuleRef>* module) {
auto found_existing = modules_.find(build_id);
if (found_existing != modules_.end()) {
*module = fxl::RefPtr<ModuleRef>(found_existing->second);
return Err();
}
std::string file_name = build_id_index_.FileForBuildID(build_id);
if (file_name.empty()) {
return Err(fxl::StringPrintf(
"Could not load symbols for \"%s\" because there was no mapping for "
"build ID \"%s\".",
name_for_msg.c_str(), build_id.c_str()));
}
auto module_symbols =
std::make_unique<ModuleSymbolsImpl>(file_name, build_id);
Err err = module_symbols->Load();
if (err.has_error())
return err;
*module = fxl::MakeRefCounted<ModuleRef>(this, std::move(module_symbols));
modules_[build_id] = module->get();
return Err();
}
void SystemSymbols::WillDeleteModule(ModuleRef* module) {
// We expect relatively few total modules and removing them is also uncommon,
// so this is a brute-force search.
for (auto iter = modules_.begin(); iter != modules_.end(); ++iter) {
if (iter->second == module) {
modules_.erase(iter);
return;
}
}
FXL_NOTREACHED(); // Notified for unknown ModuleRef.
}
} // namespace zxdb