| // Copyright 2019 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/async_dwarf_expr_eval.h" |
| |
| #include "src/developer/debug/shared/message_loop.h" |
| #include "src/developer/debug/zxdb/expr/eval_context.h" |
| #include "src/developer/debug/zxdb/expr/resolve_ptr_ref.h" |
| #include "src/lib/fxl/strings/string_printf.h" |
| |
| namespace zxdb { |
| |
| void AsyncDwarfExprEval::Eval(const fxl::RefPtr<EvalContext>& context, |
| const SymbolContext& expr_symbol_context, |
| const std::vector<uint8_t>& expr) { |
| dwarf_eval_.Eval(context->GetDataProvider(), expr_symbol_context, expr, |
| [this_ref = RefPtrTo(this), context](DwarfExprEval*, const Err& err) { |
| this_ref->OnEvalComplete(err, context); |
| |
| // Prevent the DwarfExprEval from getting reentrantly deleted from within its |
| // own callback by posting a reference back to the message loop. |
| debug_ipc::MessageLoop::Current()->PostTask( |
| FROM_HERE, [this_ref = std::move(this_ref)]() {}); |
| }); |
| } |
| |
| void AsyncDwarfExprEval::OnEvalComplete(const Err& err, const fxl::RefPtr<EvalContext>& context) { |
| if (err.has_error()) |
| return callback_(err); |
| |
| // The DWARF expression can produce different forms we need to handle. |
| if (dwarf_eval_.GetResultType() == DwarfExprEval::ResultType::kValue) { |
| // Get the concrete type since we need the byte size. But don't use this to actually construct |
| // the variable since it will strip "const" and stuff that the user will expect to see. |
| fxl::RefPtr<Type> concrete_type = context->GetConcreteType(type_.get()); |
| |
| // The DWARF expression produced the exact value (it's not in memory). |
| uint32_t type_size = concrete_type->byte_size(); |
| if (type_size > sizeof(DwarfExprEval::StackEntry)) { |
| callback_( |
| Err(fxl::StringPrintf("Result size insufficient for type of size %u. " |
| "Please file a bug with a repro case.", |
| type_size))); |
| return; |
| } |
| |
| // When the result was read directly from a register or is known to be constant, preserve that |
| // so the user can potentially write to it (or give a good error message about writing to it). |
| ExprValueSource source(ExprValueSource::Type::kTemporary); |
| if (dwarf_eval_.current_register_id() != debug_ipc::RegisterID::kUnknown) |
| source = ExprValueSource(dwarf_eval_.current_register_id()); |
| else if (dwarf_eval_.result_is_constant()) |
| source = ExprValueSource(ExprValueSource::Type::kConstant); |
| |
| uint64_t result_int = dwarf_eval_.GetResult(); |
| |
| std::vector<uint8_t> data; |
| data.resize(type_size); |
| memcpy(&data[0], &result_int, type_size); |
| callback_(ExprValue(type_, std::move(data), source)); |
| } else if (dwarf_eval_.GetResultType() == DwarfExprEval::ResultType::kData) { |
| // The DWARF result is a block of data. |
| // |
| // Here we assume the data size is correct. If it doesn't match the type, that should be caught |
| // later when it's interpreted. |
| // |
| // TODO(bug 39630) we have no source locations for this case. |
| callback_(ExprValue(type_, dwarf_eval_.result_data(), |
| ExprValueSource(ExprValueSource::Type::kComposite))); |
| } else { |
| // The DWARF result is a pointer to the value. |
| uint64_t result_int = dwarf_eval_.GetResult(); |
| ResolvePointer(context, result_int, type_, [this_ref = RefPtrTo(this)](ErrOrValue value) { |
| this_ref->callback_(std::move(value)); |
| }); |
| } |
| } |
| |
| } // namespace zxdb |