mirror of
https://github.com/opnsense/src.git
synced 2026-02-28 04:10:49 -05:00
1294 lines
41 KiB
C++
1294 lines
41 KiB
C++
//===-- 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 <functional>
|
|
#include <initializer_list>
|
|
#include <map>
|
|
#include <vector>
|
|
|
|
// 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/CompilerType.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;
|
|
};
|
|
|
|
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(const char* expression,
|
|
const char** first_unparsed = nullptr,
|
|
ExpressionPathScanEndReason* reason_to_stop = nullptr,
|
|
ExpressionPathEndResultType* final_value_type = nullptr,
|
|
const GetValueForExpressionPathOptions& options = GetValueForExpressionPathOptions::DefaultOptions(),
|
|
ExpressionPathAftermath* final_task_on_target = nullptr);
|
|
|
|
int
|
|
GetValuesForExpressionPath(const char* expression,
|
|
lldb::ValueObjectListSP& list,
|
|
const char** first_unparsed = nullptr,
|
|
ExpressionPathScanEndReason* reason_to_stop = nullptr,
|
|
ExpressionPathEndResultType* final_value_type = nullptr,
|
|
const GetValueForExpressionPathOptions& options = GetValueForExpressionPathOptions::DefaultOptions(),
|
|
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, 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<bool(ValueObject*)>);
|
|
|
|
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 = nullptr);
|
|
|
|
lldb::ValueObjectSP
|
|
GetChildAtIndexPath(const std::vector<size_t> &idxs,
|
|
size_t* index_of_error = nullptr);
|
|
|
|
lldb::ValueObjectSP
|
|
GetChildAtIndexPath(const std::initializer_list< std::pair<size_t, bool> > &idxs,
|
|
size_t* index_of_error = nullptr);
|
|
|
|
lldb::ValueObjectSP
|
|
GetChildAtIndexPath(const std::vector< std::pair<size_t, bool> > &idxs,
|
|
size_t* index_of_error = nullptr);
|
|
|
|
// this will always create the children if necessary
|
|
lldb::ValueObjectSP
|
|
GetChildAtNamePath(const std::initializer_list<ConstString> &names,
|
|
ConstString* name_of_error = nullptr);
|
|
|
|
lldb::ValueObjectSP
|
|
GetChildAtNamePath(const std::vector<ConstString> &names,
|
|
ConstString* name_of_error = nullptr);
|
|
|
|
lldb::ValueObjectSP
|
|
GetChildAtNamePath(const std::initializer_list< std::pair<ConstString, bool> > &names,
|
|
ConstString* name_of_error = nullptr);
|
|
|
|
lldb::ValueObjectSP
|
|
GetChildAtNamePath(const std::vector< std::pair<ConstString, bool> > &names,
|
|
ConstString* name_of_error = nullptr);
|
|
|
|
virtual lldb::ValueObjectSP
|
|
GetChildMemberWithName (const ConstString &name, bool can_create);
|
|
|
|
virtual size_t
|
|
GetIndexOfChildWithName (const 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 (Error& error);
|
|
|
|
virtual const char *
|
|
GetLocationAsCString ();
|
|
|
|
const char *
|
|
GetSummaryAsCString (lldb::LanguageType lang = lldb::eLanguageTypeUnknown);
|
|
|
|
bool
|
|
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 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 = nullptr);
|
|
|
|
lldb::addr_t
|
|
GetPointerValue(AddressType *address_type = nullptr);
|
|
|
|
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 CompilerType& type, bool can_create);
|
|
|
|
virtual lldb::ValueObjectSP
|
|
GetSyntheticBase (uint32_t offset, const CompilerType& 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 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 |
|
|
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,
|
|
CompilerType type);
|
|
|
|
static lldb::ValueObjectSP
|
|
CreateValueObjectFromData (const char* 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,
|
|
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() == 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)
|
|
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 lldb::VariableSP
|
|
GetVariable ()
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
virtual bool
|
|
IsRuntimeSupportValue ();
|
|
|
|
virtual uint64_t
|
|
GetLanguageFlags ();
|
|
|
|
virtual void
|
|
SetLanguageFlags (uint64_t flags);
|
|
|
|
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);
|
|
return (m_children.find(idx) != m_children.end());
|
|
}
|
|
|
|
ValueObject*
|
|
GetChildAtIndex (size_t idx)
|
|
{
|
|
Mutex::Locker locker(m_mutex);
|
|
const auto iter = m_children.find(idx);
|
|
return ((iter == m_children.end()) ? nullptr : 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<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 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
|
|
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<std::pair<TypeValidatorResult, std::string>> m_validation_result;
|
|
|
|
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.)
|
|
|
|
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 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 (const 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);
|
|
|
|
private:
|
|
virtual CompilerType
|
|
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_
|