| // 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/expr.h" |
| |
| #include <lib/syslog/cpp/macros.h> |
| |
| #include "src/developer/debug/zxdb/expr/eval_context.h" |
| #include "src/developer/debug/zxdb/expr/expr_node.h" |
| #include "src/developer/debug/zxdb/expr/expr_parser.h" |
| #include "src/developer/debug/zxdb/expr/expr_tokenizer.h" |
| #include "src/developer/debug/zxdb/symbols/modified_type.h" |
| |
| namespace zxdb { |
| |
| namespace { |
| |
| class MultiEvalTracking { |
| public: |
| using OutputVector = std::vector<ErrOrValue>; |
| using Completion = fit::callback<void(OutputVector)>; |
| |
| MultiEvalTracking(size_t count, Completion cb) : remaining_(count), completion_(std::move(cb)) { |
| data_.resize(count, ErrOrValue(ExprValue())); |
| } |
| |
| void SetResult(size_t index, ErrOrValue value) { |
| FX_DCHECK(index < data_.size()); |
| FX_DCHECK(remaining_ > 0); |
| |
| // Nothing should be set on this slot yet. |
| FX_DCHECK(!data_[index].has_error()); |
| FX_DCHECK(data_[index].value() == ExprValue()); |
| |
| data_[index] = std::move(value); |
| |
| remaining_--; |
| if (remaining_ == 0) |
| completion_(std::move(data_)); |
| } |
| |
| private: |
| size_t remaining_; // # callbacks remaining before completion. |
| OutputVector data_; |
| Completion completion_; |
| }; |
| |
| } // namespace |
| |
| void EvalExpression(const std::string& input, const fxl::RefPtr<EvalContext>& context, |
| bool follow_references, EvalCallback cb) { |
| ExprTokenizer tokenizer(input, context->GetLanguage()); |
| if (!tokenizer.Tokenize()) |
| return cb(tokenizer.err()); |
| |
| ExprParser parser(tokenizer.TakeTokens(), tokenizer.language(), |
| context->GetSymbolNameLookupCallback()); |
| auto node = parser.ParseExpression(); |
| if (parser.err().has_error()) { |
| // Add context information since we have the original input string (the |
| // parser doesn't have this). |
| ExprToken error_token = parser.error_token(); |
| if (error_token.type() != ExprTokenType::kInvalid) { |
| Err context_err(parser.err().type(), |
| parser.err().msg() + "\n" + |
| ExprTokenizer::GetErrorContext(input, error_token.byte_offset())); |
| cb(context_err); |
| } else { |
| cb(parser.err()); |
| } |
| return; |
| } |
| |
| if (follow_references) |
| node->Eval(context, std::move(cb)); |
| else |
| node->EvalFollowReferences(context, std::move(cb)); |
| } |
| |
| void EvalExpressions(const std::vector<std::string>& inputs, |
| const fxl::RefPtr<EvalContext>& context, bool follow_references, |
| fit::callback<void(std::vector<ErrOrValue>)> cb) { |
| FX_DCHECK(!inputs.empty()); |
| |
| auto tracking = std::make_shared<MultiEvalTracking>(inputs.size(), std::move(cb)); |
| for (size_t i = 0; i < inputs.size(); i++) { |
| EvalExpression(inputs[i], context, follow_references, |
| [tracking, i](ErrOrValue value) { tracking->SetResult(i, std::move(value)); }); |
| } |
| } |
| |
| // TODO(bug 44074) support non-pointer values and take their address implicitly. |
| Err ValueToAddressAndSize(const fxl::RefPtr<EvalContext>& eval_context, const ExprValue& value, |
| uint64_t* address, std::optional<uint32_t>* size) { |
| fxl::RefPtr<Type> concrete_type = eval_context->GetConcreteType(value.type()); |
| if (concrete_type->As<Collection>()) { |
| // Don't allow structs and classes that are <= 64 bits to be converted |
| // to addresses. |
| return Err("Can't convert '%s' to an address.", concrete_type->GetFullName().c_str()); |
| } |
| |
| // See if there's an intrinsic size to the object being pointed to. This is true for pointers. |
| // References should have been followed and stripped before here. |
| if (auto modified = concrete_type->As<ModifiedType>(); |
| modified && modified->tag() == DwarfTag::kPointerType) { |
| if (auto modified_type = modified->modified().Get()->As<Type>()) |
| *size = modified_type->byte_size(); |
| } |
| |
| // Convert anything else <= 64 bits to a number. |
| return value.PromoteTo64(address); |
| } |
| |
| } // namespace zxdb |