Skip to content

Commit

Permalink
[lldb][libc++] Adds valarray data formatters.
Browse files Browse the repository at this point in the history
The code is heavily based on the vector data formatter.
  • Loading branch information
mordante committed Feb 4, 2024
1 parent 3bcb1f2 commit 12b03c9
Show file tree
Hide file tree
Showing 7 changed files with 254 additions and 0 deletions.
1 change: 1 addition & 0 deletions lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ add_lldb_library(lldbPluginCPlusPlusLanguage PLUGIN
LibCxxTuple.cpp
LibCxxUnorderedMap.cpp
LibCxxVariant.cpp
LibCxxValarray.cpp
LibCxxVector.cpp
LibStdcpp.cpp
LibStdcppTuple.cpp
Expand Down
9 changes: 9 additions & 0 deletions lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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",
Expand Down
4 changes: 4 additions & 0 deletions lldb/source/Plugins/Language/CPlusPlus/LibCxx.h
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,10 @@ SyntheticChildrenFrontEnd *
LibcxxStdVectorSyntheticFrontEndCreator(CXXSyntheticChildren *,
lldb::ValueObjectSP);

SyntheticChildrenFrontEnd *
LibcxxStdValarraySyntheticFrontEndCreator(CXXSyntheticChildren *,
lldb::ValueObjectSP);

SyntheticChildrenFrontEnd *
LibcxxStdListSyntheticFrontEndCreator(CXXSyntheticChildren *,
lldb::ValueObjectSP);
Expand Down
140 changes: 140 additions & 0 deletions lldb/source/Plugins/Language/CPlusPlus/LibCxxValarray.cpp
Original file line number Diff line number Diff line change
@@ -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 <optional>

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<uint64_t> 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);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
CXX_SOURCES := main.cpp

USE_LIBCPP := 1

include Makefile.rules
Original file line number Diff line number Diff line change
@@ -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<int>) 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<double>) va_double"'],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#include <iostream>
#include <valarray>

int main() {

std::valarray<int> 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<double> va_double({1.0, 0.5, 0.25, 0.125});

std::cout << "break here\n";
}

0 comments on commit 12b03c9

Please sign in to comment.