| // 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 "src/developer/debug/zxdb/expr/symbol_eval_context.h" |
| |
| #include "src/developer/debug/zxdb/common/err.h" |
| #include "src/developer/debug/zxdb/expr/builtin_types.h" |
| #include "src/developer/debug/zxdb/expr/expr_value.h" |
| #include "src/developer/debug/zxdb/expr/find_name.h" |
| #include "src/developer/debug/zxdb/expr/resolve_collection.h" |
| #include "src/developer/debug/zxdb/expr/resolve_ptr_ref.h" |
| #include "src/developer/debug/zxdb/symbols/code_block.h" |
| #include "src/developer/debug/zxdb/symbols/data_member.h" |
| #include "src/developer/debug/zxdb/symbols/function.h" |
| #include "src/developer/debug/zxdb/symbols/identifier.h" |
| #include "src/developer/debug/zxdb/symbols/input_location.h" |
| #include "src/developer/debug/zxdb/symbols/location.h" |
| #include "src/developer/debug/zxdb/symbols/modified_type.h" |
| #include "src/developer/debug/zxdb/symbols/process_symbols.h" |
| #include "src/developer/debug/zxdb/symbols/symbol_data_provider.h" |
| #include "src/developer/debug/zxdb/symbols/variable.h" |
| #include "src/lib/fxl/logging.h" |
| #include "src/lib/fxl/strings/string_printf.h" |
| |
| namespace zxdb { |
| namespace { |
| |
| debug_ipc::RegisterID GetRegister(const Identifier& ident) { |
| auto str = GetSingleComponentIdentifierName(ident); |
| if (!str) |
| return debug_ipc::RegisterID::kUnknown; |
| return debug_ipc::StringToRegisterID(*str); |
| } |
| |
| } // namespace |
| |
| 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 (FoundName found = FindName(FindNameContext(process_symbols_.get(), |
| symbol_context_, block_.get()), |
| identifier)) { |
| switch (found.kind()) { |
| case FoundName::kVariable: |
| case FoundName::kMemberVariable: |
| DoResolve(std::move(found), std::move(cb)); |
| return; |
| case FoundName::kNamespace: |
| cb(Err("Can not evaluate a namespace."), nullptr, ExprValue()); |
| return; |
| case FoundName::kTemplate: |
| cb(Err("Can not evaluate a template with no parameters."), nullptr, |
| ExprValue()); |
| return; |
| case FoundName::kType: |
| cb(Err("Can not evaluate a type."), nullptr, ExprValue()); |
| return; |
| case FoundName::kFunction: |
| break; // Function pointers not supported yet. |
| case FoundName::kNone: |
| break; // Fall through to checking other stuff. |
| } |
| } |
| |
| auto reg = GetRegister(identifier); |
| |
| if (reg == debug_ipc::RegisterID::kUnknown || |
| GetArchForRegisterID(reg) != data_provider_->GetArch()) { |
| cb(Err("No variable '%s' found.", identifier.GetFullName().c_str()), |
| nullptr, ExprValue()); |
| return; |
| } |
| |
| // Fall back to matching registers when no symbol is found. |
| data_provider_->GetRegisterAsync( |
| reg, [cb = std::move(cb)](const Err& err, uint64_t value) { |
| cb(err, fxl::RefPtr<zxdb::Symbol>(), ExprValue(value)); |
| }); |
| } |
| |
| SymbolVariableResolver& SymbolEvalContext::GetVariableResolver() { |
| return resolver_; |
| } |
| |
| fxl::RefPtr<SymbolDataProvider> SymbolEvalContext::GetDataProvider() { |
| return data_provider_; |
| } |
| |
| NameLookupCallback SymbolEvalContext::GetSymbolNameLookupCallback() { |
| // The contract for this function is that the callback must not be stored |
| // so the callback can reference |this|. |
| return [this](const Identifier& ident) -> FoundName { |
| // Look up the symbols in the symbol table if possible. |
| FoundName result = DoTargetSymbolsNameLookup(ident); |
| |
| // Fall back on builtin types. |
| if (result.kind() == FoundName::kNone) { |
| if (auto type = GetBuiltinType(ident.GetFullName())) |
| return FoundName(std::move(type)); |
| } |
| return result; |
| }; |
| } |
| |
| void SymbolEvalContext::DoResolve(FoundName found, ValueCallback cb) const { |
| if (found.kind() == FoundName::kVariable) { |
| // 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)); |
| } |
| }); |
| }); |
| } |
| |
| FoundName SymbolEvalContext::DoTargetSymbolsNameLookup( |
| const Identifier& ident) { |
| return FindName( |
| FindNameContext(process_symbols_.get(), symbol_context_, block_.get()), |
| ident); |
| } |
| |
| } // namespace zxdb |