diff options
23 files changed, 331 insertions, 32 deletions
diff --git a/lldb/include/lldb/Core/ValueObject.h b/lldb/include/lldb/Core/ValueObject.h index 18844318c08..d9d6b78d301 100644 --- a/lldb/include/lldb/Core/ValueObject.h +++ b/lldb/include/lldb/Core/ValueObject.h @@ -88,6 +88,7 @@ public: { eExpressionPathScanEndReasonEndOfString = 1, // out of data to parse eExpressionPathScanEndReasonNoSuchChild, // child element not found + eExpressionPathScanEndReasonNoSuchSyntheticChild, // (synthetic) child element not found eExpressionPathScanEndReasonEmptyRangeNotAllowed, // [] only allowed for arrays eExpressionPathScanEndReasonDotInsteadOfArrow, // . used when -> should be used eExpressionPathScanEndReasonArrowInsteadOfDot, // -> used when . should be used @@ -379,6 +380,9 @@ public: // this vends a TypeImpl that is useful at the SB API layer virtual TypeImpl GetTypeImpl (); + + virtual bool + CanProvideValue (); //------------------------------------------------------------------ // Subclasses must implement the functions below. @@ -756,6 +760,12 @@ public: return false; } + virtual bool + DoesProvideSyntheticValue () + { + return false; + } + virtual SymbolContextScope * GetSymbolContextScope(); diff --git a/lldb/include/lldb/Core/ValueObjectSyntheticFilter.h b/lldb/include/lldb/Core/ValueObjectSyntheticFilter.h index e12698f49bb..9846ae6e247 100644 --- a/lldb/include/lldb/Core/ValueObjectSyntheticFilter.h +++ b/lldb/include/lldb/Core/ValueObjectSyntheticFilter.h @@ -132,11 +132,12 @@ public: GetNonSyntheticValue (); virtual bool - ResolveValue (Scalar &scalar) + CanProvideValue (); + + virtual bool + DoesProvideSyntheticValue () { - if (m_parent) - return m_parent->ResolveValue(scalar); - return false; + return (UpdateValueIfNeeded(), m_provides_value == eLazyBoolYes); } protected: @@ -167,12 +168,14 @@ protected: LazyBool m_might_have_children; + LazyBool m_provides_value; + private: friend class ValueObject; ValueObjectSynthetic (ValueObject &parent, lldb::SyntheticChildrenSP filter); void - CopyParentData (); + CopyValueData (ValueObject *source); //------------------------------------------------------------------ // For ValueObject only diff --git a/lldb/include/lldb/DataFormatters/TypeSynthetic.h b/lldb/include/lldb/DataFormatters/TypeSynthetic.h index a25f11d6439..9c4f77cdecb 100644 --- a/lldb/include/lldb/DataFormatters/TypeSynthetic.h +++ b/lldb/include/lldb/DataFormatters/TypeSynthetic.h @@ -81,6 +81,11 @@ namespace lldb_private { virtual bool MightHaveChildren () = 0; + // if this function returns a non-null ValueObject, then the returned ValueObject will stand + // for this ValueObject whenever a "value" request is made to this ValueObject + virtual lldb::ValueObjectSP + GetSyntheticValue () { return nullptr; } + typedef std::shared_ptr<SyntheticChildrenFrontEnd> SharedPointer; typedef std::unique_ptr<SyntheticChildrenFrontEnd> AutoPointer; @@ -593,6 +598,15 @@ namespace lldb_private { return m_interpreter->GetIndexOfChildWithName(m_wrapper_sp, name.GetCString()); } + virtual lldb::ValueObjectSP + GetSyntheticValue () + { + if (!m_wrapper_sp || m_interpreter == NULL) + return nullptr; + + return m_interpreter->GetSyntheticValue(m_wrapper_sp); + } + typedef std::shared_ptr<SyntheticChildrenFrontEnd> SharedPointer; private: diff --git a/lldb/include/lldb/DataFormatters/ValueObjectPrinter.h b/lldb/include/lldb/DataFormatters/ValueObjectPrinter.h index 327ebd137db..cc8b198f038 100644 --- a/lldb/include/lldb/DataFormatters/ValueObjectPrinter.h +++ b/lldb/include/lldb/DataFormatters/ValueObjectPrinter.h @@ -295,7 +295,7 @@ protected: uint32_t curr_depth); bool - GetDynamicValueIfNeeded (); + GetMostSpecializedValue (); const char* GetDescriptionForDisplay (); diff --git a/lldb/include/lldb/Interpreter/ScriptInterpreter.h b/lldb/include/lldb/Interpreter/ScriptInterpreter.h index 2fbc57a7a32..e7a456df029 100644 --- a/lldb/include/lldb/Interpreter/ScriptInterpreter.h +++ b/lldb/include/lldb/Interpreter/ScriptInterpreter.h @@ -121,7 +121,7 @@ public: typedef lldb::ValueObjectSP (*SWIGPythonGetValueObjectSPFromSBValue) (void* data); typedef bool (*SWIGPythonUpdateSynthProviderInstance) (void* data); typedef bool (*SWIGPythonMightHaveChildrenSynthProviderInstance) (void* data); - + typedef void* (*SWIGPythonGetValueSynthProviderInstance) (void *implementor); typedef bool (*SWIGPythonCallCommand) (const char *python_function_name, const char *session_dictionary_name, @@ -498,6 +498,12 @@ public: return true; } + virtual lldb::ValueObjectSP + GetSyntheticValue (const lldb::ScriptInterpreterObjectSP& implementor) + { + return nullptr; + } + virtual bool RunScriptBasedCommand (const char* impl_function, const char* args, @@ -607,6 +613,7 @@ public: SWIGPythonGetValueObjectSPFromSBValue swig_get_valobj_sp_from_sbvalue, SWIGPythonUpdateSynthProviderInstance swig_update_provider, SWIGPythonMightHaveChildrenSynthProviderInstance swig_mighthavechildren_provider, + SWIGPythonGetValueSynthProviderInstance swig_getvalue_provider, SWIGPythonCallCommand swig_call_command, SWIGPythonCallModuleInit swig_call_module_init, SWIGPythonCreateOSPlugin swig_create_os_plugin, diff --git a/lldb/include/lldb/Interpreter/ScriptInterpreterPython.h b/lldb/include/lldb/Interpreter/ScriptInterpreterPython.h index 92fc0328959..2cdb839196b 100644 --- a/lldb/include/lldb/Interpreter/ScriptInterpreterPython.h +++ b/lldb/include/lldb/Interpreter/ScriptInterpreterPython.h @@ -141,6 +141,9 @@ public: virtual bool MightHaveChildrenSynthProviderInstance (const lldb::ScriptInterpreterObjectSP& implementor); + virtual lldb::ValueObjectSP + GetSyntheticValue (const lldb::ScriptInterpreterObjectSP& implementor); + virtual bool RunScriptBasedCommand(const char* impl_function, const char* args, @@ -285,6 +288,7 @@ public: SWIGPythonGetValueObjectSPFromSBValue swig_get_valobj_sp_from_sbvalue, SWIGPythonUpdateSynthProviderInstance swig_update_provider, SWIGPythonMightHaveChildrenSynthProviderInstance swig_mighthavechildren_provider, + SWIGPythonGetValueSynthProviderInstance swig_getvalue_provider, SWIGPythonCallCommand swig_call_command, SWIGPythonCallModuleInit swig_call_module_init, SWIGPythonCreateOSPlugin swig_create_os_plugin, diff --git a/lldb/scripts/Python/python-wrapper.swig b/lldb/scripts/Python/python-wrapper.swig index bf22198f4e4..9f9ebaded9d 100644 --- a/lldb/scripts/Python/python-wrapper.swig +++ b/lldb/scripts/Python/python-wrapper.swig @@ -723,6 +723,34 @@ LLDBSwigPython_MightHaveChildrenSynthProviderInstance return ret_val; } +SWIGEXPORT PyObject* +LLDBSwigPython_GetValueSynthProviderInstance +( + PyObject *implementor +) +{ + PyObject* ret_val = nullptr; + + static char callee_name[] = "get_value"; + + PyObject* py_return = LLDBSwigPython_CallOptionalMember(implementor,callee_name, Py_None); + + if (py_return == Py_None || py_return == nullptr) + ret_val = nullptr; + + lldb::SBValue* sbvalue_ptr = NULL; + + if (SWIG_ConvertPtr(py_return, (void**)&sbvalue_ptr, SWIGTYPE_p_lldb__SBValue, 0) == -1) + ret_val = nullptr; + else if (sbvalue_ptr == NULL) + ret_val = nullptr; + else + ret_val = py_return; + + Py_XDECREF(py_return); + return ret_val; +} + SWIGEXPORT void* LLDBSWIGPython_CastPyObjectToSBValue ( diff --git a/lldb/source/API/SBCommandInterpreter.cpp b/lldb/source/API/SBCommandInterpreter.cpp index aa1ff55bc73..9f6f4e8d428 100644 --- a/lldb/source/API/SBCommandInterpreter.cpp +++ b/lldb/source/API/SBCommandInterpreter.cpp @@ -474,6 +474,9 @@ LLDBSwigPython_UpdateSynthProviderInstance (void* implementor); extern "C" bool LLDBSwigPython_MightHaveChildrenSynthProviderInstance (void* implementor); +extern "C" void * +LLDBSwigPython_GetValueSynthProviderInstance (void* implementor); + extern "C" bool LLDBSwigPythonCallCommand (const char *python_function_name, const char *session_dictionary_name, @@ -544,6 +547,7 @@ SBCommandInterpreter::InitializeSWIG () LLDBSWIGPython_GetValueObjectSPFromSBValue, LLDBSwigPython_UpdateSynthProviderInstance, LLDBSwigPython_MightHaveChildrenSynthProviderInstance, + LLDBSwigPython_GetValueSynthProviderInstance, LLDBSwigPythonCallCommand, LLDBSwigPythonCallModuleInit, LLDBSWIGPythonCreateOSPlugin, diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp index 3b37de79234..f38b7c01565 100644 --- a/lldb/source/Core/ValueObject.cpp +++ b/lldb/source/Core/ValueObject.cpp @@ -1450,7 +1450,7 @@ ValueObject::GetValueAsCString () } else { - my_format = GetClangType().GetFormat(); + my_format = GetValue().GetClangType().GetFormat(); } } } @@ -1482,7 +1482,7 @@ uint64_t ValueObject::GetValueAsUnsigned (uint64_t fail_value, bool *success) { // If our byte size is zero this is an aggregate type that has children - if (!GetClangType().IsAggregateType()) + if (CanProvideValue()) { Scalar scalar; if (ResolveValue (scalar)) @@ -1503,7 +1503,7 @@ int64_t ValueObject::GetValueAsSigned (int64_t fail_value, bool *success) { // If our byte size is zero this is an aggregate type that has children - if (!GetClangType().IsAggregateType()) + if (CanProvideValue()) { Scalar scalar; if (ResolveValue (scalar)) @@ -1751,7 +1751,7 @@ ValueObject::DumpPrintableRepresentation(Stream& s, cstr = GetSummaryAsCString(); else if (val_obj_display == eValueObjectRepresentationStyleSummary) { - if (GetClangType().IsAggregateType()) + if (!CanProvideValue()) { strm.Printf("%s @ %s", GetTypeName().AsCString(), GetLocationAsCString()); cstr = strm.GetString().c_str(); @@ -2805,7 +2805,7 @@ ValueObject::GetValueForExpressionPath_Impl(const char* expression_cstr, if (root->IsSynthetic()) { *first_unparsed = expression_cstr; - *reason_to_stop = ValueObject::eExpressionPathScanEndReasonNoSuchChild; + *reason_to_stop = ValueObject::eExpressionPathScanEndReasonNoSuchSyntheticChild; *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; return ValueObjectSP(); } @@ -4080,3 +4080,9 @@ ValueObject::GetFormat () const } return m_format; } + +bool +ValueObject::CanProvideValue () +{ + return (false == GetClangType().IsAggregateType()); +} diff --git a/lldb/source/Core/ValueObjectCast.cpp b/lldb/source/Core/ValueObjectCast.cpp index 4f4f8cc681d..b20371b128d 100644 --- a/lldb/source/Core/ValueObjectCast.cpp +++ b/lldb/source/Core/ValueObjectCast.cpp @@ -102,7 +102,7 @@ ValueObjectCast::UpdateValue () //m_value.SetContext (Value::eContextTypeClangType, clang_type); m_value.SetClangType (clang_type); SetAddressTypeOfChildren(m_parent->GetAddressTypeOfChildren()); - if (clang_type.IsAggregateType ()) + if (!CanProvideValue()) { // this value object represents an aggregate type whose // children have values, but this object does not. So we diff --git a/lldb/source/Core/ValueObjectDynamicValue.cpp b/lldb/source/Core/ValueObjectDynamicValue.cpp index 3481bdedf38..30a42f09461 100644 --- a/lldb/source/Core/ValueObjectDynamicValue.cpp +++ b/lldb/source/Core/ValueObjectDynamicValue.cpp @@ -329,7 +329,7 @@ ValueObjectDynamicValue::UpdateValue () m_error = m_value.GetValueAsData (&exe_ctx, m_data, 0, GetModule().get()); if (m_error.Success()) { - if (GetClangType().IsAggregateType ()) + if (!CanProvideValue()) { // this value object represents an aggregate type whose // children have values, but this object does not. So we diff --git a/lldb/source/Core/ValueObjectMemory.cpp b/lldb/source/Core/ValueObjectMemory.cpp index d2cbbfdda24..5fbe87b6652 100644 --- a/lldb/source/Core/ValueObjectMemory.cpp +++ b/lldb/source/Core/ValueObjectMemory.cpp @@ -233,7 +233,7 @@ ValueObjectMemory::UpdateValue () } } - if (GetClangType().IsAggregateType()) + if (!CanProvideValue()) { // this value object represents an aggregate type whose // children have values, but this object does not. So we diff --git a/lldb/source/Core/ValueObjectSyntheticFilter.cpp b/lldb/source/Core/ValueObjectSyntheticFilter.cpp index 18d36164989..9bdf68963db 100644 --- a/lldb/source/Core/ValueObjectSyntheticFilter.cpp +++ b/lldb/source/Core/ValueObjectSyntheticFilter.cpp @@ -66,16 +66,17 @@ ValueObjectSynthetic::ValueObjectSynthetic (ValueObject &parent, lldb::Synthetic m_name_toindex(), m_synthetic_children_count(UINT32_MAX), m_parent_type_name(parent.GetTypeName()), - m_might_have_children(eLazyBoolCalculate) + m_might_have_children(eLazyBoolCalculate), + m_provides_value(eLazyBoolCalculate) { -#ifdef LLDB_CONFIGURATION_DEBUG +#ifdef FOOBAR std::string new_name(parent.GetName().AsCString()); new_name += "$$__synth__"; SetName (ConstString(new_name.c_str())); #else SetName(parent.GetName()); #endif - CopyParentData(); + CopyValueData(m_parent); CreateSynthFilter(); } @@ -191,7 +192,20 @@ ValueObjectSynthetic::UpdateValue () m_might_have_children = eLazyBoolCalculate; } - CopyParentData(); + m_provides_value = eLazyBoolCalculate; + + lldb::ValueObjectSP synth_val(m_synth_filter_ap->GetSyntheticValue()); + + if (synth_val && synth_val->CanProvideValue()) + { + m_provides_value = eLazyBoolYes; + CopyValueData(synth_val.get()); + } + else + { + m_provides_value = eLazyBoolNo; + CopyValueData(m_parent); + } SetValueIsValid(true); return true; @@ -268,9 +282,19 @@ ValueObjectSynthetic::GetNonSyntheticValue () } void -ValueObjectSynthetic::CopyParentData () +ValueObjectSynthetic::CopyValueData (ValueObject *source) { - m_value = m_parent->GetValue(); + m_value = (source->UpdateValueIfNeeded(), source->GetValue()); ExecutionContext exe_ctx (GetExecutionContextRef()); m_error = m_value.GetValueAsData (&exe_ctx, m_data, 0, GetModule().get()); } + +bool +ValueObjectSynthetic::CanProvideValue () +{ + if (!UpdateValueIfNeeded()) + return false; + if (m_provides_value == eLazyBoolYes) + return true; + return m_parent->CanProvideValue(); +} diff --git a/lldb/source/Core/ValueObjectVariable.cpp b/lldb/source/Core/ValueObjectVariable.cpp index 225dc02c8ad..aa8ade1aed1 100644 --- a/lldb/source/Core/ValueObjectVariable.cpp +++ b/lldb/source/Core/ValueObjectVariable.cpp @@ -234,7 +234,7 @@ ValueObjectVariable::UpdateValue () } } - if (GetClangType().IsAggregateType()) + if (!CanProvideValue()) { // this value object represents an aggregate type whose // children have values, but this object does not. So we diff --git a/lldb/source/DataFormatters/TypeFormat.cpp b/lldb/source/DataFormatters/TypeFormat.cpp index 0c62daf87bb..64d37501a92 100644 --- a/lldb/source/DataFormatters/TypeFormat.cpp +++ b/lldb/source/DataFormatters/TypeFormat.cpp @@ -59,9 +59,9 @@ TypeFormatImpl_Format::FormatObject (ValueObject *valobj, { if (!valobj) return false; - if (valobj->GetClangType().IsAggregateType () == false) + if (valobj->CanProvideValue()) { - const Value& value(valobj->GetValue()); + Value& value(valobj->GetValue()); const Value::ContextType context_type = value.GetContextType(); ExecutionContext exe_ctx (valobj->GetExecutionContextRef()); DataExtractor data; @@ -92,7 +92,7 @@ TypeFormatImpl_Format::FormatObject (ValueObject *valobj, } else { - ClangASTType clang_type = valobj->GetClangType (); + ClangASTType clang_type = value.GetClangType (); if (clang_type) { // put custom bytes to display in the DataExtractor to override the default value logic @@ -180,7 +180,7 @@ TypeFormatImpl_EnumType::FormatObject (ValueObject *valobj, dest.clear(); if (!valobj) return false; - if (valobj->GetClangType().IsAggregateType ()) + if (!valobj->CanProvideValue()) return false; ProcessSP process_sp; TargetSP target_sp; diff --git a/lldb/source/DataFormatters/ValueObjectPrinter.cpp b/lldb/source/DataFormatters/ValueObjectPrinter.cpp index 3ce5051cc4e..126ff78c389 100644 --- a/lldb/source/DataFormatters/ValueObjectPrinter.cpp +++ b/lldb/source/DataFormatters/ValueObjectPrinter.cpp @@ -66,7 +66,7 @@ ValueObjectPrinter::Init (ValueObject* valobj, bool ValueObjectPrinter::PrintValueObject () { - if (!GetDynamicValueIfNeeded () || m_valobj == nullptr) + if (!GetMostSpecializedValue () || m_valobj == nullptr) return false; if (ShouldPrintValueObject()) @@ -97,7 +97,7 @@ ValueObjectPrinter::PrintValueObject () } bool -ValueObjectPrinter::GetDynamicValueIfNeeded () +ValueObjectPrinter::GetMostSpecializedValue () { if (m_valobj) return true; @@ -134,6 +134,25 @@ ValueObjectPrinter::GetDynamicValueIfNeeded () else m_valobj = m_orig_valobj; } + + if (m_valobj->IsSynthetic()) + { + if (options.m_use_synthetic == false) + { + ValueObject *non_synthetic = m_valobj->GetNonSyntheticValue().get(); + if (non_synthetic) + m_valobj = non_synthetic; + } + } + else + { + if (options.m_use_synthetic == true) + { + ValueObject *synthetic = m_valobj->GetSyntheticValue().get(); + if (synthetic) + m_valobj = synthetic; + } + } } m_clang_type = m_valobj->GetClangType(); m_type_flags = m_clang_type.GetTypeInfo (); @@ -442,8 +461,7 @@ ValueObjectPrinter::ShouldPrintChildren (bool is_failed_description, ValueObject* ValueObjectPrinter::GetValueObjectForChildrenGeneration () { - ValueObjectSP synth_valobj_sp = m_valobj->GetSyntheticValue (options.m_use_synthetic); - return (synth_valobj_sp ? synth_valobj_sp.get() : m_valobj); + return m_valobj; } void @@ -540,7 +558,13 @@ ValueObjectPrinter::PrintChildren (uint32_t curr_ptr_depth) { // Aggregate, no children... if (ShouldPrintValueObject()) - m_stream->PutCString(" {}\n"); + { + // if it has a synthetic value, then don't print {}, the synthetic children are probably only being used to vend a value + if (m_valobj->DoesProvideSyntheticValue()) + m_stream->PutCString( "\n"); + else + m_stream->PutCString(" {}\n"); + } } else { @@ -552,7 +576,7 @@ ValueObjectPrinter::PrintChildren (uint32_t curr_ptr_depth) bool ValueObjectPrinter::PrintChildrenOneLiner (bool hide_names) { - if (!GetDynamicValueIfNeeded () || m_valobj == nullptr) + if (!GetMostSpecializedValue () || m_valobj == nullptr) return false; ValueObject* synth_m_valobj = GetValueObjectForChildrenGeneration(); diff --git a/lldb/source/Interpreter/ScriptInterpreter.cpp b/lldb/source/Interpreter/ScriptInterpreter.cpp index 721eedb59d7..87bfc955be0 100644 --- a/lldb/source/Interpreter/ScriptInterpreter.cpp +++ b/lldb/source/Interpreter/ScriptInterpreter.cpp @@ -124,6 +124,7 @@ ScriptInterpreter::InitializeInterpreter (SWIGInitCallback python_swig_init_call SWIGPythonGetValueObjectSPFromSBValue swig_get_valobj_sp_from_sbvalue, SWIGPythonUpdateSynthProviderInstance swig_update_provider, SWIGPythonMightHaveChildrenSynthProviderInstance swig_mighthavechildren_provider, + SWIGPythonGetValueSynthProviderInstance swig_getvalue_provider, SWIGPythonCallCommand swig_call_command, SWIGPythonCallModuleInit swig_call_module_init, SWIGPythonCreateOSPlugin swig_create_os_plugin, @@ -148,6 +149,7 @@ ScriptInterpreter::InitializeInterpreter (SWIGInitCallback python_swig_init_call swig_get_valobj_sp_from_sbvalue, swig_update_provider, swig_mighthavechildren_provider, + swig_getvalue_provider, swig_call_command, swig_call_module_init, swig_create_os_plugin, diff --git a/lldb/source/Interpreter/ScriptInterpreterPython.cpp b/lldb/source/Interpreter/ScriptInterpreterPython.cpp index 03b39d19de0..987a168079a 100644 --- a/lldb/source/Interpreter/ScriptInterpreterPython.cpp +++ b/lldb/source/Interpreter/ScriptInterpreterPython.cpp @@ -55,6 +55,7 @@ static ScriptInterpreter::SWIGPythonCastPyObjectToSBValue g_swig_cast_to_sbvalue static ScriptInterpreter::SWIGPythonGetValueObjectSPFromSBValue g_swig_get_valobj_sp_from_sbvalue = nullptr; static ScriptInterpreter::SWIGPythonUpdateSynthProviderInstance g_swig_update_provider = nullptr; static ScriptInterpreter::SWIGPythonMightHaveChildrenSynthProviderInstance g_swig_mighthavechildren_provider = nullptr; +static ScriptInterpreter::SWIGPythonGetValueSynthProviderInstance g_swig_getvalue_provider = nullptr; static ScriptInterpreter::SWIGPythonCallCommand g_swig_call_command = nullptr; static ScriptInterpreter::SWIGPythonCallModuleInit g_swig_call_module_init = nullptr; static ScriptInterpreter::SWIGPythonCreateOSPlugin g_swig_create_os_plugin = nullptr; @@ -2140,6 +2141,42 @@ ScriptInterpreterPython::MightHaveChildrenSynthProviderInstance (const lldb::Scr return ret_val; } +lldb::ValueObjectSP +ScriptInterpreterPython::GetSyntheticValue (const lldb::ScriptInterpreterObjectSP& implementor_sp) +{ + lldb::ValueObjectSP ret_val(nullptr); + + if (!implementor_sp) + return ret_val; + + void* implementor = implementor_sp->GetObject(); + + if (!implementor) + return ret_val; + + if (!g_swig_getvalue_provider || !g_swig_cast_to_sbvalue || !g_swig_get_valobj_sp_from_sbvalue) + return ret_val; + + { + Locker py_lock(this, Locker::AcquireLock | Locker::InitSession | Locker::NoSTDIN); + void* child_ptr = g_swig_getvalue_provider (implementor); + if (child_ptr != nullptr && child_ptr != Py_None) + { + lldb::SBValue* sb_value_ptr = (lldb::SBValue*)g_swig_cast_to_sbvalue(child_ptr); + if (sb_value_ptr == nullptr) + Py_XDECREF(child_ptr); + else + ret_val = g_swig_get_valobj_sp_from_sbvalue (sb_value_ptr); + } + else + { + Py_XDECREF(child_ptr); + } + } + + return ret_val; +} + static std::string ReadPythonBacktrace (PyObject* py_backtrace) { @@ -2616,6 +2653,7 @@ ScriptInterpreterPython::InitializeInterpreter (SWIGInitCallback swig_init_callb SWIGPythonGetValueObjectSPFromSBValue swig_get_valobj_sp_from_sbvalue, SWIGPythonUpdateSynthProviderInstance swig_update_provider, SWIGPythonMightHaveChildrenSynthProviderInstance swig_mighthavechildren_provider, + SWIGPythonGetValueSynthProviderInstance swig_getvalue_provider, SWIGPythonCallCommand swig_call_command, SWIGPythonCallModuleInit swig_call_module_init, SWIGPythonCreateOSPlugin swig_create_os_plugin, @@ -2639,6 +2677,7 @@ ScriptInterpreterPython::InitializeInterpreter (SWIGInitCallback swig_init_callb g_swig_get_valobj_sp_from_sbvalue = swig_get_valobj_sp_from_sbvalue; g_swig_update_provider = swig_update_provider; g_swig_mighthavechildren_provider = swig_mighthavechildren_provider; + g_swig_getvalue_provider = swig_getvalue_provider; g_swig_call_command = swig_call_command; g_swig_call_module_init = swig_call_module_init; g_swig_create_os_plugin = swig_create_os_plugin; diff --git a/lldb/test/functionalities/data-formatter/data-formatter-synth/TestDataFormatterSynth.py b/lldb/test/functionalities/data-formatter/data-formatter-synth/TestDataFormatterSynth.py index 9c3bed1828a..36ff60babdb 100644 --- a/lldb/test/functionalities/data-formatter/data-formatter-synth/TestDataFormatterSynth.py +++ b/lldb/test/functionalities/data-formatter/data-formatter-synth/TestDataFormatterSynth.py @@ -14,12 +14,14 @@ class SynthDataFormatterTestCase(TestBase): @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin") @dsym_test + @unittest2.expectedFailure("rdar://15630776 - Summary cannot reference non-synthetic children if synthetic children exist") def test_with_dsym_and_run_command(self): """Test data formatter commands.""" self.buildDsym() self.data_formatter_commands() @dwarf_test + @unittest2.expectedFailure("rdar://15630776 - Summary cannot reference non-synthetic children if synthetic children exist") def test_with_dwarf_and_run_command(self): """Test data formatter commands.""" self.buildDwarf() diff --git a/lldb/test/functionalities/data-formatter/data-formatter-synthval/Makefile b/lldb/test/functionalities/data-formatter/data-formatter-synthval/Makefile new file mode 100644 index 00000000000..314f1cb2f07 --- /dev/null +++ b/lldb/test/functionalities/data-formatter/data-formatter-synthval/Makefile @@ -0,0 +1,5 @@ +LEVEL = ../../../make + +CXX_SOURCES := main.cpp + +include $(LEVEL)/Makefile.rules diff --git a/lldb/test/functionalities/data-formatter/data-formatter-synthval/TestDataFormatterSynthVal.py b/lldb/test/functionalities/data-formatter/data-formatter-synthval/TestDataFormatterSynthVal.py new file mode 100644 index 00000000000..c5ff06b04b4 --- /dev/null +++ b/lldb/test/functionalities/data-formatter/data-formatter-synthval/TestDataFormatterSynthVal.py @@ -0,0 +1,95 @@ +""" +Test lldb data formatter subsystem. +""" + +import os, time +import unittest2 +import lldb +from lldbtest import * +import lldbutil + +class DataFormatterSynthValueTestCase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin") + @dsym_test + def test_with_dsym_and_run_command(self): + """Test using Python synthetic children provider to provide a value.""" + self.buildDsym() + self.data_formatter_commands() + + @skipIfFreeBSD # llvm.org/pr20545 bogus output confuses buildbot parser + @dwarf_test + def test_with_dwarf_and_run_command(self): + """Test using Python synthetic children provider to provide a value.""" + self.buildDwarf() + self.data_formatter_commands() + + def setUp(self): + # Call super's setUp(). + TestBase.setUp(self) + # Find the line number to break at. + self.line = line_number('main.cpp', 'break here') + + def data_formatter_commands(self): + """Test using Python synthetic children provider to provide a value.""" + self.runCmd("file a.out", CURRENT_EXECUTABLE_SET) + + lldbutil.run_break_set_by_file_and_line (self, "main.cpp", self.line, num_expected_locations=1, loc_exact=True) + + self.runCmd("run", RUN_SUCCEEDED) + + # The stop reason of the thread should be breakpoint. + self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT, + substrs = ['stopped', + 'stop reason = breakpoint']) + + # This is the function to remove the custom formats in order to have a + # clean slate for the next test case. + def cleanup(): + self.runCmd('type format clear', check=False) + self.runCmd('type summary clear', check=False) + self.runCmd('type filter clear', check=False) + self.runCmd('type synth clear', check=False) + + # Execute the cleanup function during test case tear down. + self.addTearDownHook(cleanup) + + x = self.frame().FindVariable("x") + x.SetPreferSyntheticValue(True) + y = self.frame().FindVariable("y") + y.SetPreferSyntheticValue(True) + z = self.frame().FindVariable("z") + z.SetPreferSyntheticValue(True) + + x_val = x.GetValueAsUnsigned + y_val = y.GetValueAsUnsigned + z_val = z.GetValueAsUnsigned + + if self.TraceOn(): + print "x_val = %s; y_val = %s; z_val = %s" % (x_val(),y_val(),z_val()) + + self.assertFalse(x_val() == 3, "x == 3 before synthetics") + self.assertFalse(y_val() == 4, "y == 4 before synthetics") + self.assertFalse(z_val() == 7, "z == 7 before synthetics") + + # now set up the synth + self.runCmd("script from myIntSynthProvider import *") + self.runCmd("type synth add -l myIntSynthProvider myInt") + + if self.TraceOn(): + print "x_val = %s; y_val = %s; z_val = %s" % (x_val(),y_val(),z_val()) + + self.assertTrue(x_val() == 3, "x != 3 after synthetics") + self.assertTrue(y_val() == 4, "y != 4 after synthetics") + self.assertTrue(z_val() == 7, "z != 7 after synthetics") + + self.expect("frame variable x", substrs=['3']) + self.expect("frame variable x", substrs=['theValue = 3'], matching=False) + +if __name__ == '__main__': + import atexit + lldb.SBDebugger.Initialize() + atexit.register(lambda: lldb.SBDebugger.Terminate()) + unittest2.main() diff --git a/lldb/test/functionalities/data-formatter/data-formatter-synthval/main.cpp b/lldb/test/functionalities/data-formatter/data-formatter-synthval/main.cpp new file mode 100644 index 00000000000..fef128c1eb1 --- /dev/null +++ b/lldb/test/functionalities/data-formatter/data-formatter-synthval/main.cpp @@ -0,0 +1,15 @@ +class myInt { + private: int theValue; + public: myInt() : theValue(0) {} + public: myInt(int _x) : theValue(_x) {} + int val() { return theValue; } +}; + +myInt operator + (myInt x, myInt y) { return myInt(x.val() + y.val()); } + +int main() { + myInt x{3}; + myInt y{4}; + myInt z {x+y}; + return z.val(); // break here +} diff --git a/lldb/test/functionalities/data-formatter/data-formatter-synthval/myIntSynthProvider.py b/lldb/test/functionalities/data-formatter/data-formatter-synthval/myIntSynthProvider.py new file mode 100644 index 00000000000..d37cb0ecc5f --- /dev/null +++ b/lldb/test/functionalities/data-formatter/data-formatter-synthval/myIntSynthProvider.py @@ -0,0 +1,17 @@ +class myIntSynthProvider(object): + def __init__(self, valobj, dict): + self.valobj = valobj; + self.val = self.valobj.GetChildMemberWithName("theValue") + def num_children(self): + return 0; + def get_child_at_index(self, index): + return None + def get_child_index(self, name): + return None + def update(self): + return False + def might_have_children(self): + return False + def get_value(self): + return self.val + |