blob: e1dc405bcb6f32a8690d2c3b9813df4887d49ef1 [file] [log] [blame]
// 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