178a685aaSJim Ingham //===-- ValueObjectDynamicValue.cpp ---------------------------------*- C++ -*-===// 278a685aaSJim Ingham // 378a685aaSJim Ingham // The LLVM Compiler Infrastructure 478a685aaSJim Ingham // 578a685aaSJim Ingham // This file is distributed under the University of Illinois Open Source 678a685aaSJim Ingham // License. See LICENSE.TXT for details. 778a685aaSJim Ingham // 878a685aaSJim Ingham //===----------------------------------------------------------------------===// 978a685aaSJim Ingham 1078a685aaSJim Ingham 1178a685aaSJim Ingham #include "lldb/Core/ValueObjectDynamicValue.h" 1278a685aaSJim Ingham 1378a685aaSJim Ingham // C Includes 1478a685aaSJim Ingham // C++ Includes 1578a685aaSJim Ingham // Other libraries and framework includes 1678a685aaSJim Ingham // Project includes 17*d228483dSEnrico Granata #include "lldb/Core/Log.h" 1878a685aaSJim Ingham #include "lldb/Core/Module.h" 1978a685aaSJim Ingham #include "lldb/Core/ValueObjectList.h" 2078a685aaSJim Ingham #include "lldb/Core/Value.h" 2178a685aaSJim Ingham #include "lldb/Core/ValueObject.h" 2278a685aaSJim Ingham 2378a685aaSJim Ingham #include "lldb/Symbol/ObjectFile.h" 2478a685aaSJim Ingham #include "lldb/Symbol/SymbolContext.h" 2578a685aaSJim Ingham #include "lldb/Symbol/Type.h" 2678a685aaSJim Ingham #include "lldb/Symbol/Variable.h" 2778a685aaSJim Ingham 2878a685aaSJim Ingham #include "lldb/Target/ExecutionContext.h" 2978a685aaSJim Ingham #include "lldb/Target/LanguageRuntime.h" 3078a685aaSJim Ingham #include "lldb/Target/Process.h" 3178a685aaSJim Ingham #include "lldb/Target/RegisterContext.h" 3278a685aaSJim Ingham #include "lldb/Target/Target.h" 3378a685aaSJim Ingham #include "lldb/Target/Thread.h" 3478a685aaSJim Ingham 3578a685aaSJim Ingham 3678a685aaSJim Ingham using namespace lldb_private; 3778a685aaSJim Ingham 3881e871edSGreg Clayton lldb::ValueObjectSP 3981e871edSGreg Clayton ValueObjectCast::Create (ValueObject &parent, 4081e871edSGreg Clayton const ConstString &name, 4181e871edSGreg Clayton const ClangASTType &cast_type) 4281e871edSGreg Clayton { 4381e871edSGreg Clayton ValueObjectCast *cast_valobj_ptr = new ValueObjectCast (parent, name, cast_type); 4481e871edSGreg Clayton return cast_valobj_ptr->GetSP(); 4581e871edSGreg Clayton } 469a142cf8SGreg Clayton 479a142cf8SGreg Clayton ValueObjectCast::ValueObjectCast 489a142cf8SGreg Clayton ( 499a142cf8SGreg Clayton ValueObject &parent, 509a142cf8SGreg Clayton const ConstString &name, 519a142cf8SGreg Clayton const ClangASTType &cast_type 529a142cf8SGreg Clayton ) : 539a142cf8SGreg Clayton ValueObject(parent), 549a142cf8SGreg Clayton m_cast_type (cast_type) 559a142cf8SGreg Clayton { 569a142cf8SGreg Clayton SetName (name); 579a142cf8SGreg Clayton m_value.SetContext (Value::eContextTypeClangType, cast_type.GetOpaqueQualType()); 589a142cf8SGreg Clayton } 599a142cf8SGreg Clayton 609a142cf8SGreg Clayton ValueObjectCast::~ValueObjectCast() 619a142cf8SGreg Clayton { 629a142cf8SGreg Clayton } 639a142cf8SGreg Clayton 649a142cf8SGreg Clayton lldb::clang_type_t 657277284fSSean Callanan ValueObjectCast::GetClangTypeImpl () 669a142cf8SGreg Clayton { 679a142cf8SGreg Clayton return m_cast_type.GetOpaqueQualType(); 689a142cf8SGreg Clayton } 699a142cf8SGreg Clayton 709a142cf8SGreg Clayton uint32_t 719a142cf8SGreg Clayton ValueObjectCast::CalculateNumChildren() 729a142cf8SGreg Clayton { 739a142cf8SGreg Clayton return ClangASTContext::GetNumChildren (GetClangAST (), GetClangType(), true); 749a142cf8SGreg Clayton } 759a142cf8SGreg Clayton 769a142cf8SGreg Clayton clang::ASTContext * 777277284fSSean Callanan ValueObjectCast::GetClangASTImpl () 789a142cf8SGreg Clayton { 799a142cf8SGreg Clayton return m_cast_type.GetASTContext(); 809a142cf8SGreg Clayton } 819a142cf8SGreg Clayton 829a142cf8SGreg Clayton size_t 839a142cf8SGreg Clayton ValueObjectCast::GetByteSize() 849a142cf8SGreg Clayton { 859a142cf8SGreg Clayton return m_value.GetValueByteSize(GetClangAST(), NULL); 869a142cf8SGreg Clayton } 879a142cf8SGreg Clayton 889a142cf8SGreg Clayton lldb::ValueType 899a142cf8SGreg Clayton ValueObjectCast::GetValueType() const 909a142cf8SGreg Clayton { 919a142cf8SGreg Clayton // Let our parent answer global, local, argument, etc... 929a142cf8SGreg Clayton return m_parent->GetValueType(); 939a142cf8SGreg Clayton } 949a142cf8SGreg Clayton 959a142cf8SGreg Clayton bool 969a142cf8SGreg Clayton ValueObjectCast::UpdateValue () 979a142cf8SGreg Clayton { 989a142cf8SGreg Clayton SetValueIsValid (false); 999a142cf8SGreg Clayton m_error.Clear(); 1009a142cf8SGreg Clayton 1019a142cf8SGreg Clayton if (m_parent->UpdateValueIfNeeded(false)) 1029a142cf8SGreg Clayton { 1039a142cf8SGreg Clayton Value old_value(m_value); 1049a142cf8SGreg Clayton m_update_point.SetUpdated(); 1059a142cf8SGreg Clayton m_value = m_parent->GetValue(); 1069a142cf8SGreg Clayton m_value.SetContext (Value::eContextTypeClangType, GetClangType()); 1079a142cf8SGreg Clayton SetAddressTypeOfChildren(m_parent->GetAddressTypeOfChildren()); 1089a142cf8SGreg Clayton if (ClangASTContext::IsAggregateType (GetClangType())) 1099a142cf8SGreg Clayton { 1109a142cf8SGreg Clayton // this value object represents an aggregate type whose 1119a142cf8SGreg Clayton // children have values, but this object does not. So we 1129a142cf8SGreg Clayton // say we are changed if our location has changed. 1139a142cf8SGreg Clayton SetValueDidChange (m_value.GetValueType() != old_value.GetValueType() || m_value.GetScalar() != old_value.GetScalar()); 1149a142cf8SGreg Clayton } 115cc4d0146SGreg Clayton ExecutionContext exe_ctx (GetExecutionContextRef()); 116e72dfb32SGreg Clayton m_error = m_value.GetValueAsData(&exe_ctx, GetClangAST(), m_data, 0, GetModule().get()); 1179a142cf8SGreg Clayton SetValueDidChange (m_parent->GetValueDidChange()); 1189a142cf8SGreg Clayton return true; 1199a142cf8SGreg Clayton } 1209a142cf8SGreg Clayton 1219a142cf8SGreg Clayton // The dynamic value failed to get an error, pass the error along 1229a142cf8SGreg Clayton if (m_error.Success() && m_parent->GetError().Fail()) 1239a142cf8SGreg Clayton m_error = m_parent->GetError(); 1249a142cf8SGreg Clayton SetValueIsValid (false); 1259a142cf8SGreg Clayton return false; 1269a142cf8SGreg Clayton } 1279a142cf8SGreg Clayton 1289a142cf8SGreg Clayton 1299a142cf8SGreg Clayton 1309a142cf8SGreg Clayton bool 1319a142cf8SGreg Clayton ValueObjectCast::IsInScope () 1329a142cf8SGreg Clayton { 1339a142cf8SGreg Clayton return m_parent->IsInScope(); 1349a142cf8SGreg Clayton } 1359a142cf8SGreg Clayton 1369a142cf8SGreg Clayton //---------------------------------------------------------------------- 1379a142cf8SGreg Clayton 1389a142cf8SGreg Clayton 1399a142cf8SGreg Clayton 1409a142cf8SGreg Clayton 1412837b766SJim Ingham ValueObjectDynamicValue::ValueObjectDynamicValue (ValueObject &parent, lldb::DynamicValueType use_dynamic) : 14278a685aaSJim Ingham ValueObject(parent), 14378a685aaSJim Ingham m_address (), 1442837b766SJim Ingham m_type_sp(), 1452837b766SJim Ingham m_use_dynamic (use_dynamic) 14678a685aaSJim Ingham { 147d8b5fce2SEnrico Granata m_last_format_mgr_dynamic = use_dynamic; 1486f3533fbSEnrico Granata SetName (parent.GetName()); 14978a685aaSJim Ingham } 15078a685aaSJim Ingham 15178a685aaSJim Ingham ValueObjectDynamicValue::~ValueObjectDynamicValue() 15278a685aaSJim Ingham { 15378a685aaSJim Ingham m_owning_valobj_sp.reset(); 15478a685aaSJim Ingham } 15578a685aaSJim Ingham 15678a685aaSJim Ingham lldb::clang_type_t 1577277284fSSean Callanan ValueObjectDynamicValue::GetClangTypeImpl () 15878a685aaSJim Ingham { 15978a685aaSJim Ingham if (m_type_sp) 16078a685aaSJim Ingham return m_value.GetClangType(); 16178a685aaSJim Ingham else 16278a685aaSJim Ingham return m_parent->GetClangType(); 16378a685aaSJim Ingham } 16478a685aaSJim Ingham 16578a685aaSJim Ingham ConstString 16678a685aaSJim Ingham ValueObjectDynamicValue::GetTypeName() 16778a685aaSJim Ingham { 168c3e320a7SEnrico Granata const bool success = UpdateValueIfNeeded(false); 1695ad63941SGreg Clayton if (success && m_type_sp) 17084db9105SGreg Clayton return ClangASTType::GetConstTypeName (GetClangAST(), GetClangType()); 17178a685aaSJim Ingham else 17278a685aaSJim Ingham return m_parent->GetTypeName(); 17378a685aaSJim Ingham } 17478a685aaSJim Ingham 17578a685aaSJim Ingham uint32_t 17678a685aaSJim Ingham ValueObjectDynamicValue::CalculateNumChildren() 17778a685aaSJim Ingham { 178c3e320a7SEnrico Granata const bool success = UpdateValueIfNeeded(false); 1795ad63941SGreg Clayton if (success && m_type_sp) 18078a685aaSJim Ingham return ClangASTContext::GetNumChildren (GetClangAST (), GetClangType(), true); 18178a685aaSJim Ingham else 18278a685aaSJim Ingham return m_parent->GetNumChildren(); 18378a685aaSJim Ingham } 18478a685aaSJim Ingham 18578a685aaSJim Ingham clang::ASTContext * 1867277284fSSean Callanan ValueObjectDynamicValue::GetClangASTImpl () 18778a685aaSJim Ingham { 1880a3958e0SEnrico Granata const bool success = UpdateValueIfNeeded(false); 1895ad63941SGreg Clayton if (success && m_type_sp) 19078a685aaSJim Ingham return m_type_sp->GetClangAST(); 19178a685aaSJim Ingham else 19278a685aaSJim Ingham return m_parent->GetClangAST (); 19378a685aaSJim Ingham } 19478a685aaSJim Ingham 19578a685aaSJim Ingham size_t 19678a685aaSJim Ingham ValueObjectDynamicValue::GetByteSize() 19778a685aaSJim Ingham { 198c3e320a7SEnrico Granata const bool success = UpdateValueIfNeeded(false); 1995ad63941SGreg Clayton if (success && m_type_sp) 20078a685aaSJim Ingham return m_value.GetValueByteSize(GetClangAST(), NULL); 20178a685aaSJim Ingham else 20278a685aaSJim Ingham return m_parent->GetByteSize(); 20378a685aaSJim Ingham } 20478a685aaSJim Ingham 20578a685aaSJim Ingham lldb::ValueType 20678a685aaSJim Ingham ValueObjectDynamicValue::GetValueType() const 20778a685aaSJim Ingham { 20878a685aaSJim Ingham return m_parent->GetValueType(); 20978a685aaSJim Ingham } 21078a685aaSJim Ingham 21178a685aaSJim Ingham bool 21278a685aaSJim Ingham ValueObjectDynamicValue::UpdateValue () 21378a685aaSJim Ingham { 21478a685aaSJim Ingham SetValueIsValid (false); 21578a685aaSJim Ingham m_error.Clear(); 21678a685aaSJim Ingham 217c3e320a7SEnrico Granata if (!m_parent->UpdateValueIfNeeded(false)) 21878a685aaSJim Ingham { 219007d5be6SGreg Clayton // The dynamic value failed to get an error, pass the error along 220007d5be6SGreg Clayton if (m_error.Success() && m_parent->GetError().Fail()) 221007d5be6SGreg Clayton m_error = m_parent->GetError(); 22278a685aaSJim Ingham return false; 22378a685aaSJim Ingham } 22478a685aaSJim Ingham 2252837b766SJim Ingham // Setting our type_sp to NULL will route everything back through our 2262837b766SJim Ingham // parent which is equivalent to not using dynamic values. 2272837b766SJim Ingham if (m_use_dynamic == lldb::eNoDynamicValues) 2282837b766SJim Ingham { 2292837b766SJim Ingham m_type_sp.reset(); 2302837b766SJim Ingham return true; 2312837b766SJim Ingham } 2322837b766SJim Ingham 233cc4d0146SGreg Clayton ExecutionContext exe_ctx (GetExecutionContextRef()); 234c14ee32dSGreg Clayton Target *target = exe_ctx.GetTargetPtr(); 235c14ee32dSGreg Clayton if (target) 23678a685aaSJim Ingham { 237c14ee32dSGreg Clayton m_data.SetByteOrder(target->GetArchitecture().GetByteOrder()); 238c14ee32dSGreg Clayton m_data.SetAddressByteSize(target->GetArchitecture().GetAddressByteSize()); 23978a685aaSJim Ingham } 24078a685aaSJim Ingham 24178a685aaSJim Ingham // First make sure our Type and/or Address haven't changed: 242cc4d0146SGreg Clayton Process *process = exe_ctx.GetProcessPtr(); 24378a685aaSJim Ingham if (!process) 24478a685aaSJim Ingham return false; 24578a685aaSJim Ingham 24661be0903SJim Ingham TypeAndOrName class_type_or_name; 24778a685aaSJim Ingham Address dynamic_address; 24878a685aaSJim Ingham bool found_dynamic_type = false; 24978a685aaSJim Ingham 25078a685aaSJim Ingham lldb::LanguageType known_type = m_parent->GetObjectRuntimeLanguage(); 25178a685aaSJim Ingham if (known_type != lldb::eLanguageTypeUnknown && known_type != lldb::eLanguageTypeC) 25278a685aaSJim Ingham { 25378a685aaSJim Ingham LanguageRuntime *runtime = process->GetLanguageRuntime (known_type); 25478a685aaSJim Ingham if (runtime) 2552837b766SJim Ingham found_dynamic_type = runtime->GetDynamicTypeAndAddress (*m_parent, m_use_dynamic, class_type_or_name, dynamic_address); 25678a685aaSJim Ingham } 25778a685aaSJim Ingham else 25878a685aaSJim Ingham { 25978a685aaSJim Ingham LanguageRuntime *cpp_runtime = process->GetLanguageRuntime (lldb::eLanguageTypeC_plus_plus); 26078a685aaSJim Ingham if (cpp_runtime) 2612837b766SJim Ingham found_dynamic_type = cpp_runtime->GetDynamicTypeAndAddress (*m_parent, m_use_dynamic, class_type_or_name, dynamic_address); 26278a685aaSJim Ingham 26378a685aaSJim Ingham if (!found_dynamic_type) 26478a685aaSJim Ingham { 26578a685aaSJim Ingham LanguageRuntime *objc_runtime = process->GetLanguageRuntime (lldb::eLanguageTypeObjC); 26678a685aaSJim Ingham if (objc_runtime) 2679910bc85SEnrico Granata found_dynamic_type = objc_runtime->GetDynamicTypeAndAddress (*m_parent, m_use_dynamic, class_type_or_name, dynamic_address); 26878a685aaSJim Ingham } 26978a685aaSJim Ingham } 27078a685aaSJim Ingham 27161be0903SJim Ingham lldb::TypeSP dynamic_type_sp = class_type_or_name.GetTypeSP(); 27261be0903SJim Ingham 27361be0903SJim Ingham // Getting the dynamic value may have run the program a bit, and so marked us as needing updating, but we really 27461be0903SJim Ingham // don't... 27561be0903SJim Ingham 27661be0903SJim Ingham m_update_point.SetUpdated(); 27761be0903SJim Ingham 27878a685aaSJim Ingham // If we don't have a dynamic type, then make ourselves just a echo of our parent. 27978a685aaSJim Ingham // Or we could return false, and make ourselves an echo of our parent? 28078a685aaSJim Ingham if (!found_dynamic_type) 28178a685aaSJim Ingham { 28278a685aaSJim Ingham if (m_type_sp) 28378a685aaSJim Ingham SetValueDidChange(true); 28478a685aaSJim Ingham m_value = m_parent->GetValue(); 285e72dfb32SGreg Clayton m_error = m_value.GetValueAsData (&exe_ctx, GetClangAST(), m_data, 0, GetModule().get()); 28678a685aaSJim Ingham return m_error.Success(); 28778a685aaSJim Ingham } 28878a685aaSJim Ingham 28978a685aaSJim Ingham Value old_value(m_value); 29078a685aaSJim Ingham 291*d228483dSEnrico Granata lldb::LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES)); 292*d228483dSEnrico Granata 29378a685aaSJim Ingham if (!m_type_sp) 29478a685aaSJim Ingham { 29578a685aaSJim Ingham m_type_sp = dynamic_type_sp; 29613ac0e25SEnrico Granata ResetCompleteTypeInfo (); 297*d228483dSEnrico Granata if (log) 298*d228483dSEnrico Granata log->Printf("[%s %p] now has a dynamic type %s", 299*d228483dSEnrico Granata GetName().GetCString(), 300*d228483dSEnrico Granata this, 301*d228483dSEnrico Granata GetTypeName().AsCString("")); 30278a685aaSJim Ingham } 30378a685aaSJim Ingham else if (dynamic_type_sp != m_type_sp) 30478a685aaSJim Ingham { 30578a685aaSJim Ingham // We are another type, we need to tear down our children... 30678a685aaSJim Ingham m_type_sp = dynamic_type_sp; 30778a685aaSJim Ingham SetValueDidChange (true); 30813ac0e25SEnrico Granata ResetCompleteTypeInfo (); 309*d228483dSEnrico Granata if (log) 310*d228483dSEnrico Granata log->Printf("[%s %p] has a new dynamic type %s", 311*d228483dSEnrico Granata GetName().GetCString(), 312*d228483dSEnrico Granata this, 313*d228483dSEnrico Granata GetTypeName().AsCString("")); 31478a685aaSJim Ingham } 31578a685aaSJim Ingham 31678a685aaSJim Ingham if (!m_address.IsValid() || m_address != dynamic_address) 31778a685aaSJim Ingham { 31878a685aaSJim Ingham if (m_address.IsValid()) 31978a685aaSJim Ingham SetValueDidChange (true); 32078a685aaSJim Ingham 32178a685aaSJim Ingham // We've moved, so we should be fine... 32278a685aaSJim Ingham m_address = dynamic_address; 323cc4d0146SGreg Clayton lldb::TargetSP target_sp (GetTargetSP()); 324cc4d0146SGreg Clayton lldb::addr_t load_address = m_address.GetLoadAddress(target_sp.get()); 32578a685aaSJim Ingham m_value.GetScalar() = load_address; 32678a685aaSJim Ingham } 32778a685aaSJim Ingham 32878a685aaSJim Ingham // The type will always be the type of the dynamic object. If our parent's type was a pointer, 32978a685aaSJim Ingham // then our type should be a pointer to the type of the dynamic object. If a reference, then the original type 33078a685aaSJim Ingham // should be okay... 33178a685aaSJim Ingham lldb::clang_type_t orig_type = m_type_sp->GetClangForwardType(); 33278a685aaSJim Ingham lldb::clang_type_t corrected_type = orig_type; 33378a685aaSJim Ingham if (m_parent->IsPointerType()) 33478a685aaSJim Ingham corrected_type = ClangASTContext::CreatePointerType (m_type_sp->GetClangAST(), orig_type); 33578a685aaSJim Ingham else if (m_parent->IsPointerOrReferenceType()) 33678a685aaSJim Ingham corrected_type = ClangASTContext::CreateLValueReferenceType (m_type_sp->GetClangAST(), orig_type); 33778a685aaSJim Ingham 33878a685aaSJim Ingham m_value.SetContext (Value::eContextTypeClangType, corrected_type); 33978a685aaSJim Ingham 34078a685aaSJim Ingham // Our address is the location of the dynamic type stored in memory. It isn't a load address, 34178a685aaSJim Ingham // because we aren't pointing to the LOCATION that stores the pointer to us, we're pointing to us... 34278a685aaSJim Ingham m_value.SetValueType(Value::eValueTypeScalar); 34378a685aaSJim Ingham 34478a685aaSJim Ingham if (m_address.IsValid() && m_type_sp) 34578a685aaSJim Ingham { 34678a685aaSJim Ingham // The variable value is in the Scalar value inside the m_value. 34778a685aaSJim Ingham // We can point our m_data right to it. 348e72dfb32SGreg Clayton m_error = m_value.GetValueAsData (&exe_ctx, GetClangAST(), m_data, 0, GetModule().get()); 34978a685aaSJim Ingham if (m_error.Success()) 35078a685aaSJim Ingham { 35178a685aaSJim Ingham if (ClangASTContext::IsAggregateType (GetClangType())) 35278a685aaSJim Ingham { 35378a685aaSJim Ingham // this value object represents an aggregate type whose 35478a685aaSJim Ingham // children have values, but this object does not. So we 35578a685aaSJim Ingham // say we are changed if our location has changed. 35678a685aaSJim Ingham SetValueDidChange (m_value.GetValueType() != old_value.GetValueType() || m_value.GetScalar() != old_value.GetScalar()); 35778a685aaSJim Ingham } 35878a685aaSJim Ingham 35978a685aaSJim Ingham SetValueIsValid (true); 36078a685aaSJim Ingham return true; 36178a685aaSJim Ingham } 36278a685aaSJim Ingham } 36378a685aaSJim Ingham 36478a685aaSJim Ingham // We get here if we've failed above... 36578a685aaSJim Ingham SetValueIsValid (false); 36678a685aaSJim Ingham return false; 36778a685aaSJim Ingham } 36878a685aaSJim Ingham 36978a685aaSJim Ingham 37078a685aaSJim Ingham 37178a685aaSJim Ingham bool 37278a685aaSJim Ingham ValueObjectDynamicValue::IsInScope () 37378a685aaSJim Ingham { 37478a685aaSJim Ingham return m_parent->IsInScope(); 37578a685aaSJim Ingham } 37678a685aaSJim Ingham 37707a4ac22SEnrico Granata bool 37807a4ac22SEnrico Granata ValueObjectDynamicValue::SetValueFromCString (const char *value_str, Error& error) 37907a4ac22SEnrico Granata { 38007a4ac22SEnrico Granata if (!UpdateValueIfNeeded(false)) 38107a4ac22SEnrico Granata { 38207a4ac22SEnrico Granata error.SetErrorString("unable to read value"); 38307a4ac22SEnrico Granata return false; 38407a4ac22SEnrico Granata } 38507a4ac22SEnrico Granata 38607a4ac22SEnrico Granata uint64_t my_value = GetValueAsUnsigned(UINT64_MAX); 38707a4ac22SEnrico Granata uint64_t parent_value = m_parent->GetValueAsUnsigned(UINT64_MAX); 38807a4ac22SEnrico Granata 38907a4ac22SEnrico Granata if (my_value == UINT64_MAX || parent_value == UINT64_MAX) 39007a4ac22SEnrico Granata { 39107a4ac22SEnrico Granata error.SetErrorString("unable to read value"); 39207a4ac22SEnrico Granata return false; 39307a4ac22SEnrico Granata } 39407a4ac22SEnrico Granata 39507a4ac22SEnrico Granata // if we are at an offset from our parent, in order to set ourselves correctly we would need 39607a4ac22SEnrico Granata // to change the new value so that it refers to the correct dynamic type. we choose not to deal 39707a4ac22SEnrico Granata // with that - if anything more than a value overwrite is required, you should be using the 39807a4ac22SEnrico Granata // expression parser instead of the value editing facility 39907a4ac22SEnrico Granata if (my_value != parent_value) 40007a4ac22SEnrico Granata { 40107a4ac22SEnrico Granata // but NULL'ing out a value should always be allowed 40207a4ac22SEnrico Granata if (strcmp(value_str,"0")) 40307a4ac22SEnrico Granata { 40407a4ac22SEnrico Granata error.SetErrorString("unable to modify dynamic value, use 'expression' command"); 40507a4ac22SEnrico Granata return false; 40607a4ac22SEnrico Granata } 40707a4ac22SEnrico Granata } 40807a4ac22SEnrico Granata 40907a4ac22SEnrico Granata bool ret_val = m_parent->SetValueFromCString(value_str,error); 41007a4ac22SEnrico Granata SetNeedsUpdate(); 41107a4ac22SEnrico Granata return ret_val; 41207a4ac22SEnrico Granata } 413