blob: 0808b86c67a1ce4a9eaeba981ae7e95f883eb015 [file] [log] [blame]
//===-- ValueObject.h -------------------------------------------*- C++ -*-===//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#ifndef liblldb_ValueObject_h_
#define liblldb_ValueObject_h_
#include "lldb/Core/Value.h"
#include "lldb/Symbol/CompilerType.h"
#include "lldb/Symbol/Type.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Process.h"
#include "lldb/Utility/ConstString.h"
#include "lldb/Utility/DataExtractor.h"
#include "lldb/Utility/SharedCluster.h"
#include "lldb/Utility/Status.h"
#include "lldb/Utility/UserID.h"
#include "lldb/lldb-defines.h"
#include "lldb/lldb-enumerations.h"
#include "lldb/lldb-forward.h"
#include "lldb/lldb-private-enumerations.h"
#include "lldb/lldb-types.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include <functional>
#include <initializer_list>
#include <map>
#include <mutex>
#include <string>
#include <utility>
#include <stddef.h>
#include <stdint.h>
namespace lldb_private {
class Declaration;
class DumpValueObjectOptions;
class EvaluateExpressionOptions;
class ExecutionContextScope;
class Log;
class Scalar;
class Stream;
class SymbolContextScope;
class TypeFormatImpl;
class TypeSummaryImpl;
class TypeSummaryOptions;
/// ValueObject:
/// This abstract class provides an interface to a particular value, be it a
/// register, a local or global variable,
/// that is evaluated in some particular scope. The ValueObject also has the
/// capability of being the "child" of
/// some other variable object, and in turn of having children.
/// If a ValueObject is a root variable object - having no parent - then it must
/// be constructed with respect to some
/// particular ExecutionContextScope. If it is a child, it inherits the
/// ExecutionContextScope from its parent.
/// The ValueObject will update itself if necessary before fetching its value,
/// summary, object description, etc.
/// But it will always update itself in the ExecutionContextScope with which it
/// was originally created.
/// A brief note on life cycle management for ValueObjects. This is a little
/// tricky because a ValueObject can contain
/// various other ValueObjects - the Dynamic Value, its children, the
/// dereference value, etc. Any one of these can be
/// handed out as a shared pointer, but for that contained value object to be
/// valid, the root object and potentially other
/// of the value objects need to stay around.
/// We solve this problem by handing out shared pointers to the Value Object and
/// any of its dependents using a shared
/// ClusterManager. This treats each shared pointer handed out for the entire
/// cluster as a reference to the whole
/// cluster. The whole cluster will stay around until the last reference is
/// released.
/// The ValueObject mostly handle this automatically, if a value object is made
/// with a Parent ValueObject, then it adds
/// itself to the ClusterManager of the parent.
/// It does mean that external to the ValueObjects we should only ever make
/// available ValueObjectSP's, never ValueObjects
/// or pointers to them. So all the "Root level" ValueObject derived
/// constructors should be private, and
/// should implement a Create function that new's up object and returns a Shared
/// Pointer that it gets from the GetSP() method.
/// However, if you are making an derived ValueObject that will be contained in
/// a parent value object, you should just
/// hold onto a pointer to it internally, and by virtue of passing the parent
/// ValueObject into its constructor, it will
/// be added to the ClusterManager for the parent. Then if you ever hand out a
/// Shared Pointer to the contained ValueObject,
/// just do so by calling GetSP() on the contained object.
class ValueObject : public UserID {
enum GetExpressionPathFormat {
eGetExpressionPathFormatDereferencePointers = 1,
enum ValueObjectRepresentationStyle {
eValueObjectRepresentationStyleValue = 1,
enum ExpressionPathScanEndReason {
eExpressionPathScanEndReasonEndOfString = 1, // out of data to parse
eExpressionPathScanEndReasonNoSuchChild, // child element not found
eExpressionPathScanEndReasonNoSuchSyntheticChild, // (synthetic) child
// element not found
eExpressionPathScanEndReasonEmptyRangeNotAllowed, // [] only allowed for
// arrays
eExpressionPathScanEndReasonDotInsteadOfArrow, // . used when -> should be
// used
eExpressionPathScanEndReasonArrowInsteadOfDot, // -> used when . should be
// used
eExpressionPathScanEndReasonFragileIVarNotAllowed, // ObjC ivar expansion
// not allowed
eExpressionPathScanEndReasonRangeOperatorNotAllowed, // [] not allowed by
// options
eExpressionPathScanEndReasonRangeOperatorInvalid, // [] not valid on objects
// other than scalars,
// pointers or arrays
eExpressionPathScanEndReasonArrayRangeOperatorMet, // [] is good for arrays,
// but I cannot parse it
eExpressionPathScanEndReasonBitfieldRangeOperatorMet, // [] is good for
// bitfields, but I
// cannot parse after
// it
eExpressionPathScanEndReasonUnexpectedSymbol, // something is malformed in
// the expression
eExpressionPathScanEndReasonTakingAddressFailed, // impossible to apply &
// operator
eExpressionPathScanEndReasonDereferencingFailed, // impossible to apply *
// operator
eExpressionPathScanEndReasonRangeOperatorExpanded, // [] was expanded into a
// VOList
eExpressionPathScanEndReasonSyntheticValueMissing, // getting the synthetic
// children failed
eExpressionPathScanEndReasonUnknown = 0xFFFF
enum ExpressionPathEndResultType {
eExpressionPathEndResultTypePlain = 1, // anything but...
eExpressionPathEndResultTypeBitfield, // a bitfield
eExpressionPathEndResultTypeBoundedRange, // a range [low-high]
eExpressionPathEndResultTypeUnboundedRange, // a range []
eExpressionPathEndResultTypeValueObjectList, // several items in a VOList
eExpressionPathEndResultTypeInvalid = 0xFFFF
enum ExpressionPathAftermath {
eExpressionPathAftermathNothing = 1, // just return it
eExpressionPathAftermathDereference, // dereference the target
eExpressionPathAftermathTakeAddress // take target's address
enum ClearUserVisibleDataItems {
eClearUserVisibleDataItemsNothing = 1u << 0,
eClearUserVisibleDataItemsValue = 1u << 1,
eClearUserVisibleDataItemsSummary = 1u << 2,
eClearUserVisibleDataItemsLocation = 1u << 3,
eClearUserVisibleDataItemsDescription = 1u << 4,
eClearUserVisibleDataItemsSyntheticChildren = 1u << 5,
eClearUserVisibleDataItemsValidator = 1u << 6,
eClearUserVisibleDataItemsAllStrings =
eClearUserVisibleDataItemsValue | eClearUserVisibleDataItemsSummary |
eClearUserVisibleDataItemsLocation |
eClearUserVisibleDataItemsAll = 0xFFFF
struct GetValueForExpressionPathOptions {
enum class SyntheticChildrenTraversal {
bool m_check_dot_vs_arrow_syntax;
bool m_no_fragile_ivar;
bool m_allow_bitfields_syntax;
SyntheticChildrenTraversal m_synthetic_children_traversal;
bool dot = false, bool no_ivar = false, bool bitfield = true,
SyntheticChildrenTraversal synth_traverse =
: m_check_dot_vs_arrow_syntax(dot), m_no_fragile_ivar(no_ivar),
m_synthetic_children_traversal(synth_traverse) {}
GetValueForExpressionPathOptions &DoCheckDotVsArrowSyntax() {
m_check_dot_vs_arrow_syntax = true;
return *this;
GetValueForExpressionPathOptions &DontCheckDotVsArrowSyntax() {
m_check_dot_vs_arrow_syntax = false;
return *this;
GetValueForExpressionPathOptions &DoAllowFragileIVar() {
m_no_fragile_ivar = false;
return *this;
GetValueForExpressionPathOptions &DontAllowFragileIVar() {
m_no_fragile_ivar = true;
return *this;
GetValueForExpressionPathOptions &DoAllowBitfieldSyntax() {
m_allow_bitfields_syntax = true;
return *this;
GetValueForExpressionPathOptions &DontAllowBitfieldSyntax() {
m_allow_bitfields_syntax = false;
return *this;
GetValueForExpressionPathOptions &
SetSyntheticChildrenTraversal(SyntheticChildrenTraversal traverse) {
m_synthetic_children_traversal = traverse;
return *this;
static const GetValueForExpressionPathOptions DefaultOptions() {
static GetValueForExpressionPathOptions g_default_options;
return g_default_options;
class EvaluationPoint {
EvaluationPoint(ExecutionContextScope *exe_scope,
bool use_selected = false);
EvaluationPoint(const EvaluationPoint &rhs);
const ExecutionContextRef &GetExecutionContextRef() const {
return m_exe_ctx_ref;
// Set the EvaluationPoint to the values in exe_scope, Return true if the
// Evaluation Point changed. Since the ExecutionContextScope is always
// going to be valid currently, the Updated Context will also always be
// valid.
// bool
// SetContext (ExecutionContextScope *exe_scope);
void SetIsConstant() {
bool IsConstant() const { return !m_mod_id.IsValid(); }
ProcessModID GetModID() const { return m_mod_id; }
void SetUpdateID(ProcessModID new_id) { m_mod_id = new_id; }
void SetNeedsUpdate() { m_needs_update = true; }
void SetUpdated();
bool NeedsUpdating(bool accept_invalid_exe_ctx) {
return m_needs_update;
bool IsValid() {
const bool accept_invalid_exe_ctx = false;
if (!m_mod_id.IsValid())
return false;
else if (SyncWithProcessState(accept_invalid_exe_ctx)) {
if (!m_mod_id.IsValid())
return false;
return true;
void SetInvalid() {
// Use the stop id to mark us as invalid, leave the thread id and the
// stack id around for logging and history purposes.
// Can't update an invalid state.
m_needs_update = false;
bool SyncWithProcessState(bool accept_invalid_exe_ctx);
ProcessModID m_mod_id; // This is the stop id when this ValueObject was last
// evaluated.
ExecutionContextRef m_exe_ctx_ref;
bool m_needs_update;
virtual ~ValueObject();
const EvaluationPoint &GetUpdatePoint() const { return m_update_point; }
EvaluationPoint &GetUpdatePoint() { return m_update_point; }
const ExecutionContextRef &GetExecutionContextRef() const {
return m_update_point.GetExecutionContextRef();
lldb::TargetSP GetTargetSP() const {
return m_update_point.GetExecutionContextRef().GetTargetSP();
lldb::ProcessSP GetProcessSP() const {
return m_update_point.GetExecutionContextRef().GetProcessSP();
lldb::ThreadSP GetThreadSP() const {
return m_update_point.GetExecutionContextRef().GetThreadSP();
lldb::StackFrameSP GetFrameSP() const {
return m_update_point.GetExecutionContextRef().GetFrameSP();
void SetNeedsUpdate();
CompilerType GetCompilerType();
// this vends a TypeImpl that is useful at the SB API layer
virtual TypeImpl GetTypeImpl();
virtual bool CanProvideValue();
// Subclasses must implement the functions below.
virtual uint64_t GetByteSize() = 0;
virtual lldb::ValueType GetValueType() const = 0;
// Subclasses can implement the functions below.
virtual ConstString GetTypeName();
virtual ConstString GetDisplayTypeName();
virtual ConstString GetQualifiedTypeName();
virtual lldb::LanguageType GetObjectRuntimeLanguage();
virtual uint32_t
GetTypeInfo(CompilerType *pointee_or_element_compiler_type = nullptr);
virtual bool IsPointerType();
virtual bool IsArrayType();
virtual bool IsScalarType();
virtual bool IsPointerOrReferenceType();
virtual bool IsPossibleDynamicType();
bool IsNilReference();
bool IsUninitializedReference();
virtual bool IsBaseClass() { return false; }
bool IsBaseClass(uint32_t &depth);
virtual bool IsDereferenceOfParent() { return false; }
bool IsIntegerType(bool &is_signed);
virtual bool GetBaseClassPath(Stream &s);
virtual void GetExpressionPath(
Stream &s, bool qualify_cxx_base_classes,
GetExpressionPathFormat = eGetExpressionPathFormatDereferencePointers);
lldb::ValueObjectSP GetValueForExpressionPath(
llvm::StringRef expression,
ExpressionPathScanEndReason *reason_to_stop = nullptr,
ExpressionPathEndResultType *final_value_type = nullptr,
const GetValueForExpressionPathOptions &options =
ExpressionPathAftermath *final_task_on_target = nullptr);
virtual bool IsInScope() { return true; }
virtual lldb::offset_t GetByteOffset() { return 0; }
virtual uint32_t GetBitfieldBitSize() { return 0; }
virtual uint32_t GetBitfieldBitOffset() { return 0; }
bool IsBitfield() {
return (GetBitfieldBitSize() != 0) || (GetBitfieldBitOffset() != 0);
virtual bool IsArrayItemForPointer() { return m_is_array_item_for_pointer; }
virtual const char *GetValueAsCString();
virtual bool GetValueAsCString(const lldb_private::TypeFormatImpl &format,
std::string &destination);
bool GetValueAsCString(lldb::Format format, std::string &destination);
virtual uint64_t GetValueAsUnsigned(uint64_t fail_value,
bool *success = nullptr);
virtual int64_t GetValueAsSigned(int64_t fail_value, bool *success = nullptr);
virtual bool SetValueFromCString(const char *value_str, Status &error);
// Return the module associated with this value object in case the value is
// from an executable file and might have its data in sections of the file.
// This can be used for variables.
virtual lldb::ModuleSP GetModule();
ValueObject *GetRoot();
// Given a ValueObject, loop over itself and its parent, and its parent's
// parent, .. until either the given callback returns false, or you end up at
// a null pointer
ValueObject *FollowParentChain(std::function<bool(ValueObject *)>);
virtual bool GetDeclaration(Declaration &decl);
// The functions below should NOT be modified by subclasses
const Status &GetError();
ConstString GetName() const;
virtual lldb::ValueObjectSP GetChildAtIndex(size_t idx, bool can_create);
// this will always create the children if necessary
lldb::ValueObjectSP GetChildAtIndexPath(llvm::ArrayRef<size_t> idxs,
size_t *index_of_error = nullptr);
GetChildAtIndexPath(llvm::ArrayRef<std::pair<size_t, bool>> idxs,
size_t *index_of_error = nullptr);
// this will always create the children if necessary
lldb::ValueObjectSP GetChildAtNamePath(llvm::ArrayRef<ConstString> names,
ConstString *name_of_error = nullptr);
GetChildAtNamePath(llvm::ArrayRef<std::pair<ConstString, bool>> names,
ConstString *name_of_error = nullptr);
virtual lldb::ValueObjectSP GetChildMemberWithName(ConstString name,
bool can_create);
virtual size_t GetIndexOfChildWithName(ConstString name);
size_t GetNumChildren(uint32_t max = UINT32_MAX);
const Value &GetValue() const;
Value &GetValue();
virtual bool ResolveValue(Scalar &scalar);
// return 'false' whenever you set the error, otherwise callers may assume
// true means everything is OK - this will break breakpoint conditions among
// potentially a few others
virtual bool IsLogicalTrue(Status &error);
virtual const char *GetLocationAsCString();
const char *
GetSummaryAsCString(lldb::LanguageType lang = lldb::eLanguageTypeUnknown);
GetSummaryAsCString(TypeSummaryImpl *summary_ptr, std::string &destination,
lldb::LanguageType lang = lldb::eLanguageTypeUnknown);
bool GetSummaryAsCString(std::string &destination,
const TypeSummaryOptions &options);
bool GetSummaryAsCString(TypeSummaryImpl *summary_ptr,
std::string &destination,
const TypeSummaryOptions &options);
std::pair<TypeValidatorResult, std::string> GetValidationStatus();
const char *GetObjectDescription();
bool HasSpecialPrintableRepresentation(
ValueObjectRepresentationStyle val_obj_display,
lldb::Format custom_format);
enum class PrintableRepresentationSpecialCases : bool {
eDisable = false,
eAllow = true
DumpPrintableRepresentation(Stream &s,
ValueObjectRepresentationStyle val_obj_display =
lldb::Format custom_format = lldb::eFormatInvalid,
PrintableRepresentationSpecialCases special =
bool do_dump_error = true);
bool GetValueIsValid() const;
// If you call this on a newly created ValueObject, it will always return
// false.
bool GetValueDidChange();
bool UpdateValueIfNeeded(bool update_format = true);
bool UpdateFormatsIfNeeded();
lldb::ValueObjectSP GetSP() { return m_manager->GetSharedPointer(this); }
// Change the name of the current ValueObject. Should *not* be used from a
// synthetic child provider as it would change the name of the non synthetic
// child as well.
void SetName(ConstString name);
virtual lldb::addr_t GetAddressOf(bool scalar_is_load_address = true,
AddressType *address_type = nullptr);
lldb::addr_t GetPointerValue(AddressType *address_type = nullptr);
lldb::ValueObjectSP GetSyntheticChild(ConstString key) const;
lldb::ValueObjectSP GetSyntheticArrayMember(size_t index, bool can_create);
lldb::ValueObjectSP GetSyntheticBitFieldChild(uint32_t from, uint32_t to,
bool can_create);
lldb::ValueObjectSP GetSyntheticExpressionPathChild(const char *expression,
bool can_create);
virtual lldb::ValueObjectSP
GetSyntheticChildAtOffset(uint32_t offset, const CompilerType &type,
bool can_create,
ConstString name_const_str = ConstString());
virtual lldb::ValueObjectSP
GetSyntheticBase(uint32_t offset, const CompilerType &type, bool can_create,
ConstString name_const_str = ConstString());
virtual lldb::ValueObjectSP GetDynamicValue(lldb::DynamicValueType valueType);
lldb::DynamicValueType GetDynamicValueType();
virtual lldb::ValueObjectSP GetStaticValue();
virtual lldb::ValueObjectSP GetNonSyntheticValue();
lldb::ValueObjectSP GetSyntheticValue(bool use_synthetic = true);
virtual bool HasSyntheticValue();
virtual bool IsSynthetic() { return false; }
GetQualifiedRepresentationIfAvailable(lldb::DynamicValueType dynValue,
bool synthValue);
virtual lldb::ValueObjectSP CreateConstantValue(ConstString name);
virtual lldb::ValueObjectSP Dereference(Status &error);
// Creates a copy of the ValueObject with a new name and setting the current
// ValueObject as its parent. It should be used when we want to change the
// name of a ValueObject without modifying the actual ValueObject itself
// (e.g. sythetic child provider).
virtual lldb::ValueObjectSP Clone(ConstString new_name);
virtual lldb::ValueObjectSP AddressOf(Status &error);
virtual lldb::addr_t GetLiveAddress() { return LLDB_INVALID_ADDRESS; }
virtual void SetLiveAddress(lldb::addr_t addr = LLDB_INVALID_ADDRESS,
AddressType address_type = eAddressTypeLoad) {}
virtual lldb::ValueObjectSP Cast(const CompilerType &compiler_type);
virtual lldb::ValueObjectSP CastPointerType(const char *name,
CompilerType &ast_type);
virtual lldb::ValueObjectSP CastPointerType(const char *name,
lldb::TypeSP &type_sp);
// The backing bits of this value object were updated, clear any descriptive
// string, so we know we have to refetch them
virtual void ValueUpdated() {
ClearUserVisibleData(eClearUserVisibleDataItemsValue |
eClearUserVisibleDataItemsSummary |
virtual bool IsDynamic() { return false; }
virtual bool DoesProvideSyntheticValue() { return false; }
virtual bool IsSyntheticChildrenGenerated();
virtual void SetSyntheticChildrenGenerated(bool b);
virtual SymbolContextScope *GetSymbolContextScope();
void Dump(Stream &s);
void Dump(Stream &s, const DumpValueObjectOptions &options);
static lldb::ValueObjectSP
CreateValueObjectFromExpression(llvm::StringRef name,
llvm::StringRef expression,
const ExecutionContext &exe_ctx);
static lldb::ValueObjectSP
CreateValueObjectFromExpression(llvm::StringRef name,
llvm::StringRef expression,
const ExecutionContext &exe_ctx,
const EvaluateExpressionOptions &options);
static lldb::ValueObjectSP
CreateValueObjectFromAddress(llvm::StringRef name, uint64_t address,
const ExecutionContext &exe_ctx,
CompilerType type);
static lldb::ValueObjectSP
CreateValueObjectFromData(llvm::StringRef name, const DataExtractor &data,
const ExecutionContext &exe_ctx, CompilerType type);
void LogValueObject(Log *log);
void LogValueObject(Log *log, const DumpValueObjectOptions &options);
lldb::ValueObjectSP Persist();
// returns true if this is a char* or a char[] if it is a char* and
// check_pointer is true, it also checks that the pointer is valid
bool IsCStringContainer(bool check_pointer = false);
std::pair<size_t, bool>
ReadPointedString(lldb::DataBufferSP &buffer_sp, Status &error,
uint32_t max_length = 0, bool honor_array = true,
lldb::Format item_format = lldb::eFormatCharArray);
virtual size_t GetPointeeData(DataExtractor &data, uint32_t item_idx = 0,
uint32_t item_count = 1);
virtual uint64_t GetData(DataExtractor &data, Status &error);
virtual bool SetData(DataExtractor &data, Status &error);
virtual bool GetIsConstant() const { return m_update_point.IsConstant(); }
bool NeedsUpdating() {
const bool accept_invalid_exe_ctx =
(CanUpdateWithInvalidExecutionContext() == eLazyBoolYes);
return m_update_point.NeedsUpdating(accept_invalid_exe_ctx);
void SetIsConstant() { m_update_point.SetIsConstant(); }
lldb::Format GetFormat() const;
virtual void SetFormat(lldb::Format format) {
if (format != m_format)
m_format = format;
virtual lldb::LanguageType GetPreferredDisplayLanguage();
void SetPreferredDisplayLanguage(lldb::LanguageType);
lldb::TypeSummaryImplSP GetSummaryFormat() {
return m_type_summary_sp;
void SetSummaryFormat(lldb::TypeSummaryImplSP format) {
m_type_summary_sp = format;
lldb::TypeValidatorImplSP GetValidator() {
return m_type_validator_sp;
void SetValidator(lldb::TypeValidatorImplSP format) {
m_type_validator_sp = format;
void SetValueFormat(lldb::TypeFormatImplSP format) {
m_type_format_sp = format;
lldb::TypeFormatImplSP GetValueFormat() {
return m_type_format_sp;
void SetSyntheticChildren(const lldb::SyntheticChildrenSP &synth_sp) {
if (synth_sp.get() == m_synthetic_children_sp.get())
m_synthetic_children_sp = synth_sp;
lldb::SyntheticChildrenSP GetSyntheticChildren() {
return m_synthetic_children_sp;
// Use GetParent for display purposes, but if you want to tell the parent to
// update itself then use m_parent. The ValueObjectDynamicValue's parent is
// not the correct parent for displaying, they are really siblings, so for
// display it needs to route through to its grandparent.
virtual ValueObject *GetParent() { return m_parent; }
virtual const ValueObject *GetParent() const { return m_parent; }
ValueObject *GetNonBaseClassParent();
void SetAddressTypeOfChildren(AddressType at) {
m_address_type_of_ptr_or_ref_children = at;
AddressType GetAddressTypeOfChildren();
void SetHasCompleteType() { m_did_calculate_complete_objc_class_type = true; }
/// Find out if a ValueObject might have children.
/// This call is much more efficient than CalculateNumChildren() as
/// it doesn't need to complete the underlying type. This is designed
/// to be used in a UI environment in order to detect if the
/// disclosure triangle should be displayed or not.
/// This function returns true for class, union, structure,
/// pointers, references, arrays and more. Again, it does so without
/// doing any expensive type completion.
/// \return
/// Returns \b true if the ValueObject might have children, or \b
/// false otherwise.
virtual bool MightHaveChildren();
virtual lldb::VariableSP GetVariable() { return nullptr; }
virtual bool IsRuntimeSupportValue();
virtual uint64_t GetLanguageFlags();
virtual void SetLanguageFlags(uint64_t flags);
typedef ClusterManager<ValueObject> ValueObjectManager;
class ChildrenManager {
ChildrenManager() : m_mutex(), m_children(), m_children_count(0) {}
bool HasChildAtIndex(size_t idx) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
return (m_children.find(idx) != m_children.end());
ValueObject *GetChildAtIndex(size_t idx) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
const auto iter = m_children.find(idx);
return ((iter == m_children.end()) ? nullptr : iter->second);
void SetChildAtIndex(size_t idx, ValueObject *valobj) {
// we do not need to be mutex-protected to make a pair
ChildrenPair pair(idx, valobj);
std::lock_guard<std::recursive_mutex> guard(m_mutex);
void SetChildrenCount(size_t count) { Clear(count); }
size_t GetChildrenCount() { return m_children_count; }
void Clear(size_t new_count = 0) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
m_children_count = new_count;
typedef std::map<size_t, ValueObject *> ChildrenMap;
typedef ChildrenMap::iterator ChildrenIterator;
typedef ChildrenMap::value_type ChildrenPair;
std::recursive_mutex m_mutex;
ChildrenMap m_children;
size_t m_children_count;
// Classes that inherit from ValueObject can see and modify these
*m_parent; // The parent value object, or nullptr if this has no parent
ValueObject *m_root; // The root of the hierarchy for this ValueObject (or
// nullptr if never calculated)
EvaluationPoint m_update_point; // Stores both the stop id and the full
// context at which this value was last
// updated. When we are asked to update the value object, we check whether
// the context & stop id are the same before updating.
ConstString m_name; // The name of this object
m_data; // A data extractor that can be used to extract the value.
Value m_value;
m_error; // An error object that can describe any errors that occur when
// updating values.
std::string m_value_str; // Cached value string that will get cleared if/when
// the value is updated.
std::string m_old_value_str; // Cached old value string from the last time the
// value was gotten
std::string m_location_str; // Cached location string that will get cleared
// if/when the value is updated.
std::string m_summary_str; // Cached summary string that will get cleared
// if/when the value is updated.
std::string m_object_desc_str; // Cached result of the "object printer". This
// differs from the summary
// in that the summary is consed up by us, the object_desc_string is builtin.
llvm::Optional<std::pair<TypeValidatorResult, std::string>>
CompilerType m_override_type; // If the type of the value object should be
// overridden, the type to impose.
ValueObjectManager *m_manager; // This object is managed by the root object
// (any ValueObject that gets created
// without a parent.) The manager gets passed through all the generations of
// dependent objects, and will keep the whole cluster of objects alive as
// long as a shared pointer to any of them has been handed out. Shared
// pointers to value objects must always be made with the GetSP method.
ChildrenManager m_children;
std::map<ConstString, ValueObject *> m_synthetic_children;
ValueObject *m_dynamic_value;
ValueObject *m_synthetic_value;
ValueObject *m_deref_valobj;
lldb::ValueObjectSP m_addr_of_valobj_sp; // We have to hold onto a shared
// pointer to this one because it is
// created
// as an independent ValueObjectConstResult, which isn't managed by us.
lldb::Format m_format;
lldb::Format m_last_format;
uint32_t m_last_format_mgr_revision;
lldb::TypeSummaryImplSP m_type_summary_sp;
lldb::TypeFormatImplSP m_type_format_sp;
lldb::SyntheticChildrenSP m_synthetic_children_sp;
lldb::TypeValidatorImplSP m_type_validator_sp;
ProcessModID m_user_id_of_forced_summary;
AddressType m_address_type_of_ptr_or_ref_children;
llvm::SmallVector<uint8_t, 16> m_value_checksum;
lldb::LanguageType m_preferred_display_language;
uint64_t m_language_flags;
bool m_value_is_valid : 1, m_value_did_change : 1, m_children_count_valid : 1,
m_old_value_valid : 1, m_is_deref_of_parent : 1,
m_is_array_item_for_pointer : 1, m_is_bitfield_for_scalar : 1,
m_is_child_at_offset : 1, m_is_getting_summary : 1,
m_did_calculate_complete_objc_class_type : 1,
m_is_synthetic_children_generated : 1;
friend class ValueObjectChild;
friend class ClangExpressionDeclMap; // For GetValue
friend class ExpressionVariable; // For SetName
friend class Target; // For SetName
friend class ValueObjectConstResultImpl;
friend class ValueObjectSynthetic; // For ClearUserVisibleData
// Constructors and Destructors
// Use the no-argument constructor to make a constant variable object (with
// no ExecutionContextScope.)
// Use this constructor to create a "root variable object". The ValueObject
// will be locked to this context through-out its lifespan.
ValueObject(ExecutionContextScope *exe_scope,
AddressType child_ptr_or_ref_addr_type = eAddressTypeLoad);
// Use this constructor to create a ValueObject owned by another ValueObject.
// It will inherit the ExecutionContext of its parent.
ValueObject(ValueObject &parent);
ValueObjectManager *GetManager() { return m_manager; }
virtual bool UpdateValue() = 0;
virtual LazyBool CanUpdateWithInvalidExecutionContext() {
return eLazyBoolCalculate;
virtual void CalculateDynamicValue(lldb::DynamicValueType use_dynamic);
virtual lldb::DynamicValueType GetDynamicValueTypeImpl() {
return lldb::eNoDynamicValues;
virtual bool HasDynamicValueTypeInfo() { return false; }
virtual void CalculateSyntheticValue(bool use_synthetic = true);
// Should only be called by ValueObject::GetChildAtIndex() Returns a
// ValueObject managed by this ValueObject's manager.
virtual ValueObject *CreateChildAtIndex(size_t idx,
bool synthetic_array_member,
int32_t synthetic_index);
// Should only be called by ValueObject::GetNumChildren()
virtual size_t CalculateNumChildren(uint32_t max = UINT32_MAX) = 0;
void SetNumChildren(size_t num_children);
void SetValueDidChange(bool value_changed);
void SetValueIsValid(bool valid);
void ClearUserVisibleData(
uint32_t items = ValueObject::eClearUserVisibleDataItemsAllStrings);
void AddSyntheticChild(ConstString key, ValueObject *valobj);
DataExtractor &GetDataExtractor();
void ClearDynamicTypeInformation();
// Subclasses must implement the functions below.
virtual CompilerType GetCompilerTypeImpl() = 0;
const char *GetLocationAsCStringImpl(const Value &value,
const DataExtractor &data);
bool IsChecksumEmpty();
void SetPreferredDisplayLanguageIfNeeded(lldb::LanguageType);
virtual CompilerType MaybeCalculateCompleteType();
lldb::ValueObjectSP GetValueForExpressionPath_Impl(
llvm::StringRef expression_cstr,
ExpressionPathScanEndReason *reason_to_stop,
ExpressionPathEndResultType *final_value_type,
const GetValueForExpressionPathOptions &options,
ExpressionPathAftermath *final_task_on_target);
// A value object manager class that is seeded with the static variable value
// and it vends the user facing value object. If the type is dynamic it can
// vend the dynamic type. If this user type also has a synthetic type
// associated with it, it will vend the synthetic type. The class watches the
// process' stop
// ID and will update the user type when needed.
class ValueObjectManager {
// The root value object is the static typed variable object.
lldb::ValueObjectSP m_root_valobj_sp;
// The user value object is the value object the user wants to see.
lldb::ValueObjectSP m_user_valobj_sp;
lldb::DynamicValueType m_use_dynamic;
uint32_t m_stop_id; // The stop ID that m_user_valobj_sp is valid for.
bool m_use_synthetic;
ValueObjectManager() {}
ValueObjectManager(lldb::ValueObjectSP in_valobj_sp,
lldb::DynamicValueType use_dynamic, bool use_synthetic);
bool IsValid() const;
lldb::ValueObjectSP GetRootSP() const { return m_root_valobj_sp; }
// Gets the correct value object from the root object for a given process
// stop ID. If dynamic values are enabled, or if synthetic children are
// enabled, the value object that the user wants to see might change while
// debugging.
lldb::ValueObjectSP GetSP();
void SetUseDynamic(lldb::DynamicValueType use_dynamic);
void SetUseSynthetic(bool use_synthetic);
lldb::DynamicValueType GetUseDynamic() const { return m_use_dynamic; }
bool GetUseSynthetic() const { return m_use_synthetic; }
lldb::TargetSP GetTargetSP() const;
lldb::ProcessSP GetProcessSP() const;
lldb::ThreadSP GetThreadSP() const;
lldb::StackFrameSP GetFrameSP() const;
} // namespace lldb_private
#endif // liblldb_ValueObject_h_