diff --git a/lldb/include/lldb/Core/ValueObject.h b/lldb/include/lldb/Core/ValueObject.h index 14fd8f95ff56..84b187e54b6c 100644 --- a/lldb/include/lldb/Core/ValueObject.h +++ b/lldb/include/lldb/Core/ValueObject.h @@ -1011,6 +1011,48 @@ private: DISALLOW_COPY_AND_ASSIGN(ValueObject); }; +//------------------------------------------------------------------------------ +// A value object manager class that is seeded with the static variable value +// and it vends the user facing value object. If the type is dynamic it can +// vend the dynamic type. If this user type also has a synthetic type associated +// with it, it will vend the synthetic type. The class watches the process' stop +// ID and will update the user type when needed. +//------------------------------------------------------------------------------ +class ValueObjectManager { + // The root value object is the static typed variable object. + lldb::ValueObjectSP m_root_valobj_sp; + // The user value object is the value object the user wants to see. + lldb::ValueObjectSP m_user_valobj_sp; + lldb::DynamicValueType m_use_dynamic; + uint32_t m_stop_id; // The stop ID that m_user_valobj_sp is valid for. + bool m_use_synthetic; + +public: + ValueObjectManager() {} + + ValueObjectManager(lldb::ValueObjectSP in_valobj_sp, + lldb::DynamicValueType use_dynamic, bool use_synthetic); + + bool IsValid() const; + + lldb::ValueObjectSP GetRootSP() const { return m_root_valobj_sp; } + + // Gets the correct value object from the root object for a given process + // stop ID. If dynamic values are enabled, or if synthetic children are + // enabled, the value object that the user wants to see might change while + // debugging. + lldb::ValueObjectSP GetSP(); + + void SetUseDynamic(lldb::DynamicValueType use_dynamic); + void SetUseSynthetic(bool use_synthetic); + lldb::DynamicValueType GetUseDynamic() const { return m_use_dynamic; } + bool GetUseSynthetic() const { return m_use_synthetic; } + lldb::TargetSP GetTargetSP() const; + lldb::ProcessSP GetProcessSP() const; + lldb::ThreadSP GetThreadSP() const; + lldb::StackFrameSP GetFrameSP() const; +}; + } // namespace lldb_private #endif // liblldb_ValueObject_h_ diff --git a/lldb/include/lldb/Core/ValueObjectList.h b/lldb/include/lldb/Core/ValueObjectList.h index 8b5ebabc8a5f..c5427c6a846e 100644 --- a/lldb/include/lldb/Core/ValueObjectList.h +++ b/lldb/include/lldb/Core/ValueObjectList.h @@ -62,6 +62,9 @@ public: void Clear() { m_value_objects.clear(); } + const std::vector &GetObjects() const { + return m_value_objects; + } protected: typedef std::vector collection; //------------------------------------------------------------------ diff --git a/lldb/source/Core/IOHandler.cpp b/lldb/source/Core/IOHandler.cpp index ed85c5994e38..9c5e6ca80c20 100644 --- a/lldb/source/Core/IOHandler.cpp +++ b/lldb/source/Core/IOHandler.cpp @@ -1905,8 +1905,10 @@ protected: using namespace curses; struct Row { - ValueObjectSP valobj; + ValueObjectManager value; Row *parent; + // The process stop ID when the children were calculated. + uint32_t children_stop_id; int row_idx; int x; int y; @@ -1916,8 +1918,8 @@ struct Row { std::vector children; Row(const ValueObjectSP &v, Row *p) - : valobj(v), parent(p), row_idx(0), x(1), y(1), - might_have_children(v ? v->MightHaveChildren() : false), + : value(v, lldb::eDynamicDontRunTarget, true), parent(p), row_idx(0), + x(1), y(1), might_have_children(v ? v->MightHaveChildren() : false), expanded(false), calculated_children(false), children() {} size_t GetDepth() const { @@ -1928,8 +1930,19 @@ struct Row { void Expand() { expanded = true; + } + + std::vector &GetChildren() { + ProcessSP process_sp = value.GetProcessSP(); + auto stop_id = process_sp->GetStopID(); + if (process_sp && stop_id != children_stop_id) { + children_stop_id = stop_id; + calculated_children = false; + } if (!calculated_children) { + children.clear(); calculated_children = true; + ValueObjectSP valobj = value.GetSP(); if (valobj) { const size_t num_children = valobj->GetNumChildren(); for (size_t i = 0; i < num_children; ++i) { @@ -1937,9 +1950,14 @@ struct Row { } } } + return children; } - void Unexpand() { expanded = false; } + void Unexpand() { + expanded = false; + calculated_children = false; + children.clear(); + } void DrawTree(Window &window) { if (parent) @@ -1972,7 +1990,7 @@ struct Row { if (parent) parent->DrawTreeForChild(window, this, reverse_depth + 1); - if (&children.back() == child) { + if (&GetChildren().back() == child) { // Last child if (reverse_depth == 0) { window.PutChar(ACS_LLCORNER); @@ -2620,12 +2638,12 @@ protected: class ValueObjectListDelegate : public WindowDelegate { public: ValueObjectListDelegate() - : m_valobj_list(), m_rows(), m_selected_row(nullptr), + : m_rows(), m_selected_row(nullptr), m_selected_row_idx(0), m_first_visible_row(0), m_num_rows(0), m_max_x(0), m_max_y(0) {} ValueObjectListDelegate(ValueObjectList &valobj_list) - : m_valobj_list(valobj_list), m_rows(), m_selected_row(nullptr), + : m_rows(), m_selected_row(nullptr), m_selected_row_idx(0), m_first_visible_row(0), m_num_rows(0), m_max_x(0), m_max_y(0) { SetValues(valobj_list); @@ -2639,10 +2657,8 @@ public: m_first_visible_row = 0; m_num_rows = 0; m_rows.clear(); - m_valobj_list = valobj_list; - const size_t num_values = m_valobj_list.GetSize(); - for (size_t i = 0; i < num_values; ++i) - m_rows.push_back(Row(m_valobj_list.GetValueObjectAtIndex(i), nullptr)); + for (auto &valobj_sp : valobj_list.GetObjects()) + m_rows.push_back(Row(valobj_sp, nullptr)); } bool WindowDelegateDraw(Window &window, bool force) override { @@ -2733,8 +2749,11 @@ public: case 'B': case 'f': // Change the format for the currently selected item - if (m_selected_row) - m_selected_row->valobj->SetFormat(FormatForChar(c)); + if (m_selected_row) { + auto valobj_sp = m_selected_row->value.GetSP(); + if (valobj_sp) + valobj_sp->SetFormat(FormatForChar(c)); + } return eKeyHandled; case 't': @@ -2812,7 +2831,6 @@ public: } protected: - ValueObjectList m_valobj_list; std::vector m_rows; Row *m_selected_row; uint32_t m_selected_row_idx; @@ -2859,7 +2877,7 @@ protected: bool DisplayRowObject(Window &window, Row &row, DisplayOptions &options, bool highlight, bool last_child) { - ValueObject *valobj = row.valobj.get(); + ValueObject *valobj = row.value.GetSP().get(); if (valobj == nullptr) return false; @@ -2941,18 +2959,19 @@ protected: ++m_num_rows; } - if (row.expanded && !row.children.empty()) { - DisplayRows(window, row.children, options); + auto &children = row.GetChildren(); + if (row.expanded && !children.empty()) { + DisplayRows(window, children, options); } } } - int CalculateTotalNumberRows(const std::vector &rows) { + int CalculateTotalNumberRows(std::vector &rows) { int row_count = 0; - for (const auto &row : rows) { + for (auto &row : rows) { ++row_count; if (row.expanded) - row_count += CalculateTotalNumberRows(row.children); + row_count += CalculateTotalNumberRows(row.GetChildren()); } return row_count; } @@ -2963,8 +2982,9 @@ protected: return &row; else { --row_index; - if (row.expanded && !row.children.empty()) { - Row *result = GetRowForRowIndexImpl(row.children, row_index); + auto &children = row.GetChildren(); + if (row.expanded && !children.empty()) { + Row *result = GetRowForRowIndexImpl(children, row_index); if (result) return result; } diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp index d8870d69b64a..fc2312d60d57 100644 --- a/lldb/source/Core/ValueObject.cpp +++ b/lldb/source/Core/ValueObject.cpp @@ -3352,3 +3352,98 @@ void ValueObject::SetSyntheticChildrenGenerated(bool b) { uint64_t ValueObject::GetLanguageFlags() { return m_language_flags; } void ValueObject::SetLanguageFlags(uint64_t flags) { m_language_flags = flags; } + +ValueObjectManager::ValueObjectManager(lldb::ValueObjectSP in_valobj_sp, + lldb::DynamicValueType use_dynamic, + bool use_synthetic) : m_root_valobj_sp(), + m_user_valobj_sp(), m_use_dynamic(use_dynamic), m_stop_id(UINT32_MAX), + m_use_synthetic(use_synthetic) { + if (!in_valobj_sp) + return; + // If the user passes in a value object that is dynamic or synthetic, then + // water it down to the static type. + m_root_valobj_sp = in_valobj_sp->GetQualifiedRepresentationIfAvailable(lldb::eNoDynamicValues, false); +} + +bool ValueObjectManager::IsValid() const { + if (!m_root_valobj_sp) + return false; + lldb::TargetSP target_sp = GetTargetSP(); + if (target_sp) + return target_sp->IsValid(); + return false; +} + +lldb::ValueObjectSP ValueObjectManager::GetSP() { + lldb::ProcessSP process_sp = GetProcessSP(); + if (!process_sp) + return lldb::ValueObjectSP(); + + const uint32_t current_stop_id = process_sp->GetLastNaturalStopID(); + if (current_stop_id == m_stop_id) + return m_user_valobj_sp; + + m_stop_id = current_stop_id; + + if (!m_root_valobj_sp) { + m_user_valobj_sp.reset(); + return m_root_valobj_sp; + } + + m_user_valobj_sp = m_root_valobj_sp; + + if (m_use_dynamic != lldb::eNoDynamicValues) { + lldb::ValueObjectSP dynamic_sp = m_user_valobj_sp->GetDynamicValue(m_use_dynamic); + if (dynamic_sp) + m_user_valobj_sp = dynamic_sp; + } + + if (m_use_synthetic) { + lldb::ValueObjectSP synthetic_sp = m_user_valobj_sp->GetSyntheticValue(m_use_synthetic); + if (synthetic_sp) + m_user_valobj_sp = synthetic_sp; + } + + return m_user_valobj_sp; +} + +void ValueObjectManager::SetUseDynamic(lldb::DynamicValueType use_dynamic) { + if (use_dynamic != m_use_dynamic) { + m_use_dynamic = use_dynamic; + m_user_valobj_sp.reset(); + m_stop_id = UINT32_MAX; + } +} + +void ValueObjectManager::SetUseSynthetic(bool use_synthetic) { + if (m_use_synthetic != use_synthetic) { + m_use_synthetic = use_synthetic; + m_user_valobj_sp.reset(); + m_stop_id = UINT32_MAX; + } +} + +lldb::TargetSP ValueObjectManager::GetTargetSP() const { + if (!m_root_valobj_sp) + return m_root_valobj_sp->GetTargetSP(); + return lldb::TargetSP(); +} + +lldb::ProcessSP ValueObjectManager::GetProcessSP() const { + if (m_root_valobj_sp) + return m_root_valobj_sp->GetProcessSP(); + return lldb::ProcessSP(); +} + +lldb::ThreadSP ValueObjectManager::GetThreadSP() const { + if (m_root_valobj_sp) + return m_root_valobj_sp->GetThreadSP(); + return lldb::ThreadSP(); +} + +lldb::StackFrameSP ValueObjectManager::GetFrameSP() const { + if (m_root_valobj_sp) + return m_root_valobj_sp->GetFrameSP(); + return lldb::StackFrameSP(); +} +