blob: 3d133efab3bf63484ed4baf29d927118527d8559 [file] [log] [blame]
//===-- 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 <map>
#include <vector>
// Other libraries and framework includes
// 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/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
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,
eClearUserVisibleDataItemsAllStrings = eClearUserVisibleDataItemsValue | eClearUserVisibleDataItemsSummary | eClearUserVisibleDataItemsLocation | eClearUserVisibleDataItemsDescription,
eClearUserVisibleDataItemsAll = 0xFFFF
};
struct GetValueForExpressionPathOptions
{
bool m_check_dot_vs_arrow_syntax;
bool m_no_fragile_ivar;
bool m_allow_bitfields_syntax;
bool m_no_synthetic_children;
GetValueForExpressionPathOptions(bool dot = false,
bool no_ivar = false,
bool bitfield = true,
bool no_synth = false) :
m_check_dot_vs_arrow_syntax(dot),
m_no_fragile_ivar(no_ivar),
m_allow_bitfields_syntax(bitfield),
m_no_synthetic_children(no_synth)
{
}
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&
DoAllowSyntheticChildren()
{
m_no_synthetic_children = false;
return *this;
}
GetValueForExpressionPathOptions&
DontAllowSyntheticChildren()
{
m_no_synthetic_children = true;
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;
}
bool
IsFirstEvaluation () const
{
return m_first_update;
}
void
SetNeedsUpdate ()
{
m_needs_update = true;
}
void
SetUpdated ();
bool
NeedsUpdating()
{
SyncWithProcessState();
return m_needs_update;
}
bool
IsValid ()
{
if (!m_mod_id.IsValid())
return false;
else if (SyncWithProcessState ())
{
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 ();
ProcessModID m_mod_id; // This is the stop id when this ValueObject was last evaluated.
ExecutionContextRef m_exe_ctx_ref;
bool m_needs_update;
bool m_first_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 ();
//------------------------------------------------------------------
// 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;
}
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();
virtual ValueObject*
GetRoot ();
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<size_t> &idxs,
size_t* index_of_error = NULL);
lldb::ValueObjectSP
GetChildAtIndexPath (const std::vector<size_t> &idxs,
size_t* index_of_error = NULL);
lldb::ValueObjectSP
GetChildAtIndexPath (const std::initializer_list< std::pair<size_t, bool> > &idxs,
size_t* index_of_error = NULL);
lldb::ValueObjectSP
GetChildAtIndexPath (const std::vector< std::pair<size_t, bool> > &idxs,
size_t* index_of_error = NULL);
// this will always create the children if necessary
lldb::ValueObjectSP
GetChildAtNamePath (const std::initializer_list<ConstString> &names,
ConstString* name_of_error = NULL);
lldb::ValueObjectSP
GetChildAtNamePath (const std::vector<ConstString> &names,
ConstString* name_of_error = NULL);
lldb::ValueObjectSP
GetChildAtNamePath (const std::initializer_list< std::pair<ConstString, bool> > &names,
ConstString* name_of_error = NULL);
lldb::ValueObjectSP
GetChildAtNamePath (const std::vector< std::pair<ConstString, bool> > &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);
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;
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
GetSyntheticArrayMemberFromPointer (size_t index, bool can_create);
lldb::ValueObjectSP
GetSyntheticArrayMemberFromArray (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
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; }
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 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
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);
// 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 (Stream& s,
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);
bool
GetIsConstant () const
{
return m_update_point.IsConstant();
}
void
SetIsConstant ()
{
m_update_point.SetIsConstant();
}
lldb::Format
GetFormat () const;
void
SetFormat (lldb::Format format)
{
if (format != m_format)
ClearUserVisibleData(eClearUserVisibleDataItemsValue);
m_format = format;
}
lldb::TypeSummaryImplSP
GetSummaryFormat()
{
UpdateFormatsIfNeeded();
return m_type_summary_sp;
}
void
SetSummaryFormat(lldb::TypeSummaryImplSP format)
{
m_type_summary_sp = format;
ClearUserVisibleData(eClearUserVisibleDataItemsSummary);
}
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();
protected:
typedef ClusterManager<ValueObject> 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)
{
m_children_count = count;
}
size_t
GetChildrenCount ()
{
return m_children_count;
}
void
Clear()
{
m_children_count = 0;
Mutex::Locker locker(m_mutex);
m_children.clear();
}
private:
typedef std::map<size_t, ValueObject*> 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.
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<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;
ProcessModID m_user_id_of_forced_summary;
AddressType m_address_type_of_ptr_or_ref_children;
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;
friend class ClangExpressionDeclMap; // For GetValue
friend class ClangExpressionVariable; // For SetName
friend class Target; // For SetName
friend class ValueObjectConstResultImpl;
//------------------------------------------------------------------
// 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 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);
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_