| // 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. |
| |
| #ifndef SRC_DEVELOPER_DEBUG_ZXDB_EXPR_RESOLVE_COLLECTION_H_ |
| #define SRC_DEVELOPER_DEBUG_ZXDB_EXPR_RESOLVE_COLLECTION_H_ |
| |
| #include <optional> |
| #include <string> |
| |
| #include "lib/fit/function.h" |
| #include "src/developer/debug/zxdb/common/err.h" |
| #include "src/developer/debug/zxdb/expr/eval_callback.h" |
| #include "src/developer/debug/zxdb/expr/expr_value.h" |
| #include "src/developer/debug/zxdb/expr/found_member.h" |
| #include "src/developer/debug/zxdb/expr/found_name.h" |
| #include "src/developer/debug/zxdb/expr/parsed_identifier.h" |
| #include "src/developer/debug/zxdb/symbols/arch.h" |
| #include "src/lib/fxl/memory/ref_ptr.h" |
| |
| namespace zxdb { |
| |
| class CodeBlock; |
| class EvalContext; |
| class ExprValue; |
| class FoundMember; |
| class InheritancePath; |
| class InheritedFrom; |
| |
| // Resolves a member given a collection (class/struct/union) and either a record for a variable |
| // within that collection (in this case the data member must be on the class itself, not on a base |
| // class), or a name of a member. |
| // |
| // These will be synchronous in most cases, but resolving static members may require requesting the |
| // memory from the target which will force an asynchronous result. |
| // |
| // The FoundMember may have no data member in it. If so, calls the callback with an error (this is |
| // so callers don't have to type check the inputs). |
| void ResolveMember(const fxl::RefPtr<EvalContext>& context, const ExprValue& base, |
| const FoundMember& member, EvalCallback cb); |
| void ResolveMember(const fxl::RefPtr<EvalContext>& context, const ExprValue& base, |
| const ParsedIdentifier& identifier, EvalCallback cb); |
| |
| // Synchronous versions of ResolveMember for cases where the value is known not to be an extern |
| // (static) member or on a derived class. This is generally used when hardcoding support for known |
| // structures. |
| // |
| // The variant that takes an initializer list will interpret the strings as identifiers, parse |
| // them, and resolve a nested series of members using those strings. For example, if the input |
| // is {"a", "b"} this will resolve "base.a.b". This is used for hardcoding some printers. |
| ErrOrValue ResolveNonstaticMember(const fxl::RefPtr<EvalContext>& context, const ExprValue& base, |
| const FoundMember& member); |
| ErrOrValue ResolveNonstaticMember(const fxl::RefPtr<EvalContext>& context, const ExprValue& base, |
| const ParsedIdentifier& identifier); |
| ErrOrValue ResolveNonstaticMember(const fxl::RefPtr<EvalContext>& context, const ExprValue& base, |
| std::initializer_list<std::string> names); |
| |
| // The variant takes an ExprValue which is a pointer to the base/struct or class. Because it fetches |
| // memory it is always asynchronous. |
| // |
| // Since it's given a FoundMember, this can not check for members of derived classes. Use the |
| // version that takes an Identifier if you want this capability. |
| void ResolveMemberByPointer(const fxl::RefPtr<EvalContext>& context, const ExprValue& base_ptr, |
| const FoundMember& found_member, EvalCallback cb); |
| |
| // Same as previous version but takes the name of the member to find. The callback also provides the |
| // FoundMember corresponding to what the name matched. |
| // |
| // This also supports (when requested by the EvalContext) automatically converting base class |
| // pointers to derived class pointers when the derived class is known. It allows "foo->bar" where |
| // "bar" is a data member on the current derived class's instance of foo. |
| void ResolveMemberByPointer(const fxl::RefPtr<EvalContext>& context, const ExprValue& base_ptr, |
| const ParsedIdentifier& identifier, |
| fit::callback<void(ErrOrValue, const FoundMember&)> cb); |
| |
| // Takes a collection and an InheritancePath indicating how to get from the value to the desired |
| // base class, and extracts the base class. The |path| should have its derived class be of the type |
| // from |value|, and its base class is the one the caller wants to extract. The path should |
| // represent all intermediate classes. |
| void ResolveInherited(const fxl::RefPtr<EvalContext>& context, const ExprValue& value, |
| const InheritancePath& path, fit::callback<void(ErrOrValue)> cb); |
| |
| // Converts a pointer to a derived class to a pointer to the base class identified by the given |
| // path. This is the same as ResolveInherited() above but operates on pointers to objects rather |
| // than objects themselves. |
| // |
| // For common cases this is just a constant offset, but if the inheritance path has virtual |
| // inheritance, this function will compute the result according to the expressions (may require |
| // fetching memory) |
| void ResolveInheritedPtr(const fxl::RefPtr<EvalContext>& context, TargetPointer derived, |
| const InheritancePath& path, fit::function<void(ErrOr<TargetPointer>)> cb); |
| |
| // Takes a Collection value and a base class inside of it, computes the value of the base class. |
| // This does not support virtual inheritance. |
| // |
| // TODO(brettw) these should be removed in preference to the asynchronous version above. |
| // |
| // For the version that takes an InheritedFrom, the base class must be a direct base class of the |
| // "value" collection, not an indirect base. |
| // |
| // The asynchronous version supports virtual inheritance, while the other variants do not. The |
| // from_symbol_context should be the symbol context associated with the module from which the |
| // InheritedFrom object came. It will be used to evaluate the location expression. |
| // |
| // For the version that takes a type and an offset, the type must already have been computed as some |
| // type of base class that lives at the given offset. It need not be a direct base and no type |
| // checking is done as long as the offsets and sizes are valid. |
| ErrOrValue ResolveInherited(const fxl::RefPtr<EvalContext>& context, const ExprValue& value, |
| const InheritedFrom* from); |
| ErrOrValue ResolveInherited(const fxl::RefPtr<EvalContext>& context, const ExprValue& value, |
| fxl::RefPtr<Type> base_type, uint64_t offset); |
| |
| // Verifies that |input| type is a pointer to a collection and fills the pointed-to type into |
| // |*pointed_to|. In other cases, returns an error. The input type can be null (which will produce |
| // an error) or non-concrete (const, forward definition, etc.) so the caller doesn't have to check. |
| // |
| // The returned type will be concrete which means the type may be modified to strip CV qualifiers. |
| // This is used when looking up collection members by pointer so this is needed. It should not be |
| // used to generate types that might be visible to the user (they'll want the qualifiers). |
| Err GetConcretePointedToCollection(const fxl::RefPtr<EvalContext>& eval_context, const Type* input, |
| fxl::RefPtr<Collection>* pointed_to); |
| |
| } // namespace zxdb |
| |
| #endif // SRC_DEVELOPER_DEBUG_ZXDB_EXPR_RESOLVE_COLLECTION_H_ |