blob: 690d26d0c13bfd80029382a655a9094ec0d0c1b6 [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/expr/symbol_eval_context.h"
#include "garnet/bin/zxdb/common/err.h"
#include "garnet/bin/zxdb/expr/expr_value.h"
#include "garnet/bin/zxdb/expr/find_variable.h"
#include "garnet/bin/zxdb/expr/identifier.h"
#include "garnet/bin/zxdb/expr/resolve_collection.h"
#include "garnet/bin/zxdb/expr/resolve_ptr_ref.h"
#include "garnet/bin/zxdb/symbols/code_block.h"
#include "garnet/bin/zxdb/symbols/data_member.h"
#include "garnet/bin/zxdb/symbols/function.h"
#include "garnet/bin/zxdb/symbols/input_location.h"
#include "garnet/bin/zxdb/symbols/location.h"
#include "garnet/bin/zxdb/symbols/modified_type.h"
#include "garnet/bin/zxdb/symbols/process_symbols.h"
#include "garnet/bin/zxdb/symbols/symbol_data_provider.h"
#include "garnet/bin/zxdb/symbols/variable.h"
#include "lib/fxl/logging.h"
#include "lib/fxl/strings/string_printf.h"
namespace zxdb {
SymbolEvalContext::SymbolEvalContext(
fxl::WeakPtr<const ProcessSymbols> process_symbols,
const SymbolContext& symbol_context,
fxl::RefPtr<SymbolDataProvider> data_provider,
fxl::RefPtr<CodeBlock> code_block)
: process_symbols_(std::move(process_symbols)),
symbol_context_(symbol_context),
data_provider_(data_provider),
resolver_(std::move(data_provider)),
block_(std::move(code_block)),
weak_factory_(this) {}
SymbolEvalContext::SymbolEvalContext(
fxl::WeakPtr<const ProcessSymbols> process_symbols,
fxl::RefPtr<SymbolDataProvider> data_provider, const Location& location)
: process_symbols_(std::move(process_symbols)),
symbol_context_(location.symbol_context()),
data_provider_(data_provider),
resolver_(std::move(data_provider)),
weak_factory_(this) {
if (!location.symbol())
return;
const CodeBlock* function = location.symbol().Get()->AsCodeBlock();
if (!function)
return;
// Const cast unfortunately required for RefPtr constructor.
block_ = fxl::RefPtr<const CodeBlock>(
const_cast<CodeBlock*>(function->GetMostSpecificChild(
location.symbol_context(), location.address())));
}
SymbolEvalContext::~SymbolEvalContext() = default;
void SymbolEvalContext::GetNamedValue(const Identifier& identifier,
ValueCallback cb) {
if (auto found = FindVariable(process_symbols_.get(), block_.get(),
&symbol_context_, identifier)) {
DoResolve(std::move(*found), std::move(cb));
} else {
cb(Err("No variable '%s' found.", identifier.GetFullName().c_str()),
nullptr, ExprValue());
}
}
SymbolVariableResolver& SymbolEvalContext::GetVariableResolver() {
return resolver_;
}
fxl::RefPtr<SymbolDataProvider> SymbolEvalContext::GetDataProvider() {
return data_provider_;
}
void SymbolEvalContext::DoResolve(FoundVariable found, ValueCallback cb) const {
if (!found.is_object_member()) {
// Simple variable resolution.
resolver_.ResolveVariable(symbol_context_, found.variable(), [
var = found.variable_ref(), cb = std::move(cb)
](const Err& err, ExprValue value) {
cb(err, std::move(var), std::move(value));
});
return;
}
// Object variable resolution: Get the value of of the |this| variable.
// Callback needs to capture a ref to ourselves since it's needed to resolve
// the member later.
fxl::RefPtr<SymbolEvalContext> eval_context(
const_cast<SymbolEvalContext*>(this));
resolver_.ResolveVariable(symbol_context_, found.object_ptr(), [
found, cb = std::move(cb), eval_context = std::move(eval_context)
](const Err& err, ExprValue value) {
if (err.has_error()) {
// |this| not available, probably optimized out.
cb(err, fxl::RefPtr<zxdb::Symbol>(), ExprValue());
return;
}
// Got |this|, resolve |this-><DataMember>|.
ResolveMemberByPointer(std::move(eval_context), value, found.member(), [
found = std::move(found), cb = std::move(cb)
](const Err& err, ExprValue value) {
if (err.has_error()) {
cb(err, fxl::RefPtr<zxdb::Symbol>(), ExprValue());
} else {
// Found |this->name|.
cb(Err(), found.member().data_member_ref(), std::move(value));
}
});
});
}
} // namespace zxdb