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