From 12b03c9ff9f6ddb0a011d8f958e3a826bd7603b9 Mon Sep 17 00:00:00 2001 From: Mark de Wever Date: Sun, 4 Feb 2024 18:46:50 +0100 Subject: [PATCH] [lldb][libc++] Adds valarray data formatters. The code is heavily based on the vector data formatter. --- .../Plugins/Language/CPlusPlus/CMakeLists.txt | 1 + .../Language/CPlusPlus/CPlusPlusLanguage.cpp | 9 ++ .../Plugins/Language/CPlusPlus/LibCxx.h | 4 + .../Language/CPlusPlus/LibCxxValarray.cpp | 140 ++++++++++++++++++ .../libcxx/valarray/Makefile | 5 + .../TestDataFormatterLibcxxValarray.py | 78 ++++++++++ .../libcxx/valarray/main.cpp | 17 +++ 7 files changed, 254 insertions(+) create mode 100644 lldb/source/Plugins/Language/CPlusPlus/LibCxxValarray.cpp create mode 100644 lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/valarray/Makefile create mode 100644 lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/valarray/TestDataFormatterLibcxxValarray.py create mode 100644 lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/valarray/main.cpp diff --git a/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt b/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt index 21108b27896a1a..97fa894ea73761 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt +++ b/lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt @@ -17,6 +17,7 @@ add_lldb_library(lldbPluginCPlusPlusLanguage PLUGIN LibCxxTuple.cpp LibCxxUnorderedMap.cpp LibCxxVariant.cpp + LibCxxValarray.cpp LibCxxVector.cpp LibStdcpp.cpp LibStdcppTuple.cpp diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp index e0de80880376ac..af2f97f6b40ee6 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp +++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp @@ -750,6 +750,11 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { lldb_private::formatters::LibcxxStdVectorSyntheticFrontEndCreator, "libc++ std::vector synthetic children", "^std::__[[:alnum:]]+::vector<.+>$", stl_deref_flags, true); + AddCXXSynthetic( + cpp_category_sp, + lldb_private::formatters::LibcxxStdValarraySyntheticFrontEndCreator, + "libc++ std::valarray synthetic children", + "^std::__[[:alnum:]]+::valarray<.+>(( )?&)?$", stl_deref_flags, true); AddCXXSynthetic( cpp_category_sp, lldb_private::formatters::LibcxxStdForwardListSyntheticFrontEndCreator, @@ -871,6 +876,10 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) { lldb_private::formatters::LibcxxContainerSummaryProvider, "libc++ std::vector summary provider", "^std::__[[:alnum:]]+::vector<.+>$", stl_summary_flags, true); + AddCXXSummary( + cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, + "libc++ std::valarray summary provider", + "^std::__[[:alnum:]]+::valarray<.+>(( )?&)?$", stl_summary_flags, true); AddCXXSummary( cpp_category_sp, lldb_private::formatters::LibcxxContainerSummaryProvider, "libc++ std::list summary provider", diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h index 72da6b2426efec..a3fff03f2c6428 100644 --- a/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxx.h @@ -219,6 +219,10 @@ SyntheticChildrenFrontEnd * LibcxxStdVectorSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP); +SyntheticChildrenFrontEnd * +LibcxxStdValarraySyntheticFrontEndCreator(CXXSyntheticChildren *, + lldb::ValueObjectSP); + SyntheticChildrenFrontEnd * LibcxxStdListSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP); diff --git a/lldb/source/Plugins/Language/CPlusPlus/LibCxxValarray.cpp b/lldb/source/Plugins/Language/CPlusPlus/LibCxxValarray.cpp new file mode 100644 index 00000000000000..5ec4df3da3c900 --- /dev/null +++ b/lldb/source/Plugins/Language/CPlusPlus/LibCxxValarray.cpp @@ -0,0 +1,140 @@ +//===-- LibCxxValarray.cpp ------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "LibCxx.h" + +#include "lldb/Core/ValueObject.h" +#include "lldb/DataFormatters/FormattersHelpers.h" +#include + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::formatters; + +namespace lldb_private { +namespace formatters { +class LibcxxStdValarraySyntheticFrontEnd : public SyntheticChildrenFrontEnd { +public: + LibcxxStdValarraySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); + + ~LibcxxStdValarraySyntheticFrontEnd() override; + + size_t CalculateNumChildren() override; + + lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; + + bool Update() override; + + bool MightHaveChildren() override; + + size_t GetIndexOfChildWithName(ConstString name) override; + +private: + ValueObject *m_start = nullptr; + ValueObject *m_finish = nullptr; + CompilerType m_element_type; + uint32_t m_element_size = 0; +}; + +} // namespace formatters +} // namespace lldb_private + +lldb_private::formatters::LibcxxStdValarraySyntheticFrontEnd:: + LibcxxStdValarraySyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) + : SyntheticChildrenFrontEnd(*valobj_sp), m_element_type() { + if (valobj_sp) + Update(); +} + +lldb_private::formatters::LibcxxStdValarraySyntheticFrontEnd:: + ~LibcxxStdValarraySyntheticFrontEnd() { + // these need to stay around because they are child objects who will follow + // their parent's life cycle + // delete m_start; + // delete m_finish; +} + +size_t lldb_private::formatters::LibcxxStdValarraySyntheticFrontEnd:: + CalculateNumChildren() { + if (!m_start || !m_finish) + return 0; + uint64_t start_val = m_start->GetValueAsUnsigned(0); + uint64_t finish_val = m_finish->GetValueAsUnsigned(0); + + if (start_val == 0 || finish_val == 0) + return 0; + + if (start_val >= finish_val) + return 0; + + size_t num_children = (finish_val - start_val); + if (num_children % m_element_size) + return 0; + return num_children / m_element_size; +} + +lldb::ValueObjectSP +lldb_private::formatters::LibcxxStdValarraySyntheticFrontEnd::GetChildAtIndex( + size_t idx) { + if (!m_start || !m_finish) + return lldb::ValueObjectSP(); + + uint64_t offset = idx * m_element_size; + offset = offset + m_start->GetValueAsUnsigned(0); + StreamString name; + name.Printf("[%" PRIu64 "]", (uint64_t)idx); + return CreateValueObjectFromAddress(name.GetString(), offset, + m_backend.GetExecutionContextRef(), + m_element_type); +} + +bool lldb_private::formatters::LibcxxStdValarraySyntheticFrontEnd::Update() { + m_start = m_finish = nullptr; + + CompilerType type = m_backend.GetCompilerType(); + if (type.GetNumTemplateArguments() == 0) + return false; + + m_element_type = type.GetTypeTemplateArgument(0); + if (std::optional size = m_element_type.GetByteSize(nullptr)) + m_element_size = *size; + + if (m_element_size == 0) + return false; + + ValueObjectSP start = m_backend.GetChildMemberWithName("__begin_"); + ValueObjectSP finish = m_backend.GetChildMemberWithName("__end_"); + + if (!start || !finish) + return false; + + m_start = start.get(); + m_finish = finish.get(); + + return false; +} + +bool lldb_private::formatters::LibcxxStdValarraySyntheticFrontEnd:: + MightHaveChildren() { + return true; +} + +size_t lldb_private::formatters::LibcxxStdValarraySyntheticFrontEnd:: + GetIndexOfChildWithName(ConstString name) { + if (!m_start || !m_finish) + return UINT32_MAX; + return ExtractIndexFromString(name.GetCString()); +} + +lldb_private::SyntheticChildrenFrontEnd * +lldb_private::formatters::LibcxxStdValarraySyntheticFrontEndCreator( + CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { + if (!valobj_sp) + return nullptr; + return new LibcxxStdValarraySyntheticFrontEnd(valobj_sp); +} diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/valarray/Makefile b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/valarray/Makefile new file mode 100644 index 00000000000000..c5df567e01a2a7 --- /dev/null +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/valarray/Makefile @@ -0,0 +1,5 @@ +CXX_SOURCES := main.cpp + +USE_LIBCPP := 1 + +include Makefile.rules diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/valarray/TestDataFormatterLibcxxValarray.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/valarray/TestDataFormatterLibcxxValarray.py new file mode 100644 index 00000000000000..7b54b3485d04d4 --- /dev/null +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/valarray/TestDataFormatterLibcxxValarray.py @@ -0,0 +1,78 @@ +""" +Test lldb data formatter subsystem. +""" + + +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class LibcxxChronoDataFormatterTestCase(TestBase): + @add_test_categories(["libc++"]) + def test_with_run_command(self): + """Test that that file and class static variables display correctly.""" + self.build() + (self.target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint( + self, "break here", lldb.SBFileSpec("main.cpp", False) + ) + + self.expect( + "frame variable va_int", + substrs=[ + "va_int = size=4", + "[0] = 0", + "[1] = 0", + "[2] = 0", + "[3] = 0", + "}", + ], + ) + + lldbutil.continue_to_breakpoint(process, bkpt) + self.expect( + "frame variable va_int", + substrs=[ + "va_int = size=4", + "[0] = 1", + "[1] = 12", + "[2] = 123", + "[3] = 1234", + "}", + ], + ) + + # check access-by-index + self.expect("frame variable va_int[0]", substrs=["1"]) + self.expect("frame variable va_int[1]", substrs=["12"]) + self.expect("frame variable va_int[2]", substrs=["123"]) + self.expect("frame variable va_int[3]", substrs=["1234"]) + self.expect( + "frame variable va_int[4]", + error=True, + substrs=['array index 4 is not valid for "(valarray) va_int"'], + ) + + self.expect( + "frame variable va_double", + substrs=[ + "va_double = size=4", + "[0] = 1", + "[1] = 0.5", + "[2] = 0.25", + "[3] = 0.125", + "}", + ], + ) + + # check access-by-index + self.expect("frame variable va_double[0]", substrs=["1"]) + self.expect("frame variable va_double[1]", substrs=["0.5"]) + self.expect("frame variable va_double[2]", substrs=["0.25"]) + self.expect("frame variable va_double[3]", substrs=["0.125"]) + self.expect( + "frame variable va_double[4]", + error=True, + substrs=['array index 4 is not valid for "(valarray) va_double"'], + ) diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/valarray/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/valarray/main.cpp new file mode 100644 index 00000000000000..f32921e16fa10e --- /dev/null +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/valarray/main.cpp @@ -0,0 +1,17 @@ +#include +#include + +int main() { + + std::valarray va_int(4); + std::cout << "break here"; + + va_int[0] = 1; + va_int[1] = 12; + va_int[2] = 123; + va_int[3] = 1234; + + std::valarray va_double({1.0, 0.5, 0.25, 0.125}); + + std::cout << "break here\n"; +}