2013-08-23 13:46:38 -04:00
//===-- ValueObject.cpp -----------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
# include "lldb/lldb-python.h"
# include "lldb/Core/ValueObject.h"
// C Includes
# include <stdlib.h>
// C++ Includes
// Other libraries and framework includes
# include "llvm/Support/raw_ostream.h"
# include "clang/AST/Type.h"
// Project includes
# include "lldb/Core/DataBufferHeap.h"
# include "lldb/Core/Debugger.h"
# include "lldb/Core/Log.h"
# include "lldb/Core/Module.h"
# include "lldb/Core/StreamString.h"
# include "lldb/Core/ValueObjectCast.h"
# include "lldb/Core/ValueObjectChild.h"
# include "lldb/Core/ValueObjectConstResult.h"
# include "lldb/Core/ValueObjectDynamicValue.h"
# include "lldb/Core/ValueObjectList.h"
# include "lldb/Core/ValueObjectMemory.h"
# include "lldb/Core/ValueObjectSyntheticFilter.h"
# include "lldb/DataFormatters/DataVisualization.h"
2015-02-06 16:38:51 -05:00
# include "lldb/DataFormatters/StringPrinter.h"
2013-11-06 11:48:53 -05:00
# include "lldb/DataFormatters/ValueObjectPrinter.h"
2013-08-23 13:46:38 -04:00
2015-02-06 16:38:51 -05:00
# include "lldb/Expression/ClangExpressionVariable.h"
# include "lldb/Expression/ClangPersistentVariables.h"
2013-08-23 13:46:38 -04:00
# include "lldb/Host/Endian.h"
# include "lldb/Interpreter/CommandInterpreter.h"
# include "lldb/Interpreter/ScriptInterpreterPython.h"
# include "lldb/Symbol/ClangASTType.h"
# include "lldb/Symbol/ClangASTContext.h"
2015-02-06 16:38:51 -05:00
# include "lldb/Symbol/CompileUnit.h"
2013-08-23 13:46:38 -04:00
# include "lldb/Symbol/Type.h"
# include "lldb/Target/ExecutionContext.h"
# include "lldb/Target/LanguageRuntime.h"
# include "lldb/Target/ObjCLanguageRuntime.h"
# include "lldb/Target/Process.h"
# include "lldb/Target/RegisterContext.h"
2014-02-18 11:23:10 -05:00
# include "lldb/Target/SectionLoadList.h"
2013-08-23 13:46:38 -04:00
# include "lldb/Target/Target.h"
# include "lldb/Target/Thread.h"
using namespace lldb ;
using namespace lldb_private ;
using namespace lldb_utility ;
static user_id_t g_value_obj_uid = 0 ;
//----------------------------------------------------------------------
// ValueObject constructor
//----------------------------------------------------------------------
ValueObject : : ValueObject ( ValueObject & parent ) :
UserID ( + + g_value_obj_uid ) , // Unique identifier for every value object
m_parent ( & parent ) ,
m_root ( NULL ) ,
m_update_point ( parent . GetUpdatePoint ( ) ) ,
m_name ( ) ,
m_data ( ) ,
m_value ( ) ,
m_error ( ) ,
m_value_str ( ) ,
m_old_value_str ( ) ,
m_location_str ( ) ,
m_summary_str ( ) ,
m_object_desc_str ( ) ,
2015-02-06 16:38:51 -05:00
m_validation_result ( ) ,
2013-08-23 13:46:38 -04:00
m_manager ( parent . GetManager ( ) ) ,
m_children ( ) ,
m_synthetic_children ( ) ,
m_dynamic_value ( NULL ) ,
m_synthetic_value ( NULL ) ,
m_deref_valobj ( NULL ) ,
m_format ( eFormatDefault ) ,
m_last_format ( eFormatDefault ) ,
m_last_format_mgr_revision ( 0 ) ,
m_type_summary_sp ( ) ,
m_type_format_sp ( ) ,
m_synthetic_children_sp ( ) ,
2015-02-06 16:38:51 -05:00
m_type_validator_sp ( ) ,
2013-08-23 13:46:38 -04:00
m_user_id_of_forced_summary ( ) ,
m_address_type_of_ptr_or_ref_children ( eAddressTypeInvalid ) ,
2015-02-06 16:38:51 -05:00
m_value_checksum ( ) ,
2015-02-08 20:44:09 -05:00
m_preferred_display_language ( lldb : : eLanguageTypeUnknown ) ,
2013-08-23 13:46:38 -04:00
m_value_is_valid ( false ) ,
m_value_did_change ( false ) ,
m_children_count_valid ( false ) ,
m_old_value_valid ( false ) ,
m_is_deref_of_parent ( false ) ,
m_is_array_item_for_pointer ( false ) ,
m_is_bitfield_for_scalar ( false ) ,
m_is_child_at_offset ( false ) ,
m_is_getting_summary ( false ) ,
2015-02-06 16:38:51 -05:00
m_did_calculate_complete_objc_class_type ( false ) ,
m_is_synthetic_children_generated ( parent . m_is_synthetic_children_generated )
2013-08-23 13:46:38 -04:00
{
m_manager - > ManageObject ( this ) ;
}
//----------------------------------------------------------------------
// ValueObject constructor
//----------------------------------------------------------------------
ValueObject : : ValueObject ( ExecutionContextScope * exe_scope ,
AddressType child_ptr_or_ref_addr_type ) :
UserID ( + + g_value_obj_uid ) , // Unique identifier for every value object
m_parent ( NULL ) ,
m_root ( NULL ) ,
m_update_point ( exe_scope ) ,
m_name ( ) ,
m_data ( ) ,
m_value ( ) ,
m_error ( ) ,
m_value_str ( ) ,
m_old_value_str ( ) ,
m_location_str ( ) ,
m_summary_str ( ) ,
m_object_desc_str ( ) ,
2015-02-06 16:38:51 -05:00
m_validation_result ( ) ,
2013-08-23 13:46:38 -04:00
m_manager ( ) ,
m_children ( ) ,
m_synthetic_children ( ) ,
m_dynamic_value ( NULL ) ,
m_synthetic_value ( NULL ) ,
m_deref_valobj ( NULL ) ,
m_format ( eFormatDefault ) ,
m_last_format ( eFormatDefault ) ,
m_last_format_mgr_revision ( 0 ) ,
m_type_summary_sp ( ) ,
m_type_format_sp ( ) ,
m_synthetic_children_sp ( ) ,
2015-02-06 16:38:51 -05:00
m_type_validator_sp ( ) ,
2013-08-23 13:46:38 -04:00
m_user_id_of_forced_summary ( ) ,
m_address_type_of_ptr_or_ref_children ( child_ptr_or_ref_addr_type ) ,
2015-02-06 16:38:51 -05:00
m_value_checksum ( ) ,
2015-02-08 20:44:09 -05:00
m_preferred_display_language ( lldb : : eLanguageTypeUnknown ) ,
2013-08-23 13:46:38 -04:00
m_value_is_valid ( false ) ,
m_value_did_change ( false ) ,
m_children_count_valid ( false ) ,
m_old_value_valid ( false ) ,
m_is_deref_of_parent ( false ) ,
m_is_array_item_for_pointer ( false ) ,
m_is_bitfield_for_scalar ( false ) ,
m_is_child_at_offset ( false ) ,
m_is_getting_summary ( false ) ,
2015-02-06 16:38:51 -05:00
m_did_calculate_complete_objc_class_type ( false ) ,
m_is_synthetic_children_generated ( false )
2013-08-23 13:46:38 -04:00
{
m_manager = new ValueObjectManager ( ) ;
m_manager - > ManageObject ( this ) ;
}
//----------------------------------------------------------------------
// Destructor
//----------------------------------------------------------------------
ValueObject : : ~ ValueObject ( )
{
}
bool
ValueObject : : UpdateValueIfNeeded ( bool update_format )
{
bool did_change_formats = false ;
if ( update_format )
did_change_formats = UpdateFormatsIfNeeded ( ) ;
// If this is a constant value, then our success is predicated on whether
// we have an error or not
if ( GetIsConstant ( ) )
{
2013-11-06 11:48:53 -05:00
// if you are constant, things might still have changed behind your back
// (e.g. you are a frozen object and things have changed deeper than you cared to freeze-dry yourself)
// in this case, your value has not changed, but "computed" entries might have, so you might now have
// a different summary, or a different object description. clear these so we will recompute them
2013-08-23 13:46:38 -04:00
if ( update_format & & ! did_change_formats )
2013-11-06 11:48:53 -05:00
ClearUserVisibleData ( eClearUserVisibleDataItemsSummary | eClearUserVisibleDataItemsDescription ) ;
2013-08-23 13:46:38 -04:00
return m_error . Success ( ) ;
}
2015-02-06 16:38:51 -05:00
bool first_update = IsChecksumEmpty ( ) ;
2013-08-23 13:46:38 -04:00
if ( m_update_point . NeedsUpdating ( ) )
{
m_update_point . SetUpdated ( ) ;
// Save the old value using swap to avoid a string copy which
// also will clear our m_value_str
if ( m_value_str . empty ( ) )
{
m_old_value_valid = false ;
}
else
{
m_old_value_valid = true ;
m_old_value_str . swap ( m_value_str ) ;
ClearUserVisibleData ( eClearUserVisibleDataItemsValue ) ;
}
ClearUserVisibleData ( ) ;
if ( IsInScope ( ) )
{
const bool value_was_valid = GetValueIsValid ( ) ;
SetValueDidChange ( false ) ;
m_error . Clear ( ) ;
// Call the pure virtual function to update the value
2015-02-06 16:38:51 -05:00
bool need_compare_checksums = false ;
llvm : : SmallVector < uint8_t , 16 > old_checksum ;
if ( ! first_update & & CanProvideValue ( ) )
{
need_compare_checksums = true ;
old_checksum . resize ( m_value_checksum . size ( ) ) ;
std : : copy ( m_value_checksum . begin ( ) , m_value_checksum . end ( ) , old_checksum . begin ( ) ) ;
}
2013-08-23 13:46:38 -04:00
bool success = UpdateValue ( ) ;
SetValueIsValid ( success ) ;
2015-02-06 16:38:51 -05:00
if ( success )
{
const uint64_t max_checksum_size = 128 ;
m_data . Checksum ( m_value_checksum ,
max_checksum_size ) ;
}
else
{
need_compare_checksums = false ;
m_value_checksum . clear ( ) ;
}
assert ( ! need_compare_checksums | | ( ! old_checksum . empty ( ) & & ! m_value_checksum . empty ( ) ) ) ;
2013-08-23 13:46:38 -04:00
if ( first_update )
SetValueDidChange ( false ) ;
else if ( ! m_value_did_change & & success = = false )
{
// The value wasn't gotten successfully, so we mark this
// as changed if the value used to be valid and now isn't
SetValueDidChange ( value_was_valid ) ;
}
2015-02-06 16:38:51 -05:00
else if ( need_compare_checksums )
{
SetValueDidChange ( memcmp ( & old_checksum [ 0 ] , & m_value_checksum [ 0 ] , m_value_checksum . size ( ) ) ) ;
}
2013-08-23 13:46:38 -04:00
}
else
{
m_error . SetErrorString ( " out of scope " ) ;
}
}
return m_error . Success ( ) ;
}
bool
ValueObject : : UpdateFormatsIfNeeded ( )
{
Log * log ( lldb_private : : GetLogIfAllCategoriesSet ( LIBLLDB_LOG_TYPES ) ) ;
if ( log )
log - > Printf ( " [%s %p] checking for FormatManager revisions. ValueObject rev: %d - Global rev: %d " ,
2014-11-25 16:00:58 -05:00
GetName ( ) . GetCString ( ) , static_cast < void * > ( this ) ,
m_last_format_mgr_revision ,
DataVisualization : : GetCurrentRevision ( ) ) ;
2013-08-23 13:46:38 -04:00
bool any_change = false ;
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
if ( ( m_last_format_mgr_revision ! = DataVisualization : : GetCurrentRevision ( ) ) )
{
2014-11-25 16:00:58 -05:00
m_last_format_mgr_revision = DataVisualization : : GetCurrentRevision ( ) ;
any_change = true ;
2013-11-06 11:48:53 -05:00
SetValueFormat ( DataVisualization : : GetFormat ( * this , eNoDynamicValues ) ) ;
2013-08-23 13:46:38 -04:00
SetSummaryFormat ( DataVisualization : : GetSummaryFormat ( * this , GetDynamicValueType ( ) ) ) ;
# ifndef LLDB_DISABLE_PYTHON
SetSyntheticChildren ( DataVisualization : : GetSyntheticChildren ( * this , GetDynamicValueType ( ) ) ) ;
# endif
2015-02-06 16:38:51 -05:00
SetValidator ( DataVisualization : : GetValidator ( * this , GetDynamicValueType ( ) ) ) ;
2013-08-23 13:46:38 -04:00
}
2014-11-25 16:00:58 -05:00
2013-08-23 13:46:38 -04:00
return any_change ;
}
void
ValueObject : : SetNeedsUpdate ( )
{
m_update_point . SetNeedsUpdate ( ) ;
// We have to clear the value string here so ConstResult children will notice if their values are
// changed by hand (i.e. with SetValueAsCString).
ClearUserVisibleData ( eClearUserVisibleDataItemsValue ) ;
}
void
ValueObject : : ClearDynamicTypeInformation ( )
{
2013-11-06 11:48:53 -05:00
m_children_count_valid = false ;
2013-08-23 13:46:38 -04:00
m_did_calculate_complete_objc_class_type = false ;
m_last_format_mgr_revision = 0 ;
m_override_type = ClangASTType ( ) ;
SetValueFormat ( lldb : : TypeFormatImplSP ( ) ) ;
SetSummaryFormat ( lldb : : TypeSummaryImplSP ( ) ) ;
SetSyntheticChildren ( lldb : : SyntheticChildrenSP ( ) ) ;
}
ClangASTType
ValueObject : : MaybeCalculateCompleteType ( )
{
ClangASTType clang_type ( GetClangTypeImpl ( ) ) ;
if ( m_did_calculate_complete_objc_class_type )
{
if ( m_override_type . IsValid ( ) )
return m_override_type ;
else
return clang_type ;
}
ClangASTType class_type ;
bool is_pointer_type = false ;
if ( clang_type . IsObjCObjectPointerType ( & class_type ) )
{
is_pointer_type = true ;
}
else if ( clang_type . IsObjCObjectOrInterfaceType ( ) )
{
class_type = clang_type ;
}
else
{
return clang_type ;
}
m_did_calculate_complete_objc_class_type = true ;
if ( class_type )
{
ConstString class_name ( class_type . GetConstTypeName ( ) ) ;
if ( class_name )
{
ProcessSP process_sp ( GetUpdatePoint ( ) . GetExecutionContextRef ( ) . GetProcessSP ( ) ) ;
if ( process_sp )
{
ObjCLanguageRuntime * objc_language_runtime ( process_sp - > GetObjCLanguageRuntime ( ) ) ;
if ( objc_language_runtime )
{
TypeSP complete_objc_class_type_sp = objc_language_runtime - > LookupInCompleteClassCache ( class_name ) ;
if ( complete_objc_class_type_sp )
{
ClangASTType complete_class ( complete_objc_class_type_sp - > GetClangFullType ( ) ) ;
if ( complete_class . GetCompleteType ( ) )
{
if ( is_pointer_type )
{
m_override_type = complete_class . GetPointerType ( ) ;
}
else
{
m_override_type = complete_class ;
}
if ( m_override_type . IsValid ( ) )
return m_override_type ;
}
}
}
}
}
}
return clang_type ;
}
ClangASTType
ValueObject : : GetClangType ( )
{
return MaybeCalculateCompleteType ( ) ;
}
2013-11-06 11:48:53 -05:00
TypeImpl
ValueObject : : GetTypeImpl ( )
{
return TypeImpl ( GetClangType ( ) ) ;
}
2013-08-23 13:46:38 -04:00
DataExtractor &
ValueObject : : GetDataExtractor ( )
{
UpdateValueIfNeeded ( false ) ;
return m_data ;
}
const Error &
ValueObject : : GetError ( )
{
UpdateValueIfNeeded ( false ) ;
return m_error ;
}
const ConstString &
ValueObject : : GetName ( ) const
{
return m_name ;
}
const char *
ValueObject : : GetLocationAsCString ( )
{
return GetLocationAsCStringImpl ( m_value ,
m_data ) ;
}
const char *
ValueObject : : GetLocationAsCStringImpl ( const Value & value ,
const DataExtractor & data )
{
if ( UpdateValueIfNeeded ( false ) )
{
if ( m_location_str . empty ( ) )
{
StreamString sstr ;
Value : : ValueType value_type = value . GetValueType ( ) ;
switch ( value_type )
{
case Value : : eValueTypeScalar :
case Value : : eValueTypeVector :
if ( value . GetContextType ( ) = = Value : : eContextTypeRegisterInfo )
{
RegisterInfo * reg_info = value . GetRegisterInfo ( ) ;
if ( reg_info )
{
if ( reg_info - > name )
m_location_str = reg_info - > name ;
else if ( reg_info - > alt_name )
m_location_str = reg_info - > alt_name ;
if ( m_location_str . empty ( ) )
m_location_str = ( reg_info - > encoding = = lldb : : eEncodingVector ) ? " vector " : " scalar " ;
}
}
if ( m_location_str . empty ( ) )
m_location_str = ( value_type = = Value : : eValueTypeVector ) ? " vector " : " scalar " ;
break ;
case Value : : eValueTypeLoadAddress :
case Value : : eValueTypeFileAddress :
case Value : : eValueTypeHostAddress :
{
uint32_t addr_nibble_size = data . GetAddressByteSize ( ) * 2 ;
sstr . Printf ( " 0x%*.*llx " , addr_nibble_size , addr_nibble_size , value . GetScalar ( ) . ULongLong ( LLDB_INVALID_ADDRESS ) ) ;
m_location_str . swap ( sstr . GetString ( ) ) ;
}
break ;
}
}
}
return m_location_str . c_str ( ) ;
}
Value &
ValueObject : : GetValue ( )
{
return m_value ;
}
const Value &
ValueObject : : GetValue ( ) const
{
return m_value ;
}
bool
ValueObject : : ResolveValue ( Scalar & scalar )
{
if ( UpdateValueIfNeeded ( false ) ) // make sure that you are up to date before returning anything
{
ExecutionContext exe_ctx ( GetExecutionContextRef ( ) ) ;
Value tmp_value ( m_value ) ;
scalar = tmp_value . ResolveValue ( & exe_ctx ) ;
if ( scalar . IsValid ( ) )
{
const uint32_t bitfield_bit_size = GetBitfieldBitSize ( ) ;
if ( bitfield_bit_size )
return scalar . ExtractBitfield ( bitfield_bit_size , GetBitfieldBitOffset ( ) ) ;
return true ;
}
}
return false ;
}
bool
ValueObject : : GetValueIsValid ( ) const
{
return m_value_is_valid ;
}
void
ValueObject : : SetValueIsValid ( bool b )
{
m_value_is_valid = b ;
}
bool
ValueObject : : GetValueDidChange ( )
{
return m_value_did_change ;
}
void
ValueObject : : SetValueDidChange ( bool value_changed )
{
m_value_did_change = value_changed ;
}
ValueObjectSP
ValueObject : : GetChildAtIndex ( size_t idx , bool can_create )
{
ValueObjectSP child_sp ;
// We may need to update our value if we are dynamic
if ( IsPossibleDynamicType ( ) )
UpdateValueIfNeeded ( false ) ;
if ( idx < GetNumChildren ( ) )
{
// Check if we have already made the child value object?
if ( can_create & & ! m_children . HasChildAtIndex ( idx ) )
{
// No we haven't created the child at this index, so lets have our
// subclass do it and cache the result for quick future access.
m_children . SetChildAtIndex ( idx , CreateChildAtIndex ( idx , false , 0 ) ) ;
}
ValueObject * child = m_children . GetChildAtIndex ( idx ) ;
if ( child ! = NULL )
return child - > GetSP ( ) ;
}
return child_sp ;
}
ValueObjectSP
ValueObject : : GetChildAtIndexPath ( const std : : initializer_list < size_t > & idxs ,
size_t * index_of_error )
{
if ( idxs . size ( ) = = 0 )
return GetSP ( ) ;
ValueObjectSP root ( GetSP ( ) ) ;
for ( size_t idx : idxs )
{
root = root - > GetChildAtIndex ( idx , true ) ;
if ( ! root )
{
if ( index_of_error )
* index_of_error = idx ;
return root ;
}
}
return root ;
}
ValueObjectSP
ValueObject : : GetChildAtIndexPath ( const std : : initializer_list < std : : pair < size_t , bool > > & idxs ,
size_t * index_of_error )
{
if ( idxs . size ( ) = = 0 )
return GetSP ( ) ;
ValueObjectSP root ( GetSP ( ) ) ;
for ( std : : pair < size_t , bool > idx : idxs )
{
root = root - > GetChildAtIndex ( idx . first , idx . second ) ;
if ( ! root )
{
if ( index_of_error )
* index_of_error = idx . first ;
return root ;
}
}
return root ;
}
lldb : : ValueObjectSP
ValueObject : : GetChildAtIndexPath ( const std : : vector < size_t > & idxs ,
size_t * index_of_error )
{
if ( idxs . size ( ) = = 0 )
return GetSP ( ) ;
ValueObjectSP root ( GetSP ( ) ) ;
for ( size_t idx : idxs )
{
root = root - > GetChildAtIndex ( idx , true ) ;
if ( ! root )
{
if ( index_of_error )
* index_of_error = idx ;
return root ;
}
}
return root ;
}
lldb : : ValueObjectSP
ValueObject : : GetChildAtIndexPath ( const std : : vector < std : : pair < size_t , bool > > & idxs ,
size_t * index_of_error )
{
if ( idxs . size ( ) = = 0 )
return GetSP ( ) ;
ValueObjectSP root ( GetSP ( ) ) ;
for ( std : : pair < size_t , bool > idx : idxs )
{
root = root - > GetChildAtIndex ( idx . first , idx . second ) ;
if ( ! root )
{
if ( index_of_error )
* index_of_error = idx . first ;
return root ;
}
}
return root ;
}
2013-11-06 11:48:53 -05:00
lldb : : ValueObjectSP
ValueObject : : GetChildAtNamePath ( const std : : initializer_list < ConstString > & names ,
ConstString * name_of_error )
{
if ( names . size ( ) = = 0 )
return GetSP ( ) ;
ValueObjectSP root ( GetSP ( ) ) ;
for ( ConstString name : names )
{
root = root - > GetChildMemberWithName ( name , true ) ;
if ( ! root )
{
if ( name_of_error )
* name_of_error = name ;
return root ;
}
}
return root ;
}
lldb : : ValueObjectSP
ValueObject : : GetChildAtNamePath ( const std : : vector < ConstString > & names ,
ConstString * name_of_error )
{
if ( names . size ( ) = = 0 )
return GetSP ( ) ;
ValueObjectSP root ( GetSP ( ) ) ;
for ( ConstString name : names )
{
root = root - > GetChildMemberWithName ( name , true ) ;
if ( ! root )
{
if ( name_of_error )
* name_of_error = name ;
return root ;
}
}
return root ;
}
lldb : : ValueObjectSP
ValueObject : : GetChildAtNamePath ( const std : : initializer_list < std : : pair < ConstString , bool > > & names ,
ConstString * name_of_error )
{
if ( names . size ( ) = = 0 )
return GetSP ( ) ;
ValueObjectSP root ( GetSP ( ) ) ;
for ( std : : pair < ConstString , bool > name : names )
{
root = root - > GetChildMemberWithName ( name . first , name . second ) ;
if ( ! root )
{
if ( name_of_error )
* name_of_error = name . first ;
return root ;
}
}
return root ;
}
lldb : : ValueObjectSP
ValueObject : : GetChildAtNamePath ( const std : : vector < std : : pair < ConstString , bool > > & names ,
ConstString * name_of_error )
{
if ( names . size ( ) = = 0 )
return GetSP ( ) ;
ValueObjectSP root ( GetSP ( ) ) ;
for ( std : : pair < ConstString , bool > name : names )
{
root = root - > GetChildMemberWithName ( name . first , name . second ) ;
if ( ! root )
{
if ( name_of_error )
* name_of_error = name . first ;
return root ;
}
}
return root ;
}
2013-08-23 13:46:38 -04:00
size_t
ValueObject : : GetIndexOfChildWithName ( const ConstString & name )
{
bool omit_empty_base_classes = true ;
return GetClangType ( ) . GetIndexOfChildWithName ( name . GetCString ( ) , omit_empty_base_classes ) ;
}
ValueObjectSP
ValueObject : : GetChildMemberWithName ( const ConstString & name , bool can_create )
{
// when getting a child by name, it could be buried inside some base
// classes (which really aren't part of the expression path), so we
// need a vector of indexes that can get us down to the correct child
ValueObjectSP child_sp ;
// We may need to update our value if we are dynamic
if ( IsPossibleDynamicType ( ) )
UpdateValueIfNeeded ( false ) ;
std : : vector < uint32_t > child_indexes ;
bool omit_empty_base_classes = true ;
const size_t num_child_indexes = GetClangType ( ) . GetIndexOfChildMemberWithName ( name . GetCString ( ) ,
omit_empty_base_classes ,
child_indexes ) ;
if ( num_child_indexes > 0 )
{
std : : vector < uint32_t > : : const_iterator pos = child_indexes . begin ( ) ;
std : : vector < uint32_t > : : const_iterator end = child_indexes . end ( ) ;
child_sp = GetChildAtIndex ( * pos , can_create ) ;
for ( + + pos ; pos ! = end ; + + pos )
{
if ( child_sp )
{
ValueObjectSP new_child_sp ( child_sp - > GetChildAtIndex ( * pos , can_create ) ) ;
child_sp = new_child_sp ;
}
else
{
child_sp . reset ( ) ;
}
}
}
return child_sp ;
}
size_t
ValueObject : : GetNumChildren ( )
{
UpdateValueIfNeeded ( ) ;
if ( ! m_children_count_valid )
{
SetNumChildren ( CalculateNumChildren ( ) ) ;
}
return m_children . GetChildrenCount ( ) ;
}
bool
ValueObject : : MightHaveChildren ( )
{
bool has_children = false ;
const uint32_t type_info = GetTypeInfo ( ) ;
if ( type_info )
{
2015-02-06 16:38:51 -05:00
if ( type_info & ( eTypeHasChildren |
eTypeIsPointer |
eTypeIsReference ) )
2013-08-23 13:46:38 -04:00
has_children = true ;
}
else
{
has_children = GetNumChildren ( ) > 0 ;
}
return has_children ;
}
// Should only be called by ValueObject::GetNumChildren()
void
ValueObject : : SetNumChildren ( size_t num_children )
{
m_children_count_valid = true ;
m_children . SetChildrenCount ( num_children ) ;
}
void
ValueObject : : SetName ( const ConstString & name )
{
m_name = name ;
}
ValueObject *
ValueObject : : CreateChildAtIndex ( size_t idx , bool synthetic_array_member , int32_t synthetic_index )
{
ValueObject * valobj = NULL ;
bool omit_empty_base_classes = true ;
bool ignore_array_bounds = synthetic_array_member ;
std : : string child_name_str ;
uint32_t child_byte_size = 0 ;
int32_t child_byte_offset = 0 ;
uint32_t child_bitfield_bit_size = 0 ;
uint32_t child_bitfield_bit_offset = 0 ;
bool child_is_base_class = false ;
bool child_is_deref_of_parent = false ;
const bool transparent_pointers = synthetic_array_member = = false ;
ClangASTType child_clang_type ;
ExecutionContext exe_ctx ( GetExecutionContextRef ( ) ) ;
child_clang_type = GetClangType ( ) . GetChildClangTypeAtIndex ( & exe_ctx ,
idx ,
transparent_pointers ,
omit_empty_base_classes ,
ignore_array_bounds ,
child_name_str ,
child_byte_size ,
child_byte_offset ,
child_bitfield_bit_size ,
child_bitfield_bit_offset ,
child_is_base_class ,
2014-11-25 16:00:58 -05:00
child_is_deref_of_parent ,
this ) ;
2013-08-23 13:46:38 -04:00
if ( child_clang_type )
{
if ( synthetic_index )
child_byte_offset + = child_byte_size * synthetic_index ;
ConstString child_name ;
if ( ! child_name_str . empty ( ) )
child_name . SetCString ( child_name_str . c_str ( ) ) ;
valobj = new ValueObjectChild ( * this ,
child_clang_type ,
child_name ,
child_byte_size ,
child_byte_offset ,
child_bitfield_bit_size ,
child_bitfield_bit_offset ,
child_is_base_class ,
child_is_deref_of_parent ,
eAddressTypeInvalid ) ;
//if (valobj)
// valobj->SetAddressTypeOfChildren(eAddressTypeInvalid);
}
return valobj ;
}
bool
ValueObject : : GetSummaryAsCString ( TypeSummaryImpl * summary_ptr ,
std : : string & destination )
2015-02-06 16:38:51 -05:00
{
return GetSummaryAsCString ( summary_ptr , destination , TypeSummaryOptions ( ) ) ;
}
bool
ValueObject : : GetSummaryAsCString ( TypeSummaryImpl * summary_ptr ,
std : : string & destination ,
const TypeSummaryOptions & options )
2013-08-23 13:46:38 -04:00
{
destination . clear ( ) ;
// ideally we would like to bail out if passing NULL, but if we do so
// we end up not providing the summary for function pointers anymore
if ( /*summary_ptr == NULL ||*/ m_is_getting_summary )
return false ;
m_is_getting_summary = true ;
// this is a hot path in code and we prefer to avoid setting this string all too often also clearing out other
// information that we might care to see in a crash log. might be useful in very specific situations though.
/*Host::SetCrashDescriptionWithFormat("Trying to fetch a summary for %s %s. Summary provider's description is %s",
GetTypeName ( ) . GetCString ( ) ,
GetName ( ) . GetCString ( ) ,
summary_ptr - > GetDescription ( ) . c_str ( ) ) ; */
2015-02-06 16:38:51 -05:00
if ( UpdateValueIfNeeded ( false ) & & summary_ptr )
2013-08-23 13:46:38 -04:00
{
2015-02-06 16:38:51 -05:00
if ( HasSyntheticValue ( ) )
m_synthetic_value - > UpdateValueIfNeeded ( ) ; // the summary might depend on the synthetic children being up-to-date (e.g. ${svar%#})
summary_ptr - > FormatObject ( this , destination , options ) ;
2013-08-23 13:46:38 -04:00
}
m_is_getting_summary = false ;
return ! destination . empty ( ) ;
}
const char *
ValueObject : : GetSummaryAsCString ( )
{
if ( UpdateValueIfNeeded ( true ) & & m_summary_str . empty ( ) )
{
GetSummaryAsCString ( GetSummaryFormat ( ) . get ( ) ,
2015-02-06 16:38:51 -05:00
m_summary_str ,
TypeSummaryOptions ( ) ) ;
2013-08-23 13:46:38 -04:00
}
if ( m_summary_str . empty ( ) )
return NULL ;
return m_summary_str . c_str ( ) ;
}
2015-02-06 16:38:51 -05:00
bool
ValueObject : : GetSummaryAsCString ( std : : string & destination ,
const TypeSummaryOptions & options )
{
return GetSummaryAsCString ( GetSummaryFormat ( ) . get ( ) ,
destination ,
options ) ;
}
2013-08-23 13:46:38 -04:00
bool
ValueObject : : IsCStringContainer ( bool check_pointer )
{
ClangASTType pointee_or_element_clang_type ;
const Flags type_flags ( GetTypeInfo ( & pointee_or_element_clang_type ) ) ;
2015-02-06 16:38:51 -05:00
bool is_char_arr_ptr ( type_flags . AnySet ( eTypeIsArray | eTypeIsPointer ) & &
2013-08-23 13:46:38 -04:00
pointee_or_element_clang_type . IsCharType ( ) ) ;
if ( ! is_char_arr_ptr )
return false ;
if ( ! check_pointer )
return true ;
2015-02-06 16:38:51 -05:00
if ( type_flags . Test ( eTypeIsArray ) )
2013-08-23 13:46:38 -04:00
return true ;
addr_t cstr_address = LLDB_INVALID_ADDRESS ;
AddressType cstr_address_type = eAddressTypeInvalid ;
cstr_address = GetAddressOf ( true , & cstr_address_type ) ;
return ( cstr_address ! = LLDB_INVALID_ADDRESS ) ;
}
size_t
ValueObject : : GetPointeeData ( DataExtractor & data ,
uint32_t item_idx ,
uint32_t item_count )
{
ClangASTType pointee_or_element_clang_type ;
const uint32_t type_info = GetTypeInfo ( & pointee_or_element_clang_type ) ;
2015-02-06 16:38:51 -05:00
const bool is_pointer_type = type_info & eTypeIsPointer ;
const bool is_array_type = type_info & eTypeIsArray ;
2013-08-23 13:46:38 -04:00
if ( ! ( is_pointer_type | | is_array_type ) )
return 0 ;
if ( item_count = = 0 )
return 0 ;
2015-02-08 20:44:09 -05:00
ExecutionContext exe_ctx ( GetExecutionContextRef ( ) ) ;
const uint64_t item_type_size = pointee_or_element_clang_type . GetByteSize ( & exe_ctx ) ;
2013-08-23 13:46:38 -04:00
const uint64_t bytes = item_count * item_type_size ;
const uint64_t offset = item_idx * item_type_size ;
if ( item_idx = = 0 & & item_count = = 1 ) // simply a deref
{
if ( is_pointer_type )
{
Error error ;
ValueObjectSP pointee_sp = Dereference ( error ) ;
if ( error . Fail ( ) | | pointee_sp . get ( ) = = NULL )
return 0 ;
2014-11-25 16:00:58 -05:00
return pointee_sp - > GetData ( data , error ) ;
2013-08-23 13:46:38 -04:00
}
else
{
ValueObjectSP child_sp = GetChildAtIndex ( 0 , true ) ;
if ( child_sp . get ( ) = = NULL )
return 0 ;
2014-11-25 16:00:58 -05:00
Error error ;
return child_sp - > GetData ( data , error ) ;
2013-08-23 13:46:38 -04:00
}
return true ;
}
else /* (items > 1) */
{
Error error ;
lldb_private : : DataBufferHeap * heap_buf_ptr = NULL ;
lldb : : DataBufferSP data_sp ( heap_buf_ptr = new lldb_private : : DataBufferHeap ( ) ) ;
AddressType addr_type ;
lldb : : addr_t addr = is_pointer_type ? GetPointerValue ( & addr_type ) : GetAddressOf ( true , & addr_type ) ;
switch ( addr_type )
{
case eAddressTypeFile :
{
ModuleSP module_sp ( GetModule ( ) ) ;
if ( module_sp )
{
addr = addr + offset ;
Address so_addr ;
module_sp - > ResolveFileAddress ( addr , so_addr ) ;
ExecutionContext exe_ctx ( GetExecutionContextRef ( ) ) ;
Target * target = exe_ctx . GetTargetPtr ( ) ;
if ( target )
{
heap_buf_ptr - > SetByteSize ( bytes ) ;
size_t bytes_read = target - > ReadMemory ( so_addr , false , heap_buf_ptr - > GetBytes ( ) , bytes , error ) ;
if ( error . Success ( ) )
{
data . SetData ( data_sp ) ;
return bytes_read ;
}
}
}
}
break ;
case eAddressTypeLoad :
{
ExecutionContext exe_ctx ( GetExecutionContextRef ( ) ) ;
Process * process = exe_ctx . GetProcessPtr ( ) ;
if ( process )
{
heap_buf_ptr - > SetByteSize ( bytes ) ;
size_t bytes_read = process - > ReadMemory ( addr + offset , heap_buf_ptr - > GetBytes ( ) , bytes , error ) ;
2013-11-06 11:48:53 -05:00
if ( error . Success ( ) | | bytes_read > 0 )
2013-08-23 13:46:38 -04:00
{
data . SetData ( data_sp ) ;
return bytes_read ;
}
}
}
break ;
case eAddressTypeHost :
{
2015-02-08 20:44:09 -05:00
const uint64_t max_bytes = GetClangType ( ) . GetByteSize ( & exe_ctx ) ;
2013-08-23 13:46:38 -04:00
if ( max_bytes > offset )
{
size_t bytes_read = std : : min < uint64_t > ( max_bytes - offset , bytes ) ;
heap_buf_ptr - > CopyData ( ( uint8_t * ) ( addr + offset ) , bytes_read ) ;
data . SetData ( data_sp ) ;
return bytes_read ;
}
}
break ;
case eAddressTypeInvalid :
break ;
}
}
return 0 ;
}
uint64_t
2014-11-25 16:00:58 -05:00
ValueObject : : GetData ( DataExtractor & data , Error & error )
2013-08-23 13:46:38 -04:00
{
UpdateValueIfNeeded ( false ) ;
ExecutionContext exe_ctx ( GetExecutionContextRef ( ) ) ;
2014-11-25 16:00:58 -05:00
error = m_value . GetValueAsData ( & exe_ctx , data , 0 , GetModule ( ) . get ( ) ) ;
2013-08-23 13:46:38 -04:00
if ( error . Fail ( ) )
{
if ( m_data . GetByteSize ( ) )
{
data = m_data ;
return data . GetByteSize ( ) ;
}
else
{
return 0 ;
}
}
data . SetAddressByteSize ( m_data . GetAddressByteSize ( ) ) ;
data . SetByteOrder ( m_data . GetByteOrder ( ) ) ;
return data . GetByteSize ( ) ;
}
bool
ValueObject : : SetData ( DataExtractor & data , Error & error )
{
error . Clear ( ) ;
// Make sure our value is up to date first so that our location and location
// type is valid.
if ( ! UpdateValueIfNeeded ( false ) )
{
error . SetErrorString ( " unable to read value " ) ;
return false ;
}
uint64_t count = 0 ;
const Encoding encoding = GetClangType ( ) . GetEncoding ( count ) ;
const size_t byte_size = GetByteSize ( ) ;
Value : : ValueType value_type = m_value . GetValueType ( ) ;
switch ( value_type )
{
case Value : : eValueTypeScalar :
{
Error set_error = m_value . GetScalar ( ) . SetValueFromData ( data , encoding , byte_size ) ;
if ( ! set_error . Success ( ) )
{
error . SetErrorStringWithFormat ( " unable to set scalar value: %s " , set_error . AsCString ( ) ) ;
return false ;
}
}
break ;
case Value : : eValueTypeLoadAddress :
{
// If it is a load address, then the scalar value is the storage location
// of the data, and we have to shove this value down to that load location.
ExecutionContext exe_ctx ( GetExecutionContextRef ( ) ) ;
Process * process = exe_ctx . GetProcessPtr ( ) ;
if ( process )
{
addr_t target_addr = m_value . GetScalar ( ) . ULongLong ( LLDB_INVALID_ADDRESS ) ;
size_t bytes_written = process - > WriteMemory ( target_addr ,
data . GetDataStart ( ) ,
byte_size ,
error ) ;
if ( ! error . Success ( ) )
return false ;
if ( bytes_written ! = byte_size )
{
error . SetErrorString ( " unable to write value to memory " ) ;
return false ;
}
}
}
break ;
case Value : : eValueTypeHostAddress :
{
// If it is a host address, then we stuff the scalar as a DataBuffer into the Value's data.
DataBufferSP buffer_sp ( new DataBufferHeap ( byte_size , 0 ) ) ;
m_data . SetData ( buffer_sp , 0 ) ;
data . CopyByteOrderedData ( 0 ,
byte_size ,
const_cast < uint8_t * > ( m_data . GetDataStart ( ) ) ,
byte_size ,
m_data . GetByteOrder ( ) ) ;
m_value . GetScalar ( ) = ( uintptr_t ) m_data . GetDataStart ( ) ;
}
break ;
case Value : : eValueTypeFileAddress :
case Value : : eValueTypeVector :
break ;
}
// If we have reached this point, then we have successfully changed the value.
SetNeedsUpdate ( ) ;
return true ;
}
// will compute strlen(str), but without consuming more than
// maxlen bytes out of str (this serves the purpose of reading
// chunks of a string without having to worry about
// missing NULL terminators in the chunk)
// of course, if strlen(str) > maxlen, the function will return
// maxlen_value (which should be != maxlen, because that allows you
// to know whether strlen(str) == maxlen or strlen(str) > maxlen)
static uint32_t
strlen_or_inf ( const char * str ,
uint32_t maxlen ,
uint32_t maxlen_value )
{
uint32_t len = 0 ;
if ( str )
{
while ( * str )
{
len + + ; str + + ;
if ( len > = maxlen )
return maxlen_value ;
}
}
return len ;
}
2015-02-06 16:38:51 -05:00
static bool
CopyStringDataToBufferSP ( const StreamString & source ,
lldb : : DataBufferSP & destination )
{
destination . reset ( new DataBufferHeap ( source . GetSize ( ) + 1 , 0 ) ) ;
memcpy ( destination - > GetBytes ( ) , source . GetString ( ) . c_str ( ) , source . GetSize ( ) ) ;
return true ;
}
2013-08-23 13:46:38 -04:00
size_t
2015-02-06 16:38:51 -05:00
ValueObject : : ReadPointedString ( lldb : : DataBufferSP & buffer_sp ,
2013-08-23 13:46:38 -04:00
Error & error ,
uint32_t max_length ,
bool honor_array ,
Format item_format )
{
2015-02-06 16:38:51 -05:00
StreamString s ;
2013-08-23 13:46:38 -04:00
ExecutionContext exe_ctx ( GetExecutionContextRef ( ) ) ;
Target * target = exe_ctx . GetTargetPtr ( ) ;
2015-02-06 16:38:51 -05:00
2013-08-23 13:46:38 -04:00
if ( ! target )
{
s < < " <no target to read from> " ;
error . SetErrorString ( " no target to read from " ) ;
2015-02-06 16:38:51 -05:00
CopyStringDataToBufferSP ( s , buffer_sp ) ;
2013-08-23 13:46:38 -04:00
return 0 ;
}
if ( max_length = = 0 )
max_length = target - > GetMaximumSizeOfStringSummary ( ) ;
size_t bytes_read = 0 ;
size_t total_bytes_read = 0 ;
ClangASTType clang_type = GetClangType ( ) ;
ClangASTType elem_or_pointee_clang_type ;
const Flags type_flags ( GetTypeInfo ( & elem_or_pointee_clang_type ) ) ;
2015-02-06 16:38:51 -05:00
if ( type_flags . AnySet ( eTypeIsArray | eTypeIsPointer ) & &
2013-08-23 13:46:38 -04:00
elem_or_pointee_clang_type . IsCharType ( ) )
{
addr_t cstr_address = LLDB_INVALID_ADDRESS ;
AddressType cstr_address_type = eAddressTypeInvalid ;
size_t cstr_len = 0 ;
bool capped_data = false ;
2015-02-06 16:38:51 -05:00
if ( type_flags . Test ( eTypeIsArray ) )
2013-08-23 13:46:38 -04:00
{
// We have an array
uint64_t array_size = 0 ;
if ( clang_type . IsArrayType ( NULL , & array_size , NULL ) )
{
cstr_len = array_size ;
if ( cstr_len > max_length )
{
capped_data = true ;
cstr_len = max_length ;
}
}
cstr_address = GetAddressOf ( true , & cstr_address_type ) ;
}
else
{
// We have a pointer
cstr_address = GetPointerValue ( & cstr_address_type ) ;
}
if ( cstr_address = = 0 | | cstr_address = = LLDB_INVALID_ADDRESS )
{
s < < " <invalid address> " ;
error . SetErrorString ( " invalid address " ) ;
2015-02-06 16:38:51 -05:00
CopyStringDataToBufferSP ( s , buffer_sp ) ;
2013-08-23 13:46:38 -04:00
return 0 ;
}
2015-02-06 16:38:51 -05:00
2013-08-23 13:46:38 -04:00
Address cstr_so_addr ( cstr_address ) ;
DataExtractor data ;
if ( cstr_len > 0 & & honor_array )
{
// I am using GetPointeeData() here to abstract the fact that some ValueObjects are actually frozen pointers in the host
// but the pointed-to data lives in the debuggee, and GetPointeeData() automatically takes care of this
GetPointeeData ( data , 0 , cstr_len ) ;
2015-02-06 16:38:51 -05:00
2013-08-23 13:46:38 -04:00
if ( ( bytes_read = data . GetByteSize ( ) ) > 0 )
{
total_bytes_read = bytes_read ;
2015-02-06 16:38:51 -05:00
for ( size_t offset = 0 ; offset < bytes_read ; offset + + )
s . Printf ( " %c " , * data . PeekData ( offset , 1 ) ) ;
2013-08-23 13:46:38 -04:00
if ( capped_data )
s < < " ... " ;
}
}
else
{
cstr_len = max_length ;
const size_t k_max_buf_size = 64 ;
2015-02-06 16:38:51 -05:00
2013-08-23 13:46:38 -04:00
size_t offset = 0 ;
int cstr_len_displayed = - 1 ;
bool capped_cstr = false ;
// I am using GetPointeeData() here to abstract the fact that some ValueObjects are actually frozen pointers in the host
// but the pointed-to data lives in the debuggee, and GetPointeeData() automatically takes care of this
while ( ( bytes_read = GetPointeeData ( data , offset , k_max_buf_size ) ) > 0 )
{
total_bytes_read + = bytes_read ;
const char * cstr = data . PeekCStr ( 0 ) ;
size_t len = strlen_or_inf ( cstr , k_max_buf_size , k_max_buf_size + 1 ) ;
if ( len > k_max_buf_size )
len = k_max_buf_size ;
2015-02-06 16:38:51 -05:00
2013-08-23 13:46:38 -04:00
if ( cstr_len_displayed < 0 )
cstr_len_displayed = len ;
2015-02-06 16:38:51 -05:00
2013-08-23 13:46:38 -04:00
if ( len = = 0 )
break ;
cstr_len_displayed + = len ;
if ( len > bytes_read )
len = bytes_read ;
if ( len > cstr_len )
len = cstr_len ;
2015-02-06 16:38:51 -05:00
for ( size_t offset = 0 ; offset < bytes_read ; offset + + )
s . Printf ( " %c " , * data . PeekData ( offset , 1 ) ) ;
2013-08-23 13:46:38 -04:00
if ( len < k_max_buf_size )
break ;
if ( len > = cstr_len )
{
capped_cstr = true ;
break ;
}
2015-02-06 16:38:51 -05:00
2013-08-23 13:46:38 -04:00
cstr_len - = len ;
offset + = len ;
}
if ( cstr_len_displayed > = 0 )
{
if ( capped_cstr )
s < < " ... " ;
}
}
}
else
{
error . SetErrorString ( " not a string object " ) ;
s < < " <not a string object> " ;
}
2015-02-06 16:38:51 -05:00
CopyStringDataToBufferSP ( s , buffer_sp ) ;
2013-08-23 13:46:38 -04:00
return total_bytes_read ;
}
2015-02-06 16:38:51 -05:00
std : : pair < TypeValidatorResult , std : : string >
ValueObject : : GetValidationStatus ( )
{
if ( ! UpdateValueIfNeeded ( true ) )
return { TypeValidatorResult : : Success , " " } ; // not the validator's job to discuss update problems
if ( m_validation_result . hasValue ( ) )
return m_validation_result . getValue ( ) ;
if ( ! m_type_validator_sp )
return { TypeValidatorResult : : Success , " " } ; // no validator no failure
auto outcome = m_type_validator_sp - > FormatObject ( this ) ;
return ( m_validation_result = { outcome . m_result , outcome . m_message } ) . getValue ( ) ;
}
2013-08-23 13:46:38 -04:00
const char *
ValueObject : : GetObjectDescription ( )
{
if ( ! UpdateValueIfNeeded ( true ) )
return NULL ;
if ( ! m_object_desc_str . empty ( ) )
return m_object_desc_str . c_str ( ) ;
ExecutionContext exe_ctx ( GetExecutionContextRef ( ) ) ;
Process * process = exe_ctx . GetProcessPtr ( ) ;
if ( process = = NULL )
return NULL ;
StreamString s ;
LanguageType language = GetObjectRuntimeLanguage ( ) ;
LanguageRuntime * runtime = process - > GetLanguageRuntime ( language ) ;
if ( runtime = = NULL )
{
// Aw, hell, if the things a pointer, or even just an integer, let's try ObjC anyway...
ClangASTType clang_type = GetClangType ( ) ;
if ( clang_type )
{
bool is_signed ;
if ( clang_type . IsIntegerType ( is_signed ) | | clang_type . IsPointerType ( ) )
{
runtime = process - > GetLanguageRuntime ( eLanguageTypeObjC ) ;
}
}
}
if ( runtime & & runtime - > GetObjectDescription ( s , * this ) )
{
m_object_desc_str . append ( s . GetData ( ) ) ;
}
if ( m_object_desc_str . empty ( ) )
return NULL ;
else
return m_object_desc_str . c_str ( ) ;
}
bool
2014-02-18 11:23:10 -05:00
ValueObject : : GetValueAsCString ( const lldb_private : : TypeFormatImpl & format ,
2013-08-23 13:46:38 -04:00
std : : string & destination )
{
2014-02-18 11:23:10 -05:00
if ( UpdateValueIfNeeded ( false ) )
return format . FormatObject ( this , destination ) ;
2013-08-23 13:46:38 -04:00
else
return false ;
}
2014-02-18 11:23:10 -05:00
bool
ValueObject : : GetValueAsCString ( lldb : : Format format ,
std : : string & destination )
{
return GetValueAsCString ( TypeFormatImpl_Format ( format ) , destination ) ;
}
2013-08-23 13:46:38 -04:00
const char *
ValueObject : : GetValueAsCString ( )
{
if ( UpdateValueIfNeeded ( true ) )
{
2014-02-18 11:23:10 -05:00
lldb : : TypeFormatImplSP format_sp ;
2013-08-23 13:46:38 -04:00
lldb : : Format my_format = GetFormat ( ) ;
if ( my_format = = lldb : : eFormatDefault )
{
if ( m_type_format_sp )
2014-02-18 11:23:10 -05:00
format_sp = m_type_format_sp ;
2013-08-23 13:46:38 -04:00
else
{
if ( m_is_bitfield_for_scalar )
my_format = eFormatUnsigned ;
else
{
if ( m_value . GetContextType ( ) = = Value : : eContextTypeRegisterInfo )
{
const RegisterInfo * reg_info = m_value . GetRegisterInfo ( ) ;
if ( reg_info )
my_format = reg_info - > format ;
}
else
{
2015-02-06 16:38:51 -05:00
my_format = GetValue ( ) . GetClangType ( ) . GetFormat ( ) ;
2013-08-23 13:46:38 -04:00
}
}
}
}
if ( my_format ! = m_last_format | | m_value_str . empty ( ) )
{
m_last_format = my_format ;
2014-02-18 11:23:10 -05:00
if ( ! format_sp )
format_sp . reset ( new TypeFormatImpl_Format ( my_format ) ) ;
if ( GetValueAsCString ( * format_sp . get ( ) , m_value_str ) )
2013-08-23 13:46:38 -04:00
{
if ( ! m_value_did_change & & m_old_value_valid )
{
// The value was gotten successfully, so we consider the
// value as changed if the value string differs
SetValueDidChange ( m_old_value_str ! = m_value_str ) ;
}
}
}
}
if ( m_value_str . empty ( ) )
return NULL ;
return m_value_str . c_str ( ) ;
}
// if > 8bytes, 0 is returned. this method should mostly be used
// to read address values out of pointers
uint64_t
ValueObject : : GetValueAsUnsigned ( uint64_t fail_value , bool * success )
{
// If our byte size is zero this is an aggregate type that has children
2015-02-06 16:38:51 -05:00
if ( CanProvideValue ( ) )
2013-08-23 13:46:38 -04:00
{
Scalar scalar ;
if ( ResolveValue ( scalar ) )
{
if ( success )
* success = true ;
return scalar . ULongLong ( fail_value ) ;
}
// fallthrough, otherwise...
}
if ( success )
* success = false ;
return fail_value ;
}
2013-11-06 11:48:53 -05:00
int64_t
ValueObject : : GetValueAsSigned ( int64_t fail_value , bool * success )
{
// If our byte size is zero this is an aggregate type that has children
2015-02-06 16:38:51 -05:00
if ( CanProvideValue ( ) )
2013-11-06 11:48:53 -05:00
{
Scalar scalar ;
if ( ResolveValue ( scalar ) )
{
if ( success )
* success = true ;
2015-02-08 20:44:09 -05:00
return scalar . SLongLong ( fail_value ) ;
2013-11-06 11:48:53 -05:00
}
// fallthrough, otherwise...
}
if ( success )
* success = false ;
2015-02-08 20:44:09 -05:00
return fail_value ;
2013-11-06 11:48:53 -05:00
}
2013-08-23 13:46:38 -04:00
// if any more "special cases" are added to ValueObject::DumpPrintableRepresentation() please keep
// this call up to date by returning true for your new special cases. We will eventually move
// to checking this call result before trying to display special cases
bool
ValueObject : : HasSpecialPrintableRepresentation ( ValueObjectRepresentationStyle val_obj_display ,
Format custom_format )
{
Flags flags ( GetTypeInfo ( ) ) ;
2015-02-06 16:38:51 -05:00
if ( flags . AnySet ( eTypeIsArray | eTypeIsPointer )
2013-08-23 13:46:38 -04:00
& & val_obj_display = = ValueObject : : eValueObjectRepresentationStyleValue )
{
if ( IsCStringContainer ( true ) & &
( custom_format = = eFormatCString | |
custom_format = = eFormatCharArray | |
custom_format = = eFormatChar | |
custom_format = = eFormatVectorOfChar ) )
return true ;
2015-02-06 16:38:51 -05:00
if ( flags . Test ( eTypeIsArray ) )
2013-08-23 13:46:38 -04:00
{
if ( ( custom_format = = eFormatBytes ) | |
( custom_format = = eFormatBytesWithASCII ) )
return true ;
if ( ( custom_format = = eFormatVectorOfChar ) | |
( custom_format = = eFormatVectorOfFloat32 ) | |
( custom_format = = eFormatVectorOfFloat64 ) | |
( custom_format = = eFormatVectorOfSInt16 ) | |
( custom_format = = eFormatVectorOfSInt32 ) | |
( custom_format = = eFormatVectorOfSInt64 ) | |
( custom_format = = eFormatVectorOfSInt8 ) | |
( custom_format = = eFormatVectorOfUInt128 ) | |
( custom_format = = eFormatVectorOfUInt16 ) | |
( custom_format = = eFormatVectorOfUInt32 ) | |
( custom_format = = eFormatVectorOfUInt64 ) | |
( custom_format = = eFormatVectorOfUInt8 ) )
return true ;
}
}
return false ;
}
bool
ValueObject : : DumpPrintableRepresentation ( Stream & s ,
ValueObjectRepresentationStyle val_obj_display ,
Format custom_format ,
2014-02-18 11:23:10 -05:00
PrintableRepresentationSpecialCases special ,
bool do_dump_error )
2013-08-23 13:46:38 -04:00
{
Flags flags ( GetTypeInfo ( ) ) ;
bool allow_special = ( ( special & ePrintableRepresentationSpecialCasesAllow ) = = ePrintableRepresentationSpecialCasesAllow ) ;
bool only_special = ( ( special & ePrintableRepresentationSpecialCasesOnly ) = = ePrintableRepresentationSpecialCasesOnly ) ;
if ( allow_special )
{
2015-02-06 16:38:51 -05:00
if ( flags . AnySet ( eTypeIsArray | eTypeIsPointer )
2013-08-23 13:46:38 -04:00
& & val_obj_display = = ValueObject : : eValueObjectRepresentationStyleValue )
{
// when being asked to get a printable display an array or pointer type directly,
// try to "do the right thing"
if ( IsCStringContainer ( true ) & &
( custom_format = = eFormatCString | |
custom_format = = eFormatCharArray | |
custom_format = = eFormatChar | |
custom_format = = eFormatVectorOfChar ) ) // print char[] & char* directly
{
Error error ;
2015-02-06 16:38:51 -05:00
lldb : : DataBufferSP buffer_sp ;
ReadPointedString ( buffer_sp ,
2013-08-23 13:46:38 -04:00
error ,
0 ,
( custom_format = = eFormatVectorOfChar ) | |
( custom_format = = eFormatCharArray ) ) ;
2015-02-06 16:38:51 -05:00
lldb_private : : formatters : : ReadBufferAndDumpToStreamOptions options ( * this ) ;
options . SetData ( DataExtractor ( buffer_sp , lldb : : eByteOrderInvalid , 8 ) ) ; // none of this matters for a string - pass some defaults
options . SetStream ( & s ) ;
options . SetPrefixToken ( 0 ) ;
options . SetQuote ( ' " ' ) ;
options . SetSourceSize ( buffer_sp - > GetByteSize ( ) ) ;
lldb_private : : formatters : : ReadBufferAndDumpToStream < lldb_private : : formatters : : StringElementType : : ASCII > ( options ) ;
2013-08-23 13:46:38 -04:00
return ! error . Fail ( ) ;
}
if ( custom_format = = eFormatEnum )
return false ;
// this only works for arrays, because I have no way to know when
// the pointed memory ends, and no special \0 end of data marker
2015-02-06 16:38:51 -05:00
if ( flags . Test ( eTypeIsArray ) )
2013-08-23 13:46:38 -04:00
{
if ( ( custom_format = = eFormatBytes ) | |
( custom_format = = eFormatBytesWithASCII ) )
{
const size_t count = GetNumChildren ( ) ;
s < < ' [ ' ;
for ( size_t low = 0 ; low < count ; low + + )
{
if ( low )
s < < ' , ' ;
ValueObjectSP child = GetChildAtIndex ( low , true ) ;
if ( ! child . get ( ) )
{
s < < " <invalid child> " ;
continue ;
}
child - > DumpPrintableRepresentation ( s , ValueObject : : eValueObjectRepresentationStyleValue , custom_format ) ;
}
s < < ' ] ' ;
return true ;
}
if ( ( custom_format = = eFormatVectorOfChar ) | |
( custom_format = = eFormatVectorOfFloat32 ) | |
( custom_format = = eFormatVectorOfFloat64 ) | |
( custom_format = = eFormatVectorOfSInt16 ) | |
( custom_format = = eFormatVectorOfSInt32 ) | |
( custom_format = = eFormatVectorOfSInt64 ) | |
( custom_format = = eFormatVectorOfSInt8 ) | |
( custom_format = = eFormatVectorOfUInt128 ) | |
( custom_format = = eFormatVectorOfUInt16 ) | |
( custom_format = = eFormatVectorOfUInt32 ) | |
( custom_format = = eFormatVectorOfUInt64 ) | |
( custom_format = = eFormatVectorOfUInt8 ) ) // arrays of bytes, bytes with ASCII or any vector format should be printed directly
{
const size_t count = GetNumChildren ( ) ;
Format format = FormatManager : : GetSingleItemFormat ( custom_format ) ;
s < < ' [ ' ;
for ( size_t low = 0 ; low < count ; low + + )
{
if ( low )
s < < ' , ' ;
ValueObjectSP child = GetChildAtIndex ( low , true ) ;
if ( ! child . get ( ) )
{
s < < " <invalid child> " ;
continue ;
}
child - > DumpPrintableRepresentation ( s , ValueObject : : eValueObjectRepresentationStyleValue , format ) ;
}
s < < ' ] ' ;
return true ;
}
}
if ( ( custom_format = = eFormatBoolean ) | |
( custom_format = = eFormatBinary ) | |
( custom_format = = eFormatChar ) | |
( custom_format = = eFormatCharPrintable ) | |
( custom_format = = eFormatComplexFloat ) | |
( custom_format = = eFormatDecimal ) | |
( custom_format = = eFormatHex ) | |
( custom_format = = eFormatHexUppercase ) | |
( custom_format = = eFormatFloat ) | |
( custom_format = = eFormatOctal ) | |
( custom_format = = eFormatOSType ) | |
( custom_format = = eFormatUnicode16 ) | |
( custom_format = = eFormatUnicode32 ) | |
( custom_format = = eFormatUnsigned ) | |
( custom_format = = eFormatPointer ) | |
( custom_format = = eFormatComplexInteger ) | |
( custom_format = = eFormatComplex ) | |
( custom_format = = eFormatDefault ) ) // use the [] operator
return false ;
}
}
if ( only_special )
return false ;
bool var_success = false ;
{
const char * cstr = NULL ;
// this is a local stream that we are using to ensure that the data pointed to by cstr survives
// long enough for us to copy it to its destination - it is necessary to have this temporary storage
// area for cases where our desired output is not backed by some other longer-term storage
StreamString strm ;
if ( custom_format ! = eFormatInvalid )
SetFormat ( custom_format ) ;
switch ( val_obj_display )
{
case eValueObjectRepresentationStyleValue :
cstr = GetValueAsCString ( ) ;
break ;
case eValueObjectRepresentationStyleSummary :
cstr = GetSummaryAsCString ( ) ;
break ;
case eValueObjectRepresentationStyleLanguageSpecific :
cstr = GetObjectDescription ( ) ;
break ;
case eValueObjectRepresentationStyleLocation :
cstr = GetLocationAsCString ( ) ;
break ;
case eValueObjectRepresentationStyleChildrenCount :
2014-11-25 16:00:58 -05:00
strm . Printf ( " % " PRIu64 " " , ( uint64_t ) GetNumChildren ( ) ) ;
2013-08-23 13:46:38 -04:00
cstr = strm . GetString ( ) . c_str ( ) ;
break ;
case eValueObjectRepresentationStyleType :
cstr = GetTypeName ( ) . AsCString ( ) ;
break ;
case eValueObjectRepresentationStyleName :
cstr = GetName ( ) . AsCString ( ) ;
break ;
case eValueObjectRepresentationStyleExpressionPath :
GetExpressionPath ( strm , false ) ;
cstr = strm . GetString ( ) . c_str ( ) ;
break ;
}
if ( ! cstr )
{
if ( val_obj_display = = eValueObjectRepresentationStyleValue )
cstr = GetSummaryAsCString ( ) ;
else if ( val_obj_display = = eValueObjectRepresentationStyleSummary )
{
2015-02-06 16:38:51 -05:00
if ( ! CanProvideValue ( ) )
2013-08-23 13:46:38 -04:00
{
strm . Printf ( " %s @ %s " , GetTypeName ( ) . AsCString ( ) , GetLocationAsCString ( ) ) ;
cstr = strm . GetString ( ) . c_str ( ) ;
}
else
cstr = GetValueAsCString ( ) ;
}
}
if ( cstr )
s . PutCString ( cstr ) ;
else
{
if ( m_error . Fail ( ) )
2014-02-18 11:23:10 -05:00
{
if ( do_dump_error )
s . Printf ( " <%s> " , m_error . AsCString ( ) ) ;
else
return false ;
}
2013-08-23 13:46:38 -04:00
else if ( val_obj_display = = eValueObjectRepresentationStyleSummary )
s . PutCString ( " <no summary available> " ) ;
else if ( val_obj_display = = eValueObjectRepresentationStyleValue )
s . PutCString ( " <no value available> " ) ;
else if ( val_obj_display = = eValueObjectRepresentationStyleLanguageSpecific )
s . PutCString ( " <not a valid Objective-C object> " ) ; // edit this if we have other runtimes that support a description
else
s . PutCString ( " <no printable representation> " ) ;
}
// we should only return false here if we could not do *anything*
// even if we have an error message as output, that's a success
// from our callers' perspective, so return true
var_success = true ;
if ( custom_format ! = eFormatInvalid )
SetFormat ( eFormatDefault ) ;
}
return var_success ;
}
addr_t
ValueObject : : GetAddressOf ( bool scalar_is_load_address , AddressType * address_type )
{
if ( ! UpdateValueIfNeeded ( false ) )
return LLDB_INVALID_ADDRESS ;
switch ( m_value . GetValueType ( ) )
{
case Value : : eValueTypeScalar :
case Value : : eValueTypeVector :
if ( scalar_is_load_address )
{
if ( address_type )
* address_type = eAddressTypeLoad ;
return m_value . GetScalar ( ) . ULongLong ( LLDB_INVALID_ADDRESS ) ;
}
break ;
case Value : : eValueTypeLoadAddress :
case Value : : eValueTypeFileAddress :
case Value : : eValueTypeHostAddress :
{
if ( address_type )
* address_type = m_value . GetValueAddressType ( ) ;
return m_value . GetScalar ( ) . ULongLong ( LLDB_INVALID_ADDRESS ) ;
}
break ;
}
if ( address_type )
* address_type = eAddressTypeInvalid ;
return LLDB_INVALID_ADDRESS ;
}
addr_t
ValueObject : : GetPointerValue ( AddressType * address_type )
{
addr_t address = LLDB_INVALID_ADDRESS ;
if ( address_type )
* address_type = eAddressTypeInvalid ;
if ( ! UpdateValueIfNeeded ( false ) )
return address ;
switch ( m_value . GetValueType ( ) )
{
case Value : : eValueTypeScalar :
case Value : : eValueTypeVector :
address = m_value . GetScalar ( ) . ULongLong ( LLDB_INVALID_ADDRESS ) ;
break ;
case Value : : eValueTypeHostAddress :
case Value : : eValueTypeLoadAddress :
case Value : : eValueTypeFileAddress :
{
lldb : : offset_t data_offset = 0 ;
address = m_data . GetPointer ( & data_offset ) ;
}
break ;
}
if ( address_type )
* address_type = GetAddressTypeOfChildren ( ) ;
return address ;
}
bool
ValueObject : : SetValueFromCString ( const char * value_str , Error & error )
{
error . Clear ( ) ;
// Make sure our value is up to date first so that our location and location
// type is valid.
if ( ! UpdateValueIfNeeded ( false ) )
{
error . SetErrorString ( " unable to read value " ) ;
return false ;
}
uint64_t count = 0 ;
const Encoding encoding = GetClangType ( ) . GetEncoding ( count ) ;
const size_t byte_size = GetByteSize ( ) ;
Value : : ValueType value_type = m_value . GetValueType ( ) ;
if ( value_type = = Value : : eValueTypeScalar )
{
// If the value is already a scalar, then let the scalar change itself:
m_value . GetScalar ( ) . SetValueFromCString ( value_str , encoding , byte_size ) ;
}
else if ( byte_size < = Scalar : : GetMaxByteSize ( ) )
{
// If the value fits in a scalar, then make a new scalar and again let the
// scalar code do the conversion, then figure out where to put the new value.
Scalar new_scalar ;
error = new_scalar . SetValueFromCString ( value_str , encoding , byte_size ) ;
if ( error . Success ( ) )
{
switch ( value_type )
{
case Value : : eValueTypeLoadAddress :
{
// If it is a load address, then the scalar value is the storage location
// of the data, and we have to shove this value down to that load location.
ExecutionContext exe_ctx ( GetExecutionContextRef ( ) ) ;
Process * process = exe_ctx . GetProcessPtr ( ) ;
if ( process )
{
addr_t target_addr = m_value . GetScalar ( ) . ULongLong ( LLDB_INVALID_ADDRESS ) ;
size_t bytes_written = process - > WriteScalarToMemory ( target_addr ,
new_scalar ,
byte_size ,
error ) ;
if ( ! error . Success ( ) )
return false ;
if ( bytes_written ! = byte_size )
{
error . SetErrorString ( " unable to write value to memory " ) ;
return false ;
}
}
}
break ;
case Value : : eValueTypeHostAddress :
{
// If it is a host address, then we stuff the scalar as a DataBuffer into the Value's data.
DataExtractor new_data ;
new_data . SetByteOrder ( m_data . GetByteOrder ( ) ) ;
DataBufferSP buffer_sp ( new DataBufferHeap ( byte_size , 0 ) ) ;
m_data . SetData ( buffer_sp , 0 ) ;
bool success = new_scalar . GetData ( new_data ) ;
if ( success )
{
new_data . CopyByteOrderedData ( 0 ,
byte_size ,
const_cast < uint8_t * > ( m_data . GetDataStart ( ) ) ,
byte_size ,
m_data . GetByteOrder ( ) ) ;
}
m_value . GetScalar ( ) = ( uintptr_t ) m_data . GetDataStart ( ) ;
}
break ;
case Value : : eValueTypeFileAddress :
case Value : : eValueTypeScalar :
case Value : : eValueTypeVector :
break ;
}
}
else
{
return false ;
}
}
else
{
// We don't support setting things bigger than a scalar at present.
error . SetErrorString ( " unable to write aggregate data type " ) ;
return false ;
}
// If we have reached this point, then we have successfully changed the value.
SetNeedsUpdate ( ) ;
return true ;
}
bool
ValueObject : : GetDeclaration ( Declaration & decl )
{
decl . Clear ( ) ;
return false ;
}
ConstString
ValueObject : : GetTypeName ( )
{
return GetClangType ( ) . GetConstTypeName ( ) ;
}
2014-11-25 16:00:58 -05:00
ConstString
ValueObject : : GetDisplayTypeName ( )
{
return GetTypeName ( ) ;
}
2013-08-23 13:46:38 -04:00
ConstString
ValueObject : : GetQualifiedTypeName ( )
{
return GetClangType ( ) . GetConstQualifiedTypeName ( ) ;
}
LanguageType
ValueObject : : GetObjectRuntimeLanguage ( )
{
return GetClangType ( ) . GetMinimumLanguage ( ) ;
}
void
ValueObject : : AddSyntheticChild ( const ConstString & key , ValueObject * valobj )
{
m_synthetic_children [ key ] = valobj ;
}
ValueObjectSP
ValueObject : : GetSyntheticChild ( const ConstString & key ) const
{
ValueObjectSP synthetic_child_sp ;
std : : map < ConstString , ValueObject * > : : const_iterator pos = m_synthetic_children . find ( key ) ;
if ( pos ! = m_synthetic_children . end ( ) )
synthetic_child_sp = pos - > second - > GetSP ( ) ;
return synthetic_child_sp ;
}
uint32_t
ValueObject : : GetTypeInfo ( ClangASTType * pointee_or_element_clang_type )
{
return GetClangType ( ) . GetTypeInfo ( pointee_or_element_clang_type ) ;
}
bool
ValueObject : : IsPointerType ( )
{
return GetClangType ( ) . IsPointerType ( ) ;
}
bool
ValueObject : : IsArrayType ( )
{
return GetClangType ( ) . IsArrayType ( NULL , NULL , NULL ) ;
}
bool
ValueObject : : IsScalarType ( )
{
return GetClangType ( ) . IsScalarType ( ) ;
}
bool
ValueObject : : IsIntegerType ( bool & is_signed )
{
return GetClangType ( ) . IsIntegerType ( is_signed ) ;
}
bool
ValueObject : : IsPointerOrReferenceType ( )
{
return GetClangType ( ) . IsPointerOrReferenceType ( ) ;
}
bool
ValueObject : : IsPossibleDynamicType ( )
{
ExecutionContext exe_ctx ( GetExecutionContextRef ( ) ) ;
Process * process = exe_ctx . GetProcessPtr ( ) ;
if ( process )
return process - > IsPossibleDynamicValue ( * this ) ;
else
return GetClangType ( ) . IsPossibleDynamicType ( NULL , true , true ) ;
}
bool
ValueObject : : IsObjCNil ( )
{
2015-02-06 16:38:51 -05:00
const uint32_t mask = eTypeIsObjC | eTypeIsPointer ;
2013-08-23 13:46:38 -04:00
bool isObjCpointer = ( ( ( GetClangType ( ) . GetTypeInfo ( NULL ) ) & mask ) = = mask ) ;
if ( ! isObjCpointer )
return false ;
bool canReadValue = true ;
bool isZero = GetValueAsUnsigned ( 0 , & canReadValue ) = = 0 ;
return canReadValue & & isZero ;
}
ValueObjectSP
ValueObject : : GetSyntheticArrayMember ( size_t index , bool can_create )
{
const uint32_t type_info = GetTypeInfo ( ) ;
2015-02-06 16:38:51 -05:00
if ( type_info & eTypeIsArray )
2013-08-23 13:46:38 -04:00
return GetSyntheticArrayMemberFromArray ( index , can_create ) ;
2015-02-06 16:38:51 -05:00
if ( type_info & eTypeIsPointer )
2013-08-23 13:46:38 -04:00
return GetSyntheticArrayMemberFromPointer ( index , can_create ) ;
return ValueObjectSP ( ) ;
}
ValueObjectSP
ValueObject : : GetSyntheticArrayMemberFromPointer ( size_t index , bool can_create )
{
ValueObjectSP synthetic_child_sp ;
if ( IsPointerType ( ) )
{
char index_str [ 64 ] ;
2014-11-25 16:00:58 -05:00
snprintf ( index_str , sizeof ( index_str ) , " [% " PRIu64 " ] " , ( uint64_t ) index ) ;
2013-08-23 13:46:38 -04:00
ConstString index_const_str ( index_str ) ;
// Check if we have already created a synthetic array member in this
// valid object. If we have we will re-use it.
synthetic_child_sp = GetSyntheticChild ( index_const_str ) ;
if ( ! synthetic_child_sp )
{
ValueObject * synthetic_child ;
// We haven't made a synthetic array member for INDEX yet, so
// lets make one and cache it for any future reference.
synthetic_child = CreateChildAtIndex ( 0 , true , index ) ;
// Cache the value if we got one back...
if ( synthetic_child )
{
AddSyntheticChild ( index_const_str , synthetic_child ) ;
synthetic_child_sp = synthetic_child - > GetSP ( ) ;
synthetic_child_sp - > SetName ( ConstString ( index_str ) ) ;
synthetic_child_sp - > m_is_array_item_for_pointer = true ;
}
}
}
return synthetic_child_sp ;
}
// This allows you to create an array member using and index
// that doesn't not fall in the normal bounds of the array.
// Many times structure can be defined as:
// struct Collection
// {
// uint32_t item_count;
// Item item_array[0];
// };
// The size of the "item_array" is 1, but many times in practice
// there are more items in "item_array".
ValueObjectSP
ValueObject : : GetSyntheticArrayMemberFromArray ( size_t index , bool can_create )
{
ValueObjectSP synthetic_child_sp ;
if ( IsArrayType ( ) )
{
char index_str [ 64 ] ;
2014-11-25 16:00:58 -05:00
snprintf ( index_str , sizeof ( index_str ) , " [% " PRIu64 " ] " , ( uint64_t ) index ) ;
2013-08-23 13:46:38 -04:00
ConstString index_const_str ( index_str ) ;
// Check if we have already created a synthetic array member in this
// valid object. If we have we will re-use it.
synthetic_child_sp = GetSyntheticChild ( index_const_str ) ;
if ( ! synthetic_child_sp )
{
ValueObject * synthetic_child ;
// We haven't made a synthetic array member for INDEX yet, so
// lets make one and cache it for any future reference.
synthetic_child = CreateChildAtIndex ( 0 , true , index ) ;
// Cache the value if we got one back...
if ( synthetic_child )
{
AddSyntheticChild ( index_const_str , synthetic_child ) ;
synthetic_child_sp = synthetic_child - > GetSP ( ) ;
synthetic_child_sp - > SetName ( ConstString ( index_str ) ) ;
synthetic_child_sp - > m_is_array_item_for_pointer = true ;
}
}
}
return synthetic_child_sp ;
}
ValueObjectSP
ValueObject : : GetSyntheticBitFieldChild ( uint32_t from , uint32_t to , bool can_create )
{
ValueObjectSP synthetic_child_sp ;
if ( IsScalarType ( ) )
{
char index_str [ 64 ] ;
snprintf ( index_str , sizeof ( index_str ) , " [%i-%i] " , from , to ) ;
ConstString index_const_str ( index_str ) ;
// Check if we have already created a synthetic array member in this
// valid object. If we have we will re-use it.
synthetic_child_sp = GetSyntheticChild ( index_const_str ) ;
if ( ! synthetic_child_sp )
{
// We haven't made a synthetic array member for INDEX yet, so
// lets make one and cache it for any future reference.
ValueObjectChild * synthetic_child = new ValueObjectChild ( * this ,
GetClangType ( ) ,
index_const_str ,
GetByteSize ( ) ,
0 ,
to - from + 1 ,
from ,
false ,
false ,
eAddressTypeInvalid ) ;
// Cache the value if we got one back...
if ( synthetic_child )
{
AddSyntheticChild ( index_const_str , synthetic_child ) ;
synthetic_child_sp = synthetic_child - > GetSP ( ) ;
synthetic_child_sp - > SetName ( ConstString ( index_str ) ) ;
synthetic_child_sp - > m_is_bitfield_for_scalar = true ;
}
}
}
return synthetic_child_sp ;
}
ValueObjectSP
ValueObject : : GetSyntheticChildAtOffset ( uint32_t offset , const ClangASTType & type , bool can_create )
{
ValueObjectSP synthetic_child_sp ;
char name_str [ 64 ] ;
snprintf ( name_str , sizeof ( name_str ) , " @%i " , offset ) ;
ConstString name_const_str ( name_str ) ;
// Check if we have already created a synthetic array member in this
// valid object. If we have we will re-use it.
synthetic_child_sp = GetSyntheticChild ( name_const_str ) ;
if ( synthetic_child_sp . get ( ) )
return synthetic_child_sp ;
if ( ! can_create )
return ValueObjectSP ( ) ;
2015-02-08 20:44:09 -05:00
ExecutionContext exe_ctx ( GetExecutionContextRef ( ) ) ;
2013-08-23 13:46:38 -04:00
ValueObjectChild * synthetic_child = new ValueObjectChild ( * this ,
type ,
name_const_str ,
2015-02-08 20:44:09 -05:00
type . GetByteSize ( & exe_ctx ) ,
2013-08-23 13:46:38 -04:00
offset ,
0 ,
0 ,
false ,
false ,
eAddressTypeInvalid ) ;
if ( synthetic_child )
{
AddSyntheticChild ( name_const_str , synthetic_child ) ;
synthetic_child_sp = synthetic_child - > GetSP ( ) ;
synthetic_child_sp - > SetName ( name_const_str ) ;
synthetic_child_sp - > m_is_child_at_offset = true ;
}
return synthetic_child_sp ;
}
2014-11-25 16:00:58 -05:00
ValueObjectSP
ValueObject : : GetSyntheticBase ( uint32_t offset , const ClangASTType & type , bool can_create )
{
ValueObjectSP synthetic_child_sp ;
char name_str [ 64 ] ;
snprintf ( name_str , sizeof ( name_str ) , " %s " , type . GetTypeName ( ) . AsCString ( " <unknown> " ) ) ;
ConstString name_const_str ( name_str ) ;
// Check if we have already created a synthetic array member in this
// valid object. If we have we will re-use it.
synthetic_child_sp = GetSyntheticChild ( name_const_str ) ;
if ( synthetic_child_sp . get ( ) )
return synthetic_child_sp ;
if ( ! can_create )
return ValueObjectSP ( ) ;
const bool is_base_class = true ;
2015-02-08 20:44:09 -05:00
ExecutionContext exe_ctx ( GetExecutionContextRef ( ) ) ;
2014-11-25 16:00:58 -05:00
ValueObjectChild * synthetic_child = new ValueObjectChild ( * this ,
type ,
name_const_str ,
2015-02-08 20:44:09 -05:00
type . GetByteSize ( & exe_ctx ) ,
2014-11-25 16:00:58 -05:00
offset ,
0 ,
0 ,
is_base_class ,
false ,
eAddressTypeInvalid ) ;
if ( synthetic_child )
{
AddSyntheticChild ( name_const_str , synthetic_child ) ;
synthetic_child_sp = synthetic_child - > GetSP ( ) ;
synthetic_child_sp - > SetName ( name_const_str ) ;
}
return synthetic_child_sp ;
}
2013-08-23 13:46:38 -04:00
// your expression path needs to have a leading . or ->
// (unless it somehow "looks like" an array, in which case it has
// a leading [ symbol). while the [ is meaningful and should be shown
// to the user, . and -> are just parser design, but by no means
// added information for the user.. strip them off
static const char *
SkipLeadingExpressionPathSeparators ( const char * expression )
{
if ( ! expression | | ! expression [ 0 ] )
return expression ;
if ( expression [ 0 ] = = ' . ' )
return expression + 1 ;
if ( expression [ 0 ] = = ' - ' & & expression [ 1 ] = = ' > ' )
return expression + 2 ;
return expression ;
}
ValueObjectSP
ValueObject : : GetSyntheticExpressionPathChild ( const char * expression , bool can_create )
{
ValueObjectSP synthetic_child_sp ;
ConstString name_const_string ( expression ) ;
// Check if we have already created a synthetic array member in this
// valid object. If we have we will re-use it.
synthetic_child_sp = GetSyntheticChild ( name_const_string ) ;
if ( ! synthetic_child_sp )
{
// We haven't made a synthetic array member for expression yet, so
// lets make one and cache it for any future reference.
synthetic_child_sp = GetValueForExpressionPath ( expression ,
NULL , NULL , NULL ,
GetValueForExpressionPathOptions ( ) . DontAllowSyntheticChildren ( ) ) ;
// Cache the value if we got one back...
if ( synthetic_child_sp . get ( ) )
{
// FIXME: this causes a "real" child to end up with its name changed to the contents of expression
AddSyntheticChild ( name_const_string , synthetic_child_sp . get ( ) ) ;
synthetic_child_sp - > SetName ( ConstString ( SkipLeadingExpressionPathSeparators ( expression ) ) ) ;
}
}
return synthetic_child_sp ;
}
void
ValueObject : : CalculateSyntheticValue ( bool use_synthetic )
{
if ( use_synthetic = = false )
return ;
TargetSP target_sp ( GetTargetSP ( ) ) ;
2013-11-06 11:48:53 -05:00
if ( target_sp & & target_sp - > GetEnableSyntheticValue ( ) = = false )
2013-08-23 13:46:38 -04:00
{
m_synthetic_value = NULL ;
return ;
}
lldb : : SyntheticChildrenSP current_synth_sp ( m_synthetic_children_sp ) ;
if ( ! UpdateFormatsIfNeeded ( ) & & m_synthetic_value )
return ;
if ( m_synthetic_children_sp . get ( ) = = NULL )
return ;
if ( current_synth_sp = = m_synthetic_children_sp & & m_synthetic_value )
return ;
m_synthetic_value = new ValueObjectSynthetic ( * this , m_synthetic_children_sp ) ;
}
void
ValueObject : : CalculateDynamicValue ( DynamicValueType use_dynamic )
{
if ( use_dynamic = = eNoDynamicValues )
return ;
if ( ! m_dynamic_value & & ! IsDynamic ( ) )
{
ExecutionContext exe_ctx ( GetExecutionContextRef ( ) ) ;
Process * process = exe_ctx . GetProcessPtr ( ) ;
if ( process & & process - > IsPossibleDynamicValue ( * this ) )
{
ClearDynamicTypeInformation ( ) ;
m_dynamic_value = new ValueObjectDynamicValue ( * this , use_dynamic ) ;
}
}
}
ValueObjectSP
ValueObject : : GetDynamicValue ( DynamicValueType use_dynamic )
{
if ( use_dynamic = = eNoDynamicValues )
return ValueObjectSP ( ) ;
if ( ! IsDynamic ( ) & & m_dynamic_value = = NULL )
{
CalculateDynamicValue ( use_dynamic ) ;
}
if ( m_dynamic_value )
return m_dynamic_value - > GetSP ( ) ;
else
return ValueObjectSP ( ) ;
}
ValueObjectSP
ValueObject : : GetStaticValue ( )
{
return GetSP ( ) ;
}
lldb : : ValueObjectSP
ValueObject : : GetNonSyntheticValue ( )
{
return GetSP ( ) ;
}
ValueObjectSP
ValueObject : : GetSyntheticValue ( bool use_synthetic )
{
if ( use_synthetic = = false )
return ValueObjectSP ( ) ;
CalculateSyntheticValue ( use_synthetic ) ;
if ( m_synthetic_value )
return m_synthetic_value - > GetSP ( ) ;
else
return ValueObjectSP ( ) ;
}
bool
ValueObject : : HasSyntheticValue ( )
{
UpdateFormatsIfNeeded ( ) ;
if ( m_synthetic_children_sp . get ( ) = = NULL )
return false ;
CalculateSyntheticValue ( true ) ;
if ( m_synthetic_value )
return true ;
else
return false ;
}
bool
ValueObject : : GetBaseClassPath ( Stream & s )
{
if ( IsBaseClass ( ) )
{
bool parent_had_base_class = GetParent ( ) & & GetParent ( ) - > GetBaseClassPath ( s ) ;
ClangASTType clang_type = GetClangType ( ) ;
std : : string cxx_class_name ;
bool this_had_base_class = clang_type . GetCXXClassName ( cxx_class_name ) ;
if ( this_had_base_class )
{
if ( parent_had_base_class )
s . PutCString ( " :: " ) ;
s . PutCString ( cxx_class_name . c_str ( ) ) ;
}
return parent_had_base_class | | this_had_base_class ;
}
return false ;
}
ValueObject *
ValueObject : : GetNonBaseClassParent ( )
{
if ( GetParent ( ) )
{
if ( GetParent ( ) - > IsBaseClass ( ) )
return GetParent ( ) - > GetNonBaseClassParent ( ) ;
else
return GetParent ( ) ;
}
return NULL ;
}
2014-11-25 16:00:58 -05:00
bool
ValueObject : : IsBaseClass ( uint32_t & depth )
{
if ( ! IsBaseClass ( ) )
{
depth = 0 ;
return false ;
}
if ( GetParent ( ) )
{
GetParent ( ) - > IsBaseClass ( depth ) ;
depth = depth + 1 ;
return true ;
}
// TODO: a base of no parent? weird..
depth = 1 ;
return true ;
}
2013-08-23 13:46:38 -04:00
void
ValueObject : : GetExpressionPath ( Stream & s , bool qualify_cxx_base_classes , GetExpressionPathFormat epformat )
{
2015-02-06 16:38:51 -05:00
// synthetic children do not actually "exist" as part of the hierarchy, and sometimes they are consed up in ways
// that don't make sense from an underlying language/API standpoint. So, use a special code path here to return
// something that can hopefully be used in expression
if ( m_is_synthetic_children_generated )
{
UpdateValueIfNeeded ( ) ;
if ( m_value . GetValueType ( ) = = Value : : eValueTypeLoadAddress )
{
if ( IsPointerOrReferenceType ( ) )
{
s . Printf ( " ((%s)0x% " PRIx64 " ) " ,
GetTypeName ( ) . AsCString ( " void " ) ,
GetValueAsUnsigned ( 0 ) ) ;
return ;
}
else
{
uint64_t load_addr = m_value . GetScalar ( ) . ULongLong ( LLDB_INVALID_ADDRESS ) ;
if ( load_addr ! = LLDB_INVALID_ADDRESS )
{
s . Printf ( " (*( (%s *)0x% " PRIx64 " )) " ,
GetTypeName ( ) . AsCString ( " void " ) ,
load_addr ) ;
return ;
}
}
}
if ( CanProvideValue ( ) )
{
s . Printf ( " ((%s)%s) " ,
GetTypeName ( ) . AsCString ( " void " ) ,
GetValueAsCString ( ) ) ;
return ;
}
return ;
}
2013-08-23 13:46:38 -04:00
const bool is_deref_of_parent = IsDereferenceOfParent ( ) ;
if ( is_deref_of_parent & & epformat = = eGetExpressionPathFormatDereferencePointers )
{
// this is the original format of GetExpressionPath() producing code like *(a_ptr).memberName, which is entirely
// fine, until you put this into StackFrame::GetValueForVariableExpressionPath() which prefers to see a_ptr->memberName.
// the eHonorPointers mode is meant to produce strings in this latter format
s . PutCString ( " *( " ) ;
}
ValueObject * parent = GetParent ( ) ;
if ( parent )
parent - > GetExpressionPath ( s , qualify_cxx_base_classes , epformat ) ;
// if we are a deref_of_parent just because we are synthetic array
// members made up to allow ptr[%d] syntax to work in variable
// printing, then add our name ([%d]) to the expression path
if ( m_is_array_item_for_pointer & & epformat = = eGetExpressionPathFormatHonorPointers )
s . PutCString ( m_name . AsCString ( ) ) ;
if ( ! IsBaseClass ( ) )
{
if ( ! is_deref_of_parent )
{
ValueObject * non_base_class_parent = GetNonBaseClassParent ( ) ;
if ( non_base_class_parent )
{
ClangASTType non_base_class_parent_clang_type = non_base_class_parent - > GetClangType ( ) ;
if ( non_base_class_parent_clang_type )
{
if ( parent & & parent - > IsDereferenceOfParent ( ) & & epformat = = eGetExpressionPathFormatHonorPointers )
{
s . PutCString ( " -> " ) ;
}
else
{
const uint32_t non_base_class_parent_type_info = non_base_class_parent_clang_type . GetTypeInfo ( ) ;
2015-02-06 16:38:51 -05:00
if ( non_base_class_parent_type_info & eTypeIsPointer )
2013-08-23 13:46:38 -04:00
{
s . PutCString ( " -> " ) ;
}
2015-02-06 16:38:51 -05:00
else if ( ( non_base_class_parent_type_info & eTypeHasChildren ) & &
! ( non_base_class_parent_type_info & eTypeIsArray ) )
2013-08-23 13:46:38 -04:00
{
s . PutChar ( ' . ' ) ;
}
}
}
}
const char * name = GetName ( ) . GetCString ( ) ;
if ( name )
{
if ( qualify_cxx_base_classes )
{
if ( GetBaseClassPath ( s ) )
s . PutCString ( " :: " ) ;
}
s . PutCString ( name ) ;
}
}
}
if ( is_deref_of_parent & & epformat = = eGetExpressionPathFormatDereferencePointers )
{
s . PutChar ( ' ) ' ) ;
}
}
ValueObjectSP
ValueObject : : GetValueForExpressionPath ( const char * expression ,
const char * * first_unparsed ,
ExpressionPathScanEndReason * reason_to_stop ,
ExpressionPathEndResultType * final_value_type ,
const GetValueForExpressionPathOptions & options ,
ExpressionPathAftermath * final_task_on_target )
{
const char * dummy_first_unparsed ;
ExpressionPathScanEndReason dummy_reason_to_stop = ValueObject : : eExpressionPathScanEndReasonUnknown ;
ExpressionPathEndResultType dummy_final_value_type = ValueObject : : eExpressionPathEndResultTypeInvalid ;
ExpressionPathAftermath dummy_final_task_on_target = ValueObject : : eExpressionPathAftermathNothing ;
ValueObjectSP ret_val = GetValueForExpressionPath_Impl ( expression ,
first_unparsed ? first_unparsed : & dummy_first_unparsed ,
reason_to_stop ? reason_to_stop : & dummy_reason_to_stop ,
final_value_type ? final_value_type : & dummy_final_value_type ,
options ,
final_task_on_target ? final_task_on_target : & dummy_final_task_on_target ) ;
if ( ! final_task_on_target | | * final_task_on_target = = ValueObject : : eExpressionPathAftermathNothing )
return ret_val ;
if ( ret_val . get ( ) & & ( ( final_value_type ? * final_value_type : dummy_final_value_type ) = = eExpressionPathEndResultTypePlain ) ) // I can only deref and takeaddress of plain objects
{
if ( ( final_task_on_target ? * final_task_on_target : dummy_final_task_on_target ) = = ValueObject : : eExpressionPathAftermathDereference )
{
Error error ;
ValueObjectSP final_value = ret_val - > Dereference ( error ) ;
if ( error . Fail ( ) | | ! final_value . get ( ) )
{
if ( reason_to_stop )
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonDereferencingFailed ;
if ( final_value_type )
* final_value_type = ValueObject : : eExpressionPathEndResultTypeInvalid ;
return ValueObjectSP ( ) ;
}
else
{
if ( final_task_on_target )
* final_task_on_target = ValueObject : : eExpressionPathAftermathNothing ;
return final_value ;
}
}
if ( * final_task_on_target = = ValueObject : : eExpressionPathAftermathTakeAddress )
{
Error error ;
ValueObjectSP final_value = ret_val - > AddressOf ( error ) ;
if ( error . Fail ( ) | | ! final_value . get ( ) )
{
if ( reason_to_stop )
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonTakingAddressFailed ;
if ( final_value_type )
* final_value_type = ValueObject : : eExpressionPathEndResultTypeInvalid ;
return ValueObjectSP ( ) ;
}
else
{
if ( final_task_on_target )
* final_task_on_target = ValueObject : : eExpressionPathAftermathNothing ;
return final_value ;
}
}
}
return ret_val ; // final_task_on_target will still have its original value, so you know I did not do it
}
int
ValueObject : : GetValuesForExpressionPath ( const char * expression ,
ValueObjectListSP & list ,
const char * * first_unparsed ,
ExpressionPathScanEndReason * reason_to_stop ,
ExpressionPathEndResultType * final_value_type ,
const GetValueForExpressionPathOptions & options ,
ExpressionPathAftermath * final_task_on_target )
{
const char * dummy_first_unparsed ;
ExpressionPathScanEndReason dummy_reason_to_stop ;
ExpressionPathEndResultType dummy_final_value_type ;
ExpressionPathAftermath dummy_final_task_on_target = ValueObject : : eExpressionPathAftermathNothing ;
ValueObjectSP ret_val = GetValueForExpressionPath_Impl ( expression ,
first_unparsed ? first_unparsed : & dummy_first_unparsed ,
reason_to_stop ? reason_to_stop : & dummy_reason_to_stop ,
final_value_type ? final_value_type : & dummy_final_value_type ,
options ,
final_task_on_target ? final_task_on_target : & dummy_final_task_on_target ) ;
if ( ! ret_val . get ( ) ) // if there are errors, I add nothing to the list
return 0 ;
if ( ( reason_to_stop ? * reason_to_stop : dummy_reason_to_stop ) ! = eExpressionPathScanEndReasonArrayRangeOperatorMet )
{
// I need not expand a range, just post-process the final value and return
if ( ! final_task_on_target | | * final_task_on_target = = ValueObject : : eExpressionPathAftermathNothing )
{
list - > Append ( ret_val ) ;
return 1 ;
}
if ( ret_val . get ( ) & & ( final_value_type ? * final_value_type : dummy_final_value_type ) = = eExpressionPathEndResultTypePlain ) // I can only deref and takeaddress of plain objects
{
if ( * final_task_on_target = = ValueObject : : eExpressionPathAftermathDereference )
{
Error error ;
ValueObjectSP final_value = ret_val - > Dereference ( error ) ;
if ( error . Fail ( ) | | ! final_value . get ( ) )
{
if ( reason_to_stop )
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonDereferencingFailed ;
if ( final_value_type )
* final_value_type = ValueObject : : eExpressionPathEndResultTypeInvalid ;
return 0 ;
}
else
{
* final_task_on_target = ValueObject : : eExpressionPathAftermathNothing ;
list - > Append ( final_value ) ;
return 1 ;
}
}
if ( * final_task_on_target = = ValueObject : : eExpressionPathAftermathTakeAddress )
{
Error error ;
ValueObjectSP final_value = ret_val - > AddressOf ( error ) ;
if ( error . Fail ( ) | | ! final_value . get ( ) )
{
if ( reason_to_stop )
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonTakingAddressFailed ;
if ( final_value_type )
* final_value_type = ValueObject : : eExpressionPathEndResultTypeInvalid ;
return 0 ;
}
else
{
* final_task_on_target = ValueObject : : eExpressionPathAftermathNothing ;
list - > Append ( final_value ) ;
return 1 ;
}
}
}
}
else
{
return ExpandArraySliceExpression ( first_unparsed ? * first_unparsed : dummy_first_unparsed ,
first_unparsed ? first_unparsed : & dummy_first_unparsed ,
ret_val ,
list ,
reason_to_stop ? reason_to_stop : & dummy_reason_to_stop ,
final_value_type ? final_value_type : & dummy_final_value_type ,
options ,
final_task_on_target ? final_task_on_target : & dummy_final_task_on_target ) ;
}
// in any non-covered case, just do the obviously right thing
list - > Append ( ret_val ) ;
return 1 ;
}
ValueObjectSP
ValueObject : : GetValueForExpressionPath_Impl ( const char * expression_cstr ,
const char * * first_unparsed ,
ExpressionPathScanEndReason * reason_to_stop ,
ExpressionPathEndResultType * final_result ,
const GetValueForExpressionPathOptions & options ,
ExpressionPathAftermath * what_next )
{
ValueObjectSP root = GetSP ( ) ;
if ( ! root . get ( ) )
return ValueObjectSP ( ) ;
* first_unparsed = expression_cstr ;
while ( true )
{
const char * expression_cstr = * first_unparsed ; // hide the top level expression_cstr
ClangASTType root_clang_type = root - > GetClangType ( ) ;
ClangASTType pointee_clang_type ;
Flags pointee_clang_type_info ;
Flags root_clang_type_info ( root_clang_type . GetTypeInfo ( & pointee_clang_type ) ) ;
if ( pointee_clang_type )
pointee_clang_type_info . Reset ( pointee_clang_type . GetTypeInfo ( ) ) ;
if ( ! expression_cstr | | * expression_cstr = = ' \0 ' )
{
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonEndOfString ;
return root ;
}
switch ( * expression_cstr )
{
case ' - ' :
{
if ( options . m_check_dot_vs_arrow_syntax & &
2015-02-06 16:38:51 -05:00
root_clang_type_info . Test ( eTypeIsPointer ) ) // if you are trying to use -> on a non-pointer and I must catch the error
2013-08-23 13:46:38 -04:00
{
* first_unparsed = expression_cstr ;
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonArrowInsteadOfDot ;
* final_result = ValueObject : : eExpressionPathEndResultTypeInvalid ;
return ValueObjectSP ( ) ;
}
2015-02-06 16:38:51 -05:00
if ( root_clang_type_info . Test ( eTypeIsObjC ) & & // if yo are trying to extract an ObjC IVar when this is forbidden
root_clang_type_info . Test ( eTypeIsPointer ) & &
2013-08-23 13:46:38 -04:00
options . m_no_fragile_ivar )
{
* first_unparsed = expression_cstr ;
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonFragileIVarNotAllowed ;
* final_result = ValueObject : : eExpressionPathEndResultTypeInvalid ;
return ValueObjectSP ( ) ;
}
if ( expression_cstr [ 1 ] ! = ' > ' )
{
* first_unparsed = expression_cstr ;
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonUnexpectedSymbol ;
* final_result = ValueObject : : eExpressionPathEndResultTypeInvalid ;
return ValueObjectSP ( ) ;
}
expression_cstr + + ; // skip the -
}
case ' . ' : // or fallthrough from ->
{
if ( options . m_check_dot_vs_arrow_syntax & & * expression_cstr = = ' . ' & &
2015-02-06 16:38:51 -05:00
root_clang_type_info . Test ( eTypeIsPointer ) ) // if you are trying to use . on a pointer and I must catch the error
2013-08-23 13:46:38 -04:00
{
* first_unparsed = expression_cstr ;
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonDotInsteadOfArrow ;
* final_result = ValueObject : : eExpressionPathEndResultTypeInvalid ;
return ValueObjectSP ( ) ;
}
expression_cstr + + ; // skip .
const char * next_separator = strpbrk ( expression_cstr + 1 , " -.[ " ) ;
ConstString child_name ;
if ( ! next_separator ) // if no other separator just expand this last layer
{
child_name . SetCString ( expression_cstr ) ;
ValueObjectSP child_valobj_sp = root - > GetChildMemberWithName ( child_name , true ) ;
if ( child_valobj_sp . get ( ) ) // we know we are done, so just return
{
* first_unparsed = " " ;
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonEndOfString ;
* final_result = ValueObject : : eExpressionPathEndResultTypePlain ;
return child_valobj_sp ;
}
else if ( options . m_no_synthetic_children = = false ) // let's try with synthetic children
{
if ( root - > IsSynthetic ( ) )
{
* first_unparsed = expression_cstr ;
2015-02-06 16:38:51 -05:00
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonNoSuchSyntheticChild ;
2013-08-23 13:46:38 -04:00
* final_result = ValueObject : : eExpressionPathEndResultTypeInvalid ;
return ValueObjectSP ( ) ;
}
child_valobj_sp = root - > GetSyntheticValue ( ) ;
if ( child_valobj_sp . get ( ) )
child_valobj_sp = child_valobj_sp - > GetChildMemberWithName ( child_name , true ) ;
}
// if we are here and options.m_no_synthetic_children is true, child_valobj_sp is going to be a NULL SP,
// so we hit the "else" branch, and return an error
if ( child_valobj_sp . get ( ) ) // if it worked, just return
{
* first_unparsed = " " ;
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonEndOfString ;
* final_result = ValueObject : : eExpressionPathEndResultTypePlain ;
return child_valobj_sp ;
}
else
{
* first_unparsed = expression_cstr ;
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonNoSuchChild ;
* final_result = ValueObject : : eExpressionPathEndResultTypeInvalid ;
return ValueObjectSP ( ) ;
}
}
else // other layers do expand
{
child_name . SetCStringWithLength ( expression_cstr , next_separator - expression_cstr ) ;
ValueObjectSP child_valobj_sp = root - > GetChildMemberWithName ( child_name , true ) ;
if ( child_valobj_sp . get ( ) ) // store the new root and move on
{
root = child_valobj_sp ;
* first_unparsed = next_separator ;
* final_result = ValueObject : : eExpressionPathEndResultTypePlain ;
continue ;
}
else if ( options . m_no_synthetic_children = = false ) // let's try with synthetic children
{
if ( root - > IsSynthetic ( ) )
{
* first_unparsed = expression_cstr ;
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonNoSuchChild ;
* final_result = ValueObject : : eExpressionPathEndResultTypeInvalid ;
return ValueObjectSP ( ) ;
}
child_valobj_sp = root - > GetSyntheticValue ( true ) ;
if ( child_valobj_sp )
child_valobj_sp = child_valobj_sp - > GetChildMemberWithName ( child_name , true ) ;
}
// if we are here and options.m_no_synthetic_children is true, child_valobj_sp is going to be a NULL SP,
// so we hit the "else" branch, and return an error
if ( child_valobj_sp . get ( ) ) // if it worked, move on
{
root = child_valobj_sp ;
* first_unparsed = next_separator ;
* final_result = ValueObject : : eExpressionPathEndResultTypePlain ;
continue ;
}
else
{
* first_unparsed = expression_cstr ;
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonNoSuchChild ;
* final_result = ValueObject : : eExpressionPathEndResultTypeInvalid ;
return ValueObjectSP ( ) ;
}
}
break ;
}
case ' [ ' :
{
2015-02-06 16:38:51 -05:00
if ( ! root_clang_type_info . Test ( eTypeIsArray ) & & ! root_clang_type_info . Test ( eTypeIsPointer ) & & ! root_clang_type_info . Test ( eTypeIsVector ) ) // if this is not a T[] nor a T*
2013-08-23 13:46:38 -04:00
{
2015-02-06 16:38:51 -05:00
if ( ! root_clang_type_info . Test ( eTypeIsScalar ) ) // if this is not even a scalar...
2013-08-23 13:46:38 -04:00
{
if ( options . m_no_synthetic_children ) // ...only chance left is synthetic
{
* first_unparsed = expression_cstr ;
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonRangeOperatorInvalid ;
* final_result = ValueObject : : eExpressionPathEndResultTypeInvalid ;
return ValueObjectSP ( ) ;
}
}
else if ( ! options . m_allow_bitfields_syntax ) // if this is a scalar, check that we can expand bitfields
{
* first_unparsed = expression_cstr ;
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonRangeOperatorNotAllowed ;
* final_result = ValueObject : : eExpressionPathEndResultTypeInvalid ;
return ValueObjectSP ( ) ;
}
}
if ( * ( expression_cstr + 1 ) = = ' ] ' ) // if this is an unbounded range it only works for arrays
{
2015-02-06 16:38:51 -05:00
if ( ! root_clang_type_info . Test ( eTypeIsArray ) )
2013-08-23 13:46:38 -04:00
{
* first_unparsed = expression_cstr ;
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonEmptyRangeNotAllowed ;
* final_result = ValueObject : : eExpressionPathEndResultTypeInvalid ;
return ValueObjectSP ( ) ;
}
else // even if something follows, we cannot expand unbounded ranges, just let the caller do it
{
* first_unparsed = expression_cstr + 2 ;
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonArrayRangeOperatorMet ;
* final_result = ValueObject : : eExpressionPathEndResultTypeUnboundedRange ;
return root ;
}
}
const char * separator_position = : : strchr ( expression_cstr + 1 , ' - ' ) ;
const char * close_bracket_position = : : strchr ( expression_cstr + 1 , ' ] ' ) ;
if ( ! close_bracket_position ) // if there is no ], this is a syntax error
{
* first_unparsed = expression_cstr ;
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonUnexpectedSymbol ;
* final_result = ValueObject : : eExpressionPathEndResultTypeInvalid ;
return ValueObjectSP ( ) ;
}
if ( ! separator_position | | separator_position > close_bracket_position ) // if no separator, this is either [] or [N]
{
char * end = NULL ;
unsigned long index = : : strtoul ( expression_cstr + 1 , & end , 0 ) ;
if ( ! end | | end ! = close_bracket_position ) // if something weird is in our way return an error
{
* first_unparsed = expression_cstr ;
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonUnexpectedSymbol ;
* final_result = ValueObject : : eExpressionPathEndResultTypeInvalid ;
return ValueObjectSP ( ) ;
}
if ( end - expression_cstr = = 1 ) // if this is [], only return a valid value for arrays
{
2015-02-06 16:38:51 -05:00
if ( root_clang_type_info . Test ( eTypeIsArray ) )
2013-08-23 13:46:38 -04:00
{
* first_unparsed = expression_cstr + 2 ;
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonArrayRangeOperatorMet ;
* final_result = ValueObject : : eExpressionPathEndResultTypeUnboundedRange ;
return root ;
}
else
{
* first_unparsed = expression_cstr ;
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonEmptyRangeNotAllowed ;
* final_result = ValueObject : : eExpressionPathEndResultTypeInvalid ;
return ValueObjectSP ( ) ;
}
}
// from here on we do have a valid index
2015-02-06 16:38:51 -05:00
if ( root_clang_type_info . Test ( eTypeIsArray ) )
2013-08-23 13:46:38 -04:00
{
ValueObjectSP child_valobj_sp = root - > GetChildAtIndex ( index , true ) ;
if ( ! child_valobj_sp )
child_valobj_sp = root - > GetSyntheticArrayMemberFromArray ( index , true ) ;
if ( ! child_valobj_sp )
if ( root - > HasSyntheticValue ( ) & & root - > GetSyntheticValue ( ) - > GetNumChildren ( ) > index )
child_valobj_sp = root - > GetSyntheticValue ( ) - > GetChildAtIndex ( index , true ) ;
if ( child_valobj_sp )
{
root = child_valobj_sp ;
* first_unparsed = end + 1 ; // skip ]
* final_result = ValueObject : : eExpressionPathEndResultTypePlain ;
continue ;
}
else
{
* first_unparsed = expression_cstr ;
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonNoSuchChild ;
* final_result = ValueObject : : eExpressionPathEndResultTypeInvalid ;
return ValueObjectSP ( ) ;
}
}
2015-02-06 16:38:51 -05:00
else if ( root_clang_type_info . Test ( eTypeIsPointer ) )
2013-08-23 13:46:38 -04:00
{
if ( * what_next = = ValueObject : : eExpressionPathAftermathDereference & & // if this is a ptr-to-scalar, I am accessing it by index and I would have deref'ed anyway, then do it now and use this as a bitfield
2015-02-06 16:38:51 -05:00
pointee_clang_type_info . Test ( eTypeIsScalar ) )
2013-08-23 13:46:38 -04:00
{
Error error ;
root = root - > Dereference ( error ) ;
if ( error . Fail ( ) | | ! root . get ( ) )
{
* first_unparsed = expression_cstr ;
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonDereferencingFailed ;
* final_result = ValueObject : : eExpressionPathEndResultTypeInvalid ;
return ValueObjectSP ( ) ;
}
else
{
* what_next = eExpressionPathAftermathNothing ;
continue ;
}
}
else
{
if ( root - > GetClangType ( ) . GetMinimumLanguage ( ) = = eLanguageTypeObjC
2015-02-06 16:38:51 -05:00
& & pointee_clang_type_info . AllClear ( eTypeIsPointer )
2013-08-23 13:46:38 -04:00
& & root - > HasSyntheticValue ( )
& & options . m_no_synthetic_children = = false )
{
root = root - > GetSyntheticValue ( ) - > GetChildAtIndex ( index , true ) ;
}
else
root = root - > GetSyntheticArrayMemberFromPointer ( index , true ) ;
if ( ! root . get ( ) )
{
* first_unparsed = expression_cstr ;
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonNoSuchChild ;
* final_result = ValueObject : : eExpressionPathEndResultTypeInvalid ;
return ValueObjectSP ( ) ;
}
else
{
* first_unparsed = end + 1 ; // skip ]
* final_result = ValueObject : : eExpressionPathEndResultTypePlain ;
continue ;
}
}
}
2015-02-06 16:38:51 -05:00
else if ( root_clang_type_info . Test ( eTypeIsScalar ) )
2013-08-23 13:46:38 -04:00
{
root = root - > GetSyntheticBitFieldChild ( index , index , true ) ;
if ( ! root . get ( ) )
{
* first_unparsed = expression_cstr ;
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonNoSuchChild ;
* final_result = ValueObject : : eExpressionPathEndResultTypeInvalid ;
return ValueObjectSP ( ) ;
}
else // we do not know how to expand members of bitfields, so we just return and let the caller do any further processing
{
* first_unparsed = end + 1 ; // skip ]
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonBitfieldRangeOperatorMet ;
* final_result = ValueObject : : eExpressionPathEndResultTypeBitfield ;
return root ;
}
}
2015-02-06 16:38:51 -05:00
else if ( root_clang_type_info . Test ( eTypeIsVector ) )
2013-08-23 13:46:38 -04:00
{
root = root - > GetChildAtIndex ( index , true ) ;
if ( ! root . get ( ) )
{
* first_unparsed = expression_cstr ;
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonNoSuchChild ;
* final_result = ValueObject : : eExpressionPathEndResultTypeInvalid ;
return ValueObjectSP ( ) ;
}
else
{
* first_unparsed = end + 1 ; // skip ]
* final_result = ValueObject : : eExpressionPathEndResultTypePlain ;
continue ;
}
}
else if ( options . m_no_synthetic_children = = false )
{
if ( root - > HasSyntheticValue ( ) )
root = root - > GetSyntheticValue ( ) ;
else if ( ! root - > IsSynthetic ( ) )
{
* first_unparsed = expression_cstr ;
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonSyntheticValueMissing ;
* final_result = ValueObject : : eExpressionPathEndResultTypeInvalid ;
return ValueObjectSP ( ) ;
}
// if we are here, then root itself is a synthetic VO.. should be good to go
if ( ! root . get ( ) )
{
* first_unparsed = expression_cstr ;
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonSyntheticValueMissing ;
* final_result = ValueObject : : eExpressionPathEndResultTypeInvalid ;
return ValueObjectSP ( ) ;
}
root = root - > GetChildAtIndex ( index , true ) ;
if ( ! root . get ( ) )
{
* first_unparsed = expression_cstr ;
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonNoSuchChild ;
* final_result = ValueObject : : eExpressionPathEndResultTypeInvalid ;
return ValueObjectSP ( ) ;
}
else
{
* first_unparsed = end + 1 ; // skip ]
* final_result = ValueObject : : eExpressionPathEndResultTypePlain ;
continue ;
}
}
else
{
* first_unparsed = expression_cstr ;
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonNoSuchChild ;
* final_result = ValueObject : : eExpressionPathEndResultTypeInvalid ;
return ValueObjectSP ( ) ;
}
}
else // we have a low and a high index
{
char * end = NULL ;
unsigned long index_lower = : : strtoul ( expression_cstr + 1 , & end , 0 ) ;
if ( ! end | | end ! = separator_position ) // if something weird is in our way return an error
{
* first_unparsed = expression_cstr ;
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonUnexpectedSymbol ;
* final_result = ValueObject : : eExpressionPathEndResultTypeInvalid ;
return ValueObjectSP ( ) ;
}
unsigned long index_higher = : : strtoul ( separator_position + 1 , & end , 0 ) ;
if ( ! end | | end ! = close_bracket_position ) // if something weird is in our way return an error
{
* first_unparsed = expression_cstr ;
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonUnexpectedSymbol ;
* final_result = ValueObject : : eExpressionPathEndResultTypeInvalid ;
return ValueObjectSP ( ) ;
}
if ( index_lower > index_higher ) // swap indices if required
{
unsigned long temp = index_lower ;
index_lower = index_higher ;
index_higher = temp ;
}
2015-02-06 16:38:51 -05:00
if ( root_clang_type_info . Test ( eTypeIsScalar ) ) // expansion only works for scalars
2013-08-23 13:46:38 -04:00
{
root = root - > GetSyntheticBitFieldChild ( index_lower , index_higher , true ) ;
if ( ! root . get ( ) )
{
* first_unparsed = expression_cstr ;
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonNoSuchChild ;
* final_result = ValueObject : : eExpressionPathEndResultTypeInvalid ;
return ValueObjectSP ( ) ;
}
else
{
* first_unparsed = end + 1 ; // skip ]
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonBitfieldRangeOperatorMet ;
* final_result = ValueObject : : eExpressionPathEndResultTypeBitfield ;
return root ;
}
}
2015-02-06 16:38:51 -05:00
else if ( root_clang_type_info . Test ( eTypeIsPointer ) & & // if this is a ptr-to-scalar, I am accessing it by index and I would have deref'ed anyway, then do it now and use this as a bitfield
2013-08-23 13:46:38 -04:00
* what_next = = ValueObject : : eExpressionPathAftermathDereference & &
2015-02-06 16:38:51 -05:00
pointee_clang_type_info . Test ( eTypeIsScalar ) )
2013-08-23 13:46:38 -04:00
{
Error error ;
root = root - > Dereference ( error ) ;
if ( error . Fail ( ) | | ! root . get ( ) )
{
* first_unparsed = expression_cstr ;
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonDereferencingFailed ;
* final_result = ValueObject : : eExpressionPathEndResultTypeInvalid ;
return ValueObjectSP ( ) ;
}
else
{
* what_next = ValueObject : : eExpressionPathAftermathNothing ;
continue ;
}
}
else
{
* first_unparsed = expression_cstr ;
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonArrayRangeOperatorMet ;
* final_result = ValueObject : : eExpressionPathEndResultTypeBoundedRange ;
return root ;
}
}
break ;
}
default : // some non-separator is in the way
{
* first_unparsed = expression_cstr ;
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonUnexpectedSymbol ;
* final_result = ValueObject : : eExpressionPathEndResultTypeInvalid ;
return ValueObjectSP ( ) ;
break ;
}
}
}
}
int
ValueObject : : ExpandArraySliceExpression ( const char * expression_cstr ,
const char * * first_unparsed ,
ValueObjectSP root ,
ValueObjectListSP & list ,
ExpressionPathScanEndReason * reason_to_stop ,
ExpressionPathEndResultType * final_result ,
const GetValueForExpressionPathOptions & options ,
ExpressionPathAftermath * what_next )
{
if ( ! root . get ( ) )
return 0 ;
* first_unparsed = expression_cstr ;
while ( true )
{
const char * expression_cstr = * first_unparsed ; // hide the top level expression_cstr
ClangASTType root_clang_type = root - > GetClangType ( ) ;
ClangASTType pointee_clang_type ;
Flags pointee_clang_type_info ;
Flags root_clang_type_info ( root_clang_type . GetTypeInfo ( & pointee_clang_type ) ) ;
if ( pointee_clang_type )
pointee_clang_type_info . Reset ( pointee_clang_type . GetTypeInfo ( ) ) ;
if ( ! expression_cstr | | * expression_cstr = = ' \0 ' )
{
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonEndOfString ;
list - > Append ( root ) ;
return 1 ;
}
switch ( * expression_cstr )
{
case ' [ ' :
{
2015-02-06 16:38:51 -05:00
if ( ! root_clang_type_info . Test ( eTypeIsArray ) & & ! root_clang_type_info . Test ( eTypeIsPointer ) ) // if this is not a T[] nor a T*
2013-08-23 13:46:38 -04:00
{
2015-02-06 16:38:51 -05:00
if ( ! root_clang_type_info . Test ( eTypeIsScalar ) ) // if this is not even a scalar, this syntax is just plain wrong!
2013-08-23 13:46:38 -04:00
{
* first_unparsed = expression_cstr ;
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonRangeOperatorInvalid ;
* final_result = ValueObject : : eExpressionPathEndResultTypeInvalid ;
return 0 ;
}
else if ( ! options . m_allow_bitfields_syntax ) // if this is a scalar, check that we can expand bitfields
{
* first_unparsed = expression_cstr ;
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonRangeOperatorNotAllowed ;
* final_result = ValueObject : : eExpressionPathEndResultTypeInvalid ;
return 0 ;
}
}
if ( * ( expression_cstr + 1 ) = = ' ] ' ) // if this is an unbounded range it only works for arrays
{
2015-02-06 16:38:51 -05:00
if ( ! root_clang_type_info . Test ( eTypeIsArray ) )
2013-08-23 13:46:38 -04:00
{
* first_unparsed = expression_cstr ;
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonEmptyRangeNotAllowed ;
* final_result = ValueObject : : eExpressionPathEndResultTypeInvalid ;
return 0 ;
}
else // expand this into list
{
const size_t max_index = root - > GetNumChildren ( ) - 1 ;
for ( size_t index = 0 ; index < max_index ; index + + )
{
ValueObjectSP child =
root - > GetChildAtIndex ( index , true ) ;
list - > Append ( child ) ;
}
* first_unparsed = expression_cstr + 2 ;
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonRangeOperatorExpanded ;
* final_result = ValueObject : : eExpressionPathEndResultTypeValueObjectList ;
return max_index ; // tell me number of items I added to the VOList
}
}
const char * separator_position = : : strchr ( expression_cstr + 1 , ' - ' ) ;
const char * close_bracket_position = : : strchr ( expression_cstr + 1 , ' ] ' ) ;
if ( ! close_bracket_position ) // if there is no ], this is a syntax error
{
* first_unparsed = expression_cstr ;
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonUnexpectedSymbol ;
* final_result = ValueObject : : eExpressionPathEndResultTypeInvalid ;
return 0 ;
}
if ( ! separator_position | | separator_position > close_bracket_position ) // if no separator, this is either [] or [N]
{
char * end = NULL ;
unsigned long index = : : strtoul ( expression_cstr + 1 , & end , 0 ) ;
if ( ! end | | end ! = close_bracket_position ) // if something weird is in our way return an error
{
* first_unparsed = expression_cstr ;
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonUnexpectedSymbol ;
* final_result = ValueObject : : eExpressionPathEndResultTypeInvalid ;
return 0 ;
}
if ( end - expression_cstr = = 1 ) // if this is [], only return a valid value for arrays
{
2015-02-06 16:38:51 -05:00
if ( root_clang_type_info . Test ( eTypeIsArray ) )
2013-08-23 13:46:38 -04:00
{
const size_t max_index = root - > GetNumChildren ( ) - 1 ;
for ( size_t index = 0 ; index < max_index ; index + + )
{
ValueObjectSP child =
root - > GetChildAtIndex ( index , true ) ;
list - > Append ( child ) ;
}
* first_unparsed = expression_cstr + 2 ;
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonRangeOperatorExpanded ;
* final_result = ValueObject : : eExpressionPathEndResultTypeValueObjectList ;
return max_index ; // tell me number of items I added to the VOList
}
else
{
* first_unparsed = expression_cstr ;
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonEmptyRangeNotAllowed ;
* final_result = ValueObject : : eExpressionPathEndResultTypeInvalid ;
return 0 ;
}
}
// from here on we do have a valid index
2015-02-06 16:38:51 -05:00
if ( root_clang_type_info . Test ( eTypeIsArray ) )
2013-08-23 13:46:38 -04:00
{
root = root - > GetChildAtIndex ( index , true ) ;
if ( ! root . get ( ) )
{
* first_unparsed = expression_cstr ;
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonNoSuchChild ;
* final_result = ValueObject : : eExpressionPathEndResultTypeInvalid ;
return 0 ;
}
else
{
list - > Append ( root ) ;
* first_unparsed = end + 1 ; // skip ]
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonRangeOperatorExpanded ;
* final_result = ValueObject : : eExpressionPathEndResultTypeValueObjectList ;
return 1 ;
}
}
2015-02-06 16:38:51 -05:00
else if ( root_clang_type_info . Test ( eTypeIsPointer ) )
2013-08-23 13:46:38 -04:00
{
if ( * what_next = = ValueObject : : eExpressionPathAftermathDereference & & // if this is a ptr-to-scalar, I am accessing it by index and I would have deref'ed anyway, then do it now and use this as a bitfield
2015-02-06 16:38:51 -05:00
pointee_clang_type_info . Test ( eTypeIsScalar ) )
2013-08-23 13:46:38 -04:00
{
Error error ;
root = root - > Dereference ( error ) ;
if ( error . Fail ( ) | | ! root . get ( ) )
{
* first_unparsed = expression_cstr ;
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonDereferencingFailed ;
* final_result = ValueObject : : eExpressionPathEndResultTypeInvalid ;
return 0 ;
}
else
{
* what_next = eExpressionPathAftermathNothing ;
continue ;
}
}
else
{
root = root - > GetSyntheticArrayMemberFromPointer ( index , true ) ;
if ( ! root . get ( ) )
{
* first_unparsed = expression_cstr ;
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonNoSuchChild ;
* final_result = ValueObject : : eExpressionPathEndResultTypeInvalid ;
return 0 ;
}
else
{
list - > Append ( root ) ;
* first_unparsed = end + 1 ; // skip ]
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonRangeOperatorExpanded ;
* final_result = ValueObject : : eExpressionPathEndResultTypeValueObjectList ;
return 1 ;
}
}
}
else /*if (ClangASTContext::IsScalarType(root_clang_type))*/
{
root = root - > GetSyntheticBitFieldChild ( index , index , true ) ;
if ( ! root . get ( ) )
{
* first_unparsed = expression_cstr ;
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonNoSuchChild ;
* final_result = ValueObject : : eExpressionPathEndResultTypeInvalid ;
return 0 ;
}
else // we do not know how to expand members of bitfields, so we just return and let the caller do any further processing
{
list - > Append ( root ) ;
* first_unparsed = end + 1 ; // skip ]
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonRangeOperatorExpanded ;
* final_result = ValueObject : : eExpressionPathEndResultTypeValueObjectList ;
return 1 ;
}
}
}
else // we have a low and a high index
{
char * end = NULL ;
unsigned long index_lower = : : strtoul ( expression_cstr + 1 , & end , 0 ) ;
if ( ! end | | end ! = separator_position ) // if something weird is in our way return an error
{
* first_unparsed = expression_cstr ;
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonUnexpectedSymbol ;
* final_result = ValueObject : : eExpressionPathEndResultTypeInvalid ;
return 0 ;
}
unsigned long index_higher = : : strtoul ( separator_position + 1 , & end , 0 ) ;
if ( ! end | | end ! = close_bracket_position ) // if something weird is in our way return an error
{
* first_unparsed = expression_cstr ;
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonUnexpectedSymbol ;
* final_result = ValueObject : : eExpressionPathEndResultTypeInvalid ;
return 0 ;
}
if ( index_lower > index_higher ) // swap indices if required
{
unsigned long temp = index_lower ;
index_lower = index_higher ;
index_higher = temp ;
}
2015-02-06 16:38:51 -05:00
if ( root_clang_type_info . Test ( eTypeIsScalar ) ) // expansion only works for scalars
2013-08-23 13:46:38 -04:00
{
root = root - > GetSyntheticBitFieldChild ( index_lower , index_higher , true ) ;
if ( ! root . get ( ) )
{
* first_unparsed = expression_cstr ;
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonNoSuchChild ;
* final_result = ValueObject : : eExpressionPathEndResultTypeInvalid ;
return 0 ;
}
else
{
list - > Append ( root ) ;
* first_unparsed = end + 1 ; // skip ]
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonRangeOperatorExpanded ;
* final_result = ValueObject : : eExpressionPathEndResultTypeValueObjectList ;
return 1 ;
}
}
2015-02-06 16:38:51 -05:00
else if ( root_clang_type_info . Test ( eTypeIsPointer ) & & // if this is a ptr-to-scalar, I am accessing it by index and I would have deref'ed anyway, then do it now and use this as a bitfield
2013-08-23 13:46:38 -04:00
* what_next = = ValueObject : : eExpressionPathAftermathDereference & &
2015-02-06 16:38:51 -05:00
pointee_clang_type_info . Test ( eTypeIsScalar ) )
2013-08-23 13:46:38 -04:00
{
Error error ;
root = root - > Dereference ( error ) ;
if ( error . Fail ( ) | | ! root . get ( ) )
{
* first_unparsed = expression_cstr ;
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonDereferencingFailed ;
* final_result = ValueObject : : eExpressionPathEndResultTypeInvalid ;
return 0 ;
}
else
{
* what_next = ValueObject : : eExpressionPathAftermathNothing ;
continue ;
}
}
else
{
for ( unsigned long index = index_lower ;
index < = index_higher ; index + + )
{
ValueObjectSP child =
root - > GetChildAtIndex ( index , true ) ;
list - > Append ( child ) ;
}
* first_unparsed = end + 1 ;
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonRangeOperatorExpanded ;
* final_result = ValueObject : : eExpressionPathEndResultTypeValueObjectList ;
return index_higher - index_lower + 1 ; // tell me number of items I added to the VOList
}
}
break ;
}
default : // some non-[ separator, or something entirely wrong, is in the way
{
* first_unparsed = expression_cstr ;
* reason_to_stop = ValueObject : : eExpressionPathScanEndReasonUnexpectedSymbol ;
* final_result = ValueObject : : eExpressionPathEndResultTypeInvalid ;
return 0 ;
break ;
}
}
}
}
void
2013-11-06 11:48:53 -05:00
ValueObject : : LogValueObject ( Log * log )
2013-08-23 13:46:38 -04:00
{
2013-11-06 11:48:53 -05:00
if ( log )
return LogValueObject ( log , DumpValueObjectOptions : : DefaultOptions ( ) ) ;
2013-08-23 13:46:38 -04:00
}
void
2013-11-06 11:48:53 -05:00
ValueObject : : LogValueObject ( Log * log , const DumpValueObjectOptions & options )
2013-08-23 13:46:38 -04:00
{
2013-11-06 11:48:53 -05:00
if ( log )
2013-08-23 13:46:38 -04:00
{
StreamString s ;
2013-11-06 11:48:53 -05:00
Dump ( s , options ) ;
2013-08-23 13:46:38 -04:00
if ( s . GetSize ( ) )
log - > PutCString ( s . GetData ( ) ) ;
}
}
void
2013-11-06 11:48:53 -05:00
ValueObject : : Dump ( Stream & s )
2013-08-23 13:46:38 -04:00
{
2015-02-06 16:38:51 -05:00
Dump ( s , DumpValueObjectOptions : : DefaultOptions ( ) ) ;
2013-08-23 13:46:38 -04:00
}
void
2013-11-06 11:48:53 -05:00
ValueObject : : Dump ( Stream & s ,
const DumpValueObjectOptions & options )
{
ValueObjectPrinter printer ( this , & s , options ) ;
printer . PrintValueObject ( ) ;
2013-08-23 13:46:38 -04:00
}
ValueObjectSP
ValueObject : : CreateConstantValue ( const ConstString & name )
{
ValueObjectSP valobj_sp ;
if ( UpdateValueIfNeeded ( false ) & & m_error . Success ( ) )
{
ExecutionContext exe_ctx ( GetExecutionContextRef ( ) ) ;
DataExtractor data ;
data . SetByteOrder ( m_data . GetByteOrder ( ) ) ;
data . SetAddressByteSize ( m_data . GetAddressByteSize ( ) ) ;
if ( IsBitfield ( ) )
{
Value v ( Scalar ( GetValueAsUnsigned ( UINT64_MAX ) ) ) ;
m_error = v . GetValueAsData ( & exe_ctx , data , 0 , GetModule ( ) . get ( ) ) ;
}
else
m_error = m_value . GetValueAsData ( & exe_ctx , data , 0 , GetModule ( ) . get ( ) ) ;
valobj_sp = ValueObjectConstResult : : Create ( exe_ctx . GetBestExecutionContextScope ( ) ,
GetClangType ( ) ,
name ,
data ,
GetAddressOf ( ) ) ;
}
if ( ! valobj_sp )
{
2014-02-18 11:23:10 -05:00
ExecutionContext exe_ctx ( GetExecutionContextRef ( ) ) ;
valobj_sp = ValueObjectConstResult : : Create ( exe_ctx . GetBestExecutionContextScope ( ) , m_error ) ;
2013-08-23 13:46:38 -04:00
}
return valobj_sp ;
}
2015-02-06 16:38:51 -05:00
ValueObjectSP
ValueObject : : GetQualifiedRepresentationIfAvailable ( lldb : : DynamicValueType dynValue ,
bool synthValue )
{
ValueObjectSP result_sp ( GetSP ( ) ) ;
switch ( dynValue )
{
case lldb : : eDynamicCanRunTarget :
case lldb : : eDynamicDontRunTarget :
{
if ( ! result_sp - > IsDynamic ( ) )
{
if ( result_sp - > GetDynamicValue ( dynValue ) )
result_sp = result_sp - > GetDynamicValue ( dynValue ) ;
}
}
break ;
case lldb : : eNoDynamicValues :
{
if ( result_sp - > IsDynamic ( ) )
{
if ( result_sp - > GetStaticValue ( ) )
result_sp = result_sp - > GetStaticValue ( ) ;
}
}
break ;
}
if ( synthValue )
{
if ( ! result_sp - > IsSynthetic ( ) )
{
if ( result_sp - > GetSyntheticValue ( ) )
result_sp = result_sp - > GetSyntheticValue ( ) ;
}
}
else
{
if ( result_sp - > IsSynthetic ( ) )
{
if ( result_sp - > GetNonSyntheticValue ( ) )
result_sp = result_sp - > GetNonSyntheticValue ( ) ;
}
}
return result_sp ;
}
2014-11-25 16:00:58 -05:00
lldb : : addr_t
ValueObject : : GetCPPVTableAddress ( AddressType & address_type )
{
ClangASTType pointee_type ;
ClangASTType this_type ( GetClangType ( ) ) ;
uint32_t type_info = this_type . GetTypeInfo ( & pointee_type ) ;
if ( type_info )
{
bool ptr_or_ref = false ;
2015-02-06 16:38:51 -05:00
if ( type_info & ( eTypeIsPointer | eTypeIsReference ) )
2014-11-25 16:00:58 -05:00
{
ptr_or_ref = true ;
type_info = pointee_type . GetTypeInfo ( ) ;
}
2015-02-06 16:38:51 -05:00
const uint32_t cpp_class = eTypeIsClass | eTypeIsCPlusPlus ;
2014-11-25 16:00:58 -05:00
if ( ( type_info & cpp_class ) = = cpp_class )
{
if ( ptr_or_ref )
{
address_type = GetAddressTypeOfChildren ( ) ;
return GetValueAsUnsigned ( LLDB_INVALID_ADDRESS ) ;
}
else
return GetAddressOf ( false , & address_type ) ;
}
}
address_type = eAddressTypeInvalid ;
return LLDB_INVALID_ADDRESS ;
}
2013-08-23 13:46:38 -04:00
ValueObjectSP
ValueObject : : Dereference ( Error & error )
{
if ( m_deref_valobj )
return m_deref_valobj - > GetSP ( ) ;
const bool is_pointer_type = IsPointerType ( ) ;
if ( is_pointer_type )
{
bool omit_empty_base_classes = true ;
bool ignore_array_bounds = false ;
std : : string child_name_str ;
uint32_t child_byte_size = 0 ;
int32_t child_byte_offset = 0 ;
uint32_t child_bitfield_bit_size = 0 ;
uint32_t child_bitfield_bit_offset = 0 ;
bool child_is_base_class = false ;
bool child_is_deref_of_parent = false ;
const bool transparent_pointers = false ;
ClangASTType clang_type = GetClangType ( ) ;
ClangASTType child_clang_type ;
ExecutionContext exe_ctx ( GetExecutionContextRef ( ) ) ;
child_clang_type = clang_type . GetChildClangTypeAtIndex ( & exe_ctx ,
0 ,
transparent_pointers ,
omit_empty_base_classes ,
ignore_array_bounds ,
child_name_str ,
child_byte_size ,
child_byte_offset ,
child_bitfield_bit_size ,
child_bitfield_bit_offset ,
child_is_base_class ,
2014-11-25 16:00:58 -05:00
child_is_deref_of_parent ,
this ) ;
2013-08-23 13:46:38 -04:00
if ( child_clang_type & & child_byte_size )
{
ConstString child_name ;
if ( ! child_name_str . empty ( ) )
child_name . SetCString ( child_name_str . c_str ( ) ) ;
m_deref_valobj = new ValueObjectChild ( * this ,
child_clang_type ,
child_name ,
child_byte_size ,
child_byte_offset ,
child_bitfield_bit_size ,
child_bitfield_bit_offset ,
child_is_base_class ,
child_is_deref_of_parent ,
eAddressTypeInvalid ) ;
}
}
if ( m_deref_valobj )
{
error . Clear ( ) ;
return m_deref_valobj - > GetSP ( ) ;
}
else
{
StreamString strm ;
GetExpressionPath ( strm , true ) ;
if ( is_pointer_type )
error . SetErrorStringWithFormat ( " dereference failed: (%s) %s " , GetTypeName ( ) . AsCString ( " <invalid type> " ) , strm . GetString ( ) . c_str ( ) ) ;
else
error . SetErrorStringWithFormat ( " not a pointer type: (%s) %s " , GetTypeName ( ) . AsCString ( " <invalid type> " ) , strm . GetString ( ) . c_str ( ) ) ;
return ValueObjectSP ( ) ;
}
}
ValueObjectSP
ValueObject : : AddressOf ( Error & error )
{
if ( m_addr_of_valobj_sp )
return m_addr_of_valobj_sp ;
AddressType address_type = eAddressTypeInvalid ;
const bool scalar_is_load_address = false ;
addr_t addr = GetAddressOf ( scalar_is_load_address , & address_type ) ;
error . Clear ( ) ;
if ( addr ! = LLDB_INVALID_ADDRESS )
{
switch ( address_type )
{
case eAddressTypeInvalid :
{
StreamString expr_path_strm ;
GetExpressionPath ( expr_path_strm , true ) ;
error . SetErrorStringWithFormat ( " '%s' is not in memory " , expr_path_strm . GetString ( ) . c_str ( ) ) ;
}
break ;
case eAddressTypeFile :
case eAddressTypeLoad :
case eAddressTypeHost :
{
ClangASTType clang_type = GetClangType ( ) ;
if ( clang_type )
{
std : : string name ( 1 , ' & ' ) ;
name . append ( m_name . AsCString ( " " ) ) ;
ExecutionContext exe_ctx ( GetExecutionContextRef ( ) ) ;
m_addr_of_valobj_sp = ValueObjectConstResult : : Create ( exe_ctx . GetBestExecutionContextScope ( ) ,
clang_type . GetPointerType ( ) ,
ConstString ( name . c_str ( ) ) ,
addr ,
eAddressTypeInvalid ,
m_data . GetAddressByteSize ( ) ) ;
}
}
break ;
}
}
else
{
StreamString expr_path_strm ;
GetExpressionPath ( expr_path_strm , true ) ;
error . SetErrorStringWithFormat ( " '%s' doesn't have a valid address " , expr_path_strm . GetString ( ) . c_str ( ) ) ;
}
return m_addr_of_valobj_sp ;
}
ValueObjectSP
ValueObject : : Cast ( const ClangASTType & clang_ast_type )
{
return ValueObjectCast : : Create ( * this , GetName ( ) , clang_ast_type ) ;
}
ValueObjectSP
ValueObject : : CastPointerType ( const char * name , ClangASTType & clang_ast_type )
{
ValueObjectSP valobj_sp ;
AddressType address_type ;
addr_t ptr_value = GetPointerValue ( & address_type ) ;
if ( ptr_value ! = LLDB_INVALID_ADDRESS )
{
Address ptr_addr ( ptr_value ) ;
ExecutionContext exe_ctx ( GetExecutionContextRef ( ) ) ;
valobj_sp = ValueObjectMemory : : Create ( exe_ctx . GetBestExecutionContextScope ( ) ,
name ,
ptr_addr ,
clang_ast_type ) ;
}
return valobj_sp ;
}
ValueObjectSP
ValueObject : : CastPointerType ( const char * name , TypeSP & type_sp )
{
ValueObjectSP valobj_sp ;
AddressType address_type ;
addr_t ptr_value = GetPointerValue ( & address_type ) ;
if ( ptr_value ! = LLDB_INVALID_ADDRESS )
{
Address ptr_addr ( ptr_value ) ;
ExecutionContext exe_ctx ( GetExecutionContextRef ( ) ) ;
valobj_sp = ValueObjectMemory : : Create ( exe_ctx . GetBestExecutionContextScope ( ) ,
name ,
ptr_addr ,
type_sp ) ;
}
return valobj_sp ;
}
ValueObject : : EvaluationPoint : : EvaluationPoint ( ) :
m_mod_id ( ) ,
m_exe_ctx_ref ( ) ,
2015-02-06 16:38:51 -05:00
m_needs_update ( true )
2013-08-23 13:46:38 -04:00
{
}
ValueObject : : EvaluationPoint : : EvaluationPoint ( ExecutionContextScope * exe_scope , bool use_selected ) :
m_mod_id ( ) ,
m_exe_ctx_ref ( ) ,
2015-02-06 16:38:51 -05:00
m_needs_update ( true )
2013-08-23 13:46:38 -04:00
{
ExecutionContext exe_ctx ( exe_scope ) ;
TargetSP target_sp ( exe_ctx . GetTargetSP ( ) ) ;
if ( target_sp )
{
m_exe_ctx_ref . SetTargetSP ( target_sp ) ;
ProcessSP process_sp ( exe_ctx . GetProcessSP ( ) ) ;
if ( ! process_sp )
process_sp = target_sp - > GetProcessSP ( ) ;
if ( process_sp )
{
m_mod_id = process_sp - > GetModID ( ) ;
m_exe_ctx_ref . SetProcessSP ( process_sp ) ;
ThreadSP thread_sp ( exe_ctx . GetThreadSP ( ) ) ;
if ( ! thread_sp )
{
if ( use_selected )
thread_sp = process_sp - > GetThreadList ( ) . GetSelectedThread ( ) ;
}
if ( thread_sp )
{
m_exe_ctx_ref . SetThreadSP ( thread_sp ) ;
StackFrameSP frame_sp ( exe_ctx . GetFrameSP ( ) ) ;
if ( ! frame_sp )
{
if ( use_selected )
frame_sp = thread_sp - > GetSelectedFrame ( ) ;
}
if ( frame_sp )
m_exe_ctx_ref . SetFrameSP ( frame_sp ) ;
}
}
}
}
ValueObject : : EvaluationPoint : : EvaluationPoint ( const ValueObject : : EvaluationPoint & rhs ) :
m_mod_id ( ) ,
m_exe_ctx_ref ( rhs . m_exe_ctx_ref ) ,
2015-02-06 16:38:51 -05:00
m_needs_update ( true )
2013-08-23 13:46:38 -04:00
{
}
ValueObject : : EvaluationPoint : : ~ EvaluationPoint ( )
{
}
// This function checks the EvaluationPoint against the current process state. If the current
// state matches the evaluation point, or the evaluation point is already invalid, then we return
// false, meaning "no change". If the current state is different, we update our state, and return
// true meaning "yes, change". If we did see a change, we also set m_needs_update to true, so
// future calls to NeedsUpdate will return true.
// exe_scope will be set to the current execution context scope.
bool
ValueObject : : EvaluationPoint : : SyncWithProcessState ( )
{
// Start with the target, if it is NULL, then we're obviously not going to get any further:
2014-02-18 11:23:10 -05:00
const bool thread_and_frame_only_if_stopped = true ;
ExecutionContext exe_ctx ( m_exe_ctx_ref . Lock ( thread_and_frame_only_if_stopped ) ) ;
2013-08-23 13:46:38 -04:00
if ( exe_ctx . GetTargetPtr ( ) = = NULL )
return false ;
// If we don't have a process nothing can change.
Process * process = exe_ctx . GetProcessPtr ( ) ;
if ( process = = NULL )
return false ;
// If our stop id is the current stop ID, nothing has changed:
ProcessModID current_mod_id = process - > GetModID ( ) ;
// If the current stop id is 0, either we haven't run yet, or the process state has been cleared.
// In either case, we aren't going to be able to sync with the process state.
if ( current_mod_id . GetStopID ( ) = = 0 )
return false ;
bool changed = false ;
const bool was_valid = m_mod_id . IsValid ( ) ;
if ( was_valid )
{
if ( m_mod_id = = current_mod_id )
{
// Everything is already up to date in this object, no need to
// update the execution context scope.
changed = false ;
}
else
{
m_mod_id = current_mod_id ;
m_needs_update = true ;
changed = true ;
}
}
// Now re-look up the thread and frame in case the underlying objects have gone away & been recreated.
// That way we'll be sure to return a valid exe_scope.
// If we used to have a thread or a frame but can't find it anymore, then mark ourselves as invalid.
if ( m_exe_ctx_ref . HasThreadRef ( ) )
{
ThreadSP thread_sp ( m_exe_ctx_ref . GetThreadSP ( ) ) ;
if ( thread_sp )
{
if ( m_exe_ctx_ref . HasFrameRef ( ) )
{
StackFrameSP frame_sp ( m_exe_ctx_ref . GetFrameSP ( ) ) ;
if ( ! frame_sp )
{
// We used to have a frame, but now it is gone
SetInvalid ( ) ;
changed = was_valid ;
}
}
}
else
{
// We used to have a thread, but now it is gone
SetInvalid ( ) ;
changed = was_valid ;
}
}
return changed ;
}
void
ValueObject : : EvaluationPoint : : SetUpdated ( )
{
ProcessSP process_sp ( m_exe_ctx_ref . GetProcessSP ( ) ) ;
if ( process_sp )
m_mod_id = process_sp - > GetModID ( ) ;
m_needs_update = false ;
}
void
ValueObject : : ClearUserVisibleData ( uint32_t clear_mask )
{
if ( ( clear_mask & eClearUserVisibleDataItemsValue ) = = eClearUserVisibleDataItemsValue )
m_value_str . clear ( ) ;
if ( ( clear_mask & eClearUserVisibleDataItemsLocation ) = = eClearUserVisibleDataItemsLocation )
m_location_str . clear ( ) ;
if ( ( clear_mask & eClearUserVisibleDataItemsSummary ) = = eClearUserVisibleDataItemsSummary )
m_summary_str . clear ( ) ;
if ( ( clear_mask & eClearUserVisibleDataItemsDescription ) = = eClearUserVisibleDataItemsDescription )
m_object_desc_str . clear ( ) ;
if ( ( clear_mask & eClearUserVisibleDataItemsSyntheticChildren ) = = eClearUserVisibleDataItemsSyntheticChildren )
{
if ( m_synthetic_value )
m_synthetic_value = NULL ;
}
2015-02-06 16:38:51 -05:00
if ( ( clear_mask & eClearUserVisibleDataItemsValidator ) = = eClearUserVisibleDataItemsValidator )
m_validation_result . reset ( ) ;
2013-08-23 13:46:38 -04:00
}
SymbolContextScope *
ValueObject : : GetSymbolContextScope ( )
{
if ( m_parent )
{
if ( ! m_parent - > IsPointerOrReferenceType ( ) )
return m_parent - > GetSymbolContextScope ( ) ;
}
return NULL ;
}
lldb : : ValueObjectSP
ValueObject : : CreateValueObjectFromExpression ( const char * name ,
const char * expression ,
const ExecutionContext & exe_ctx )
2015-02-06 16:38:51 -05:00
{
return CreateValueObjectFromExpression ( name , expression , exe_ctx , EvaluateExpressionOptions ( ) ) ;
}
lldb : : ValueObjectSP
ValueObject : : CreateValueObjectFromExpression ( const char * name ,
const char * expression ,
const ExecutionContext & exe_ctx ,
const EvaluateExpressionOptions & options )
2013-08-23 13:46:38 -04:00
{
lldb : : ValueObjectSP retval_sp ;
lldb : : TargetSP target_sp ( exe_ctx . GetTargetSP ( ) ) ;
if ( ! target_sp )
return retval_sp ;
if ( ! expression | | ! * expression )
return retval_sp ;
target_sp - > EvaluateExpression ( expression ,
exe_ctx . GetFrameSP ( ) . get ( ) ,
2015-02-06 16:38:51 -05:00
retval_sp ,
options ) ;
2013-08-23 13:46:38 -04:00
if ( retval_sp & & name & & * name )
retval_sp - > SetName ( ConstString ( name ) ) ;
return retval_sp ;
}
lldb : : ValueObjectSP
ValueObject : : CreateValueObjectFromAddress ( const char * name ,
uint64_t address ,
const ExecutionContext & exe_ctx ,
ClangASTType type )
{
if ( type )
{
ClangASTType pointer_type ( type . GetPointerType ( ) ) ;
if ( pointer_type )
{
lldb : : DataBufferSP buffer ( new lldb_private : : DataBufferHeap ( & address , sizeof ( lldb : : addr_t ) ) ) ;
lldb : : ValueObjectSP ptr_result_valobj_sp ( ValueObjectConstResult : : Create ( exe_ctx . GetBestExecutionContextScope ( ) ,
pointer_type ,
ConstString ( name ) ,
buffer ,
2015-02-06 16:38:51 -05:00
exe_ctx . GetByteOrder ( ) ,
2013-08-23 13:46:38 -04:00
exe_ctx . GetAddressByteSize ( ) ) ) ;
if ( ptr_result_valobj_sp )
{
ptr_result_valobj_sp - > GetValue ( ) . SetValueType ( Value : : eValueTypeLoadAddress ) ;
Error err ;
ptr_result_valobj_sp = ptr_result_valobj_sp - > Dereference ( err ) ;
if ( ptr_result_valobj_sp & & name & & * name )
ptr_result_valobj_sp - > SetName ( ConstString ( name ) ) ;
}
return ptr_result_valobj_sp ;
}
}
return lldb : : ValueObjectSP ( ) ;
}
lldb : : ValueObjectSP
ValueObject : : CreateValueObjectFromData ( const char * name ,
2014-11-25 16:00:58 -05:00
const DataExtractor & data ,
2013-08-23 13:46:38 -04:00
const ExecutionContext & exe_ctx ,
ClangASTType type )
{
lldb : : ValueObjectSP new_value_sp ;
new_value_sp = ValueObjectConstResult : : Create ( exe_ctx . GetBestExecutionContextScope ( ) ,
type ,
ConstString ( name ) ,
data ,
LLDB_INVALID_ADDRESS ) ;
new_value_sp - > SetAddressTypeOfChildren ( eAddressTypeLoad ) ;
if ( new_value_sp & & name & & * name )
new_value_sp - > SetName ( ConstString ( name ) ) ;
return new_value_sp ;
}
ModuleSP
ValueObject : : GetModule ( )
{
ValueObject * root ( GetRoot ( ) ) ;
if ( root ! = this )
return root - > GetModule ( ) ;
return lldb : : ModuleSP ( ) ;
}
ValueObject *
ValueObject : : GetRoot ( )
{
if ( m_root )
return m_root ;
2015-02-08 20:44:09 -05:00
return ( m_root = FollowParentChain ( [ ] ( ValueObject * vo ) - > bool {
return ( vo - > m_parent ! = nullptr ) ;
} ) ) ;
}
ValueObject *
ValueObject : : FollowParentChain ( std : : function < bool ( ValueObject * ) > f )
{
ValueObject * vo = this ;
while ( vo )
2013-08-23 13:46:38 -04:00
{
2015-02-08 20:44:09 -05:00
if ( f ( vo ) = = false )
break ;
vo = vo - > m_parent ;
2013-08-23 13:46:38 -04:00
}
2015-02-08 20:44:09 -05:00
return vo ;
2013-08-23 13:46:38 -04:00
}
AddressType
ValueObject : : GetAddressTypeOfChildren ( )
{
if ( m_address_type_of_ptr_or_ref_children = = eAddressTypeInvalid )
{
ValueObject * root ( GetRoot ( ) ) ;
if ( root ! = this )
return root - > GetAddressTypeOfChildren ( ) ;
}
return m_address_type_of_ptr_or_ref_children ;
}
lldb : : DynamicValueType
ValueObject : : GetDynamicValueType ( )
{
ValueObject * with_dv_info = this ;
while ( with_dv_info )
{
if ( with_dv_info - > HasDynamicValueTypeInfo ( ) )
return with_dv_info - > GetDynamicValueTypeImpl ( ) ;
with_dv_info = with_dv_info - > m_parent ;
}
return lldb : : eNoDynamicValues ;
}
lldb : : Format
ValueObject : : GetFormat ( ) const
{
const ValueObject * with_fmt_info = this ;
while ( with_fmt_info )
{
if ( with_fmt_info - > m_format ! = lldb : : eFormatDefault )
return with_fmt_info - > m_format ;
with_fmt_info = with_fmt_info - > m_parent ;
}
return m_format ;
}
2015-02-06 16:38:51 -05:00
lldb : : LanguageType
ValueObject : : GetPreferredDisplayLanguage ( )
{
2015-02-08 20:44:09 -05:00
lldb : : LanguageType type = m_preferred_display_language ;
if ( m_preferred_display_language = = lldb : : eLanguageTypeUnknown )
2015-02-06 16:38:51 -05:00
{
2015-02-08 20:44:09 -05:00
if ( GetRoot ( ) )
2015-02-06 16:38:51 -05:00
{
2015-02-08 20:44:09 -05:00
if ( GetRoot ( ) = = this )
2015-02-06 16:38:51 -05:00
{
2015-02-08 20:44:09 -05:00
if ( StackFrameSP frame_sp = GetFrameSP ( ) )
{
const SymbolContext & sc ( frame_sp - > GetSymbolContext ( eSymbolContextCompUnit ) ) ;
if ( CompileUnit * cu = sc . comp_unit )
type = cu - > GetLanguage ( ) ;
}
}
else
{
type = GetRoot ( ) - > GetPreferredDisplayLanguage ( ) ;
2015-02-06 16:38:51 -05:00
}
}
}
2015-02-08 20:44:09 -05:00
return ( m_preferred_display_language = type ) ; // only compute it once
}
void
ValueObject : : SetPreferredDisplayLanguage ( lldb : : LanguageType lt )
{
m_preferred_display_language = lt ;
2015-02-06 16:38:51 -05:00
}
bool
ValueObject : : CanProvideValue ( )
{
// we need to support invalid types as providers of values because some bare-board
// debugging scenarios have no notion of types, but still manage to have raw numeric
// values for things like registers. sigh.
const ClangASTType & type ( GetClangType ( ) ) ;
return ( false = = type . IsValid ( ) ) | | ( 0 ! = ( type . GetTypeInfo ( ) & eTypeHasValue ) ) ;
}
bool
ValueObject : : IsChecksumEmpty ( )
{
return m_value_checksum . empty ( ) ;
}
ValueObjectSP
ValueObject : : Persist ( )
{
if ( ! UpdateValueIfNeeded ( ) )
return nullptr ;
TargetSP target_sp ( GetTargetSP ( ) ) ;
if ( ! target_sp )
return nullptr ;
ConstString name ( target_sp - > GetPersistentVariables ( ) . GetNextPersistentVariableName ( ) ) ;
ClangExpressionVariableSP clang_var_sp ( new ClangExpressionVariable ( target_sp . get ( ) , GetValue ( ) , name ) ) ;
if ( clang_var_sp )
{
clang_var_sp - > m_live_sp = clang_var_sp - > m_frozen_sp ;
clang_var_sp - > m_flags | = ClangExpressionVariable : : EVIsProgramReference ;
target_sp - > GetPersistentVariables ( ) . AddVariable ( clang_var_sp ) ;
}
return clang_var_sp - > GetValueObject ( ) ;
}
bool
ValueObject : : IsSyntheticChildrenGenerated ( )
{
return m_is_synthetic_children_generated ;
}
void
ValueObject : : SetSyntheticChildrenGenerated ( bool b )
{
m_is_synthetic_children_generated = b ;
}