//===-- ValueObject.h -------------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef liblldb_ValueObject_h_ #define liblldb_ValueObject_h_ // C Includes // C++ Includes #include #include // Other libraries and framework includes #include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallVector.h" // Project includes #include "lldb/lldb-private.h" #include "lldb/Core/DataExtractor.h" #include "lldb/Core/Error.h" #include "lldb/Core/Flags.h" #include "lldb/Core/ConstString.h" #include "lldb/Core/UserID.h" #include "lldb/Core/Value.h" #include "lldb/Symbol/ClangASTType.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/ExecutionContextScope.h" #include "lldb/Target/Process.h" #include "lldb/Target/StackID.h" #include "lldb/Utility/SharedCluster.h" namespace lldb_private { /// 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 { public: enum GetExpressionPathFormat { eGetExpressionPathFormatDereferencePointers = 1, eGetExpressionPathFormatHonorPointers }; enum ValueObjectRepresentationStyle { eValueObjectRepresentationStyleValue = 1, eValueObjectRepresentationStyleSummary, eValueObjectRepresentationStyleLanguageSpecific, eValueObjectRepresentationStyleLocation, eValueObjectRepresentationStyleChildrenCount, eValueObjectRepresentationStyleType, eValueObjectRepresentationStyleName, eValueObjectRepresentationStyleExpressionPath }; 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 | eClearUserVisibleDataItemsDescription, eClearUserVisibleDataItemsAll = 0xFFFF }; struct GetValueForExpressionPathOptions { enum class SyntheticChildrenTraversal { None, ToSynthetic, FromSynthetic, Both }; bool m_check_dot_vs_arrow_syntax; bool m_no_fragile_ivar; bool m_allow_bitfields_syntax; SyntheticChildrenTraversal m_synthetic_children_traversal; GetValueForExpressionPathOptions(bool dot = false, bool no_ivar = false, bool bitfield = true, SyntheticChildrenTraversal synth_traverse = SyntheticChildrenTraversal::ToSynthetic) : m_check_dot_vs_arrow_syntax(dot), m_no_fragile_ivar(no_ivar), m_allow_bitfields_syntax(bitfield), 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 { public: EvaluationPoint (); EvaluationPoint (ExecutionContextScope *exe_scope, bool use_selected = false); EvaluationPoint (const EvaluationPoint &rhs); ~EvaluationPoint (); 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 () { SetUpdated(); m_mod_id.SetInvalid(); } 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) { SyncWithProcessState(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. m_mod_id.SetInvalid(); // Can't update an invalid state. m_needs_update = false; } private: 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; }; 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 (); virtual ~ValueObject(); ClangASTType GetClangType (); // 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 (ClangASTType *pointee_or_element_clang_type = NULL); virtual bool IsPointerType (); virtual bool IsArrayType (); virtual bool IsScalarType (); virtual bool IsPointerOrReferenceType (); virtual bool IsPossibleDynamicType (); virtual bool IsObjCNil (); 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(const char* expression, const char** first_unparsed = NULL, ExpressionPathScanEndReason* reason_to_stop = NULL, ExpressionPathEndResultType* final_value_type = NULL, const GetValueForExpressionPathOptions& options = GetValueForExpressionPathOptions::DefaultOptions(), ExpressionPathAftermath* final_task_on_target = NULL); int GetValuesForExpressionPath(const char* expression, lldb::ValueObjectListSP& list, const char** first_unparsed = NULL, ExpressionPathScanEndReason* reason_to_stop = NULL, ExpressionPathEndResultType* final_value_type = NULL, const GetValueForExpressionPathOptions& options = GetValueForExpressionPathOptions::DefaultOptions(), ExpressionPathAftermath* final_task_on_target = NULL); 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 = NULL); virtual int64_t GetValueAsSigned (int64_t fail_value, bool *success = NULL); virtual bool SetValueFromCString (const char *value_str, Error& 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); virtual bool GetDeclaration (Declaration &decl); //------------------------------------------------------------------ // The functions below should NOT be modified by subclasses //------------------------------------------------------------------ const Error & GetError(); const ConstString & GetName() const; virtual lldb::ValueObjectSP GetChildAtIndex (size_t idx, bool can_create); // this will always create the children if necessary lldb::ValueObjectSP GetChildAtIndexPath (const std::initializer_list &idxs, size_t* index_of_error = NULL); lldb::ValueObjectSP GetChildAtIndexPath (const std::vector &idxs, size_t* index_of_error = NULL); lldb::ValueObjectSP GetChildAtIndexPath (const std::initializer_list< std::pair > &idxs, size_t* index_of_error = NULL); lldb::ValueObjectSP GetChildAtIndexPath (const std::vector< std::pair > &idxs, size_t* index_of_error = NULL); // this will always create the children if necessary lldb::ValueObjectSP GetChildAtNamePath (const std::initializer_list &names, ConstString* name_of_error = NULL); lldb::ValueObjectSP GetChildAtNamePath (const std::vector &names, ConstString* name_of_error = NULL); lldb::ValueObjectSP GetChildAtNamePath (const std::initializer_list< std::pair > &names, ConstString* name_of_error = NULL); lldb::ValueObjectSP GetChildAtNamePath (const std::vector< std::pair > &names, ConstString* name_of_error = NULL); virtual lldb::ValueObjectSP GetChildMemberWithName (const ConstString &name, bool can_create); virtual size_t GetIndexOfChildWithName (const ConstString &name); size_t GetNumChildren (); const Value & GetValue() const; Value & GetValue(); virtual bool ResolveValue (Scalar &scalar); virtual const char * GetLocationAsCString (); const char * GetSummaryAsCString (); bool GetSummaryAsCString (TypeSummaryImpl* summary_ptr, std::string& destination); bool GetSummaryAsCString (std::string& destination, const TypeSummaryOptions& options); bool GetSummaryAsCString (TypeSummaryImpl* summary_ptr, std::string& destination, const TypeSummaryOptions& options); std::pair GetValidationStatus (); const char * GetObjectDescription (); bool HasSpecialPrintableRepresentation (ValueObjectRepresentationStyle val_obj_display, lldb::Format custom_format); enum PrintableRepresentationSpecialCases { ePrintableRepresentationSpecialCasesDisable = 0, ePrintableRepresentationSpecialCasesAllow = 1, ePrintableRepresentationSpecialCasesOnly = 3 }; bool DumpPrintableRepresentation (Stream& s, ValueObjectRepresentationStyle val_obj_display = eValueObjectRepresentationStyleSummary, lldb::Format custom_format = lldb::eFormatInvalid, PrintableRepresentationSpecialCases special = ePrintableRepresentationSpecialCasesAllow, 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); } void SetName (const ConstString &name); virtual lldb::addr_t GetAddressOf (bool scalar_is_load_address = true, AddressType *address_type = NULL); lldb::addr_t GetPointerValue (AddressType *address_type = NULL); lldb::ValueObjectSP GetSyntheticChild (const 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 ClangASTType& type, bool can_create); virtual lldb::ValueObjectSP GetSyntheticBase (uint32_t offset, const ClangASTType& type, bool can_create); 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; } lldb::ValueObjectSP GetQualifiedRepresentationIfAvailable (lldb::DynamicValueType dynValue, bool synthValue); virtual lldb::ValueObjectSP CreateConstantValue (const ConstString &name); virtual lldb::ValueObjectSP Dereference (Error &error); virtual lldb::ValueObjectSP AddressOf (Error &error); virtual lldb::addr_t GetLiveAddress() { return LLDB_INVALID_ADDRESS; } virtual void SetLiveAddress(lldb::addr_t addr = LLDB_INVALID_ADDRESS, AddressType address_type = eAddressTypeLoad) { } // Find the address of the C++ vtable pointer virtual lldb::addr_t GetCPPVTableAddress(AddressType &address_type); virtual lldb::ValueObjectSP Cast (const ClangASTType &clang_ast_type); virtual lldb::ValueObjectSP CastPointerType (const char *name, ClangASTType &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 | eClearUserVisibleDataItemsDescription); } virtual bool IsDynamic () { return false; } virtual bool DoesProvideSyntheticValue () { return false; } bool IsSyntheticChildrenGenerated (); void SetSyntheticChildrenGenerated (bool b); virtual SymbolContextScope * GetSymbolContextScope(); void Dump (Stream &s); void Dump (Stream &s, const DumpValueObjectOptions& options); static lldb::ValueObjectSP CreateValueObjectFromExpression (const char* name, const char* expression, const ExecutionContext& exe_ctx); static lldb::ValueObjectSP CreateValueObjectFromExpression (const char* name, const char* expression, const ExecutionContext& exe_ctx, const EvaluateExpressionOptions& options); static lldb::ValueObjectSP CreateValueObjectFromAddress (const char* name, uint64_t address, const ExecutionContext& exe_ctx, ClangASTType type); static lldb::ValueObjectSP CreateValueObjectFromData (const char* name, const DataExtractor& data, const ExecutionContext& exe_ctx, ClangASTType 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); size_t ReadPointedString (lldb::DataBufferSP& buffer_sp, Error& 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, Error &error); virtual bool SetData (DataExtractor &data, Error &error); virtual bool GetIsConstant () const { return m_update_point.IsConstant(); } bool NeedsUpdating () { const bool accept_invalid_exe_ctx = CanUpdateWithInvalidExecutionContext(); 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) ClearUserVisibleData(eClearUserVisibleDataItemsValue); m_format = format; } virtual lldb::LanguageType GetPreferredDisplayLanguage (); void SetPreferredDisplayLanguage (lldb::LanguageType); lldb::TypeSummaryImplSP GetSummaryFormat() { UpdateFormatsIfNeeded(); return m_type_summary_sp; } void SetSummaryFormat(lldb::TypeSummaryImplSP format) { m_type_summary_sp = format; ClearUserVisibleData(eClearUserVisibleDataItemsSummary); } lldb::TypeValidatorImplSP GetValidator() { UpdateFormatsIfNeeded(); return m_type_validator_sp; } void SetValidator(lldb::TypeValidatorImplSP format) { m_type_validator_sp = format; ClearUserVisibleData(eClearUserVisibleDataItemsValidator); } void SetValueFormat(lldb::TypeFormatImplSP format) { m_type_format_sp = format; ClearUserVisibleData(eClearUserVisibleDataItemsValue); } lldb::TypeFormatImplSP GetValueFormat() { UpdateFormatsIfNeeded(); return m_type_format_sp; } void SetSyntheticChildren(const lldb::SyntheticChildrenSP &synth_sp) { if (synth_sp.get() == m_synthetic_children_sp.get()) return; ClearUserVisibleData(eClearUserVisibleDataItemsSyntheticChildren); m_synthetic_children_sp = synth_sp; } lldb::SyntheticChildrenSP GetSyntheticChildren() { UpdateFormatsIfNeeded(); 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 bool IsRuntimeSupportValue (); protected: typedef ClusterManager ValueObjectManager; class ChildrenManager { public: ChildrenManager() : m_mutex(Mutex::eMutexTypeRecursive), m_children(), m_children_count(0) {} bool HasChildAtIndex (size_t idx) { Mutex::Locker locker(m_mutex); ChildrenIterator iter = m_children.find(idx); ChildrenIterator end = m_children.end(); return (iter != end); } ValueObject* GetChildAtIndex (size_t idx) { Mutex::Locker locker(m_mutex); ChildrenIterator iter = m_children.find(idx); ChildrenIterator end = m_children.end(); if (iter == end) return NULL; else return iter->second; } void SetChildAtIndex (size_t idx, ValueObject* valobj) { ChildrenPair pair(idx,valobj); // we do not need to be mutex-protected to make a pair Mutex::Locker locker(m_mutex); m_children.insert(pair); } void SetChildrenCount (size_t count) { Clear(count); } size_t GetChildrenCount () { return m_children_count; } void Clear(size_t new_count = 0) { Mutex::Locker locker(m_mutex); m_children_count = new_count; m_children.clear(); } private: typedef std::map ChildrenMap; typedef ChildrenMap::iterator ChildrenIterator; typedef ChildrenMap::value_type ChildrenPair; Mutex m_mutex; ChildrenMap m_children; size_t m_children_count; }; //------------------------------------------------------------------ // Classes that inherit from ValueObject can see and modify these //------------------------------------------------------------------ ValueObject * m_parent; // The parent value object, or NULL if this has no parent ValueObject * m_root; // The root of the hierarchy for this ValueObject (or NULL 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 DataExtractor m_data; // A data extractor that can be used to extract the value. Value m_value; Error 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> m_validation_result; ClangASTType 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 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 m_value_checksum; lldb::LanguageType m_preferred_display_language; 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 ClangExpressionVariable; // 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.) ValueObject(); // 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 bool CanUpdateWithInvalidExecutionContext () { return false; } 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() = 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 (const ConstString &key, ValueObject *valobj); DataExtractor & GetDataExtractor (); void ClearDynamicTypeInformation (); //------------------------------------------------------------------ // Subclasses must implement the functions below. //------------------------------------------------------------------ virtual ClangASTType GetClangTypeImpl () = 0; const char * GetLocationAsCStringImpl (const Value& value, const DataExtractor& data); bool IsChecksumEmpty (); private: //------------------------------------------------------------------ // For ValueObject only //------------------------------------------------------------------ virtual ClangASTType MaybeCalculateCompleteType (); lldb::ValueObjectSP GetValueForExpressionPath_Impl(const char* expression_cstr, const char** first_unparsed, ExpressionPathScanEndReason* reason_to_stop, ExpressionPathEndResultType* final_value_type, const GetValueForExpressionPathOptions& options, ExpressionPathAftermath* final_task_on_target); // this method will ONLY expand [] expressions into a VOList and return // the number of elements it added to the VOList // it will NOT loop through expanding the follow-up of the expression_cstr // for all objects in the list int ExpandArraySliceExpression(const char* expression_cstr, const char** first_unparsed, lldb::ValueObjectSP root, lldb::ValueObjectListSP& list, ExpressionPathScanEndReason* reason_to_stop, ExpressionPathEndResultType* final_value_type, const GetValueForExpressionPathOptions& options, ExpressionPathAftermath* final_task_on_target); DISALLOW_COPY_AND_ASSIGN (ValueObject); }; } // namespace lldb_private #endif // liblldb_ValueObject_h_