Add a data formatter for libc++ std::bitset

Reviewers: jingham, EricWF

Subscribers: mgorny, lldb-commits

Differential Revision: https://reviews.llvm.org/D39966

llvm-svn: 318145
This commit is contained in:
Pavel Labath 2017-11-14 11:15:03 +00:00
parent 42bfedd935
commit 5269875ef9
7 changed files with 197 additions and 0 deletions

View File

@ -0,0 +1,6 @@
LEVEL = ../../../../../make
CXX_SOURCES := main.cpp
USE_LIBCPP := 1
include $(LEVEL)/Makefile.rules

View File

@ -0,0 +1,46 @@
"""
Test lldb data formatter subsystem.
"""
from __future__ import print_function
import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil
class TestDataFormatterLibcxxBitset(TestBase):
mydir = TestBase.compute_mydir(__file__)
def setUp(self):
TestBase.setUp(self)
primes = [1]*300
primes[0] = primes[1] = 0
for i in range(2, len(primes)):
for j in range(2*i, len(primes), i):
primes[j] = 0
self.primes = primes
def check(self, name, size):
var = self.frame().FindVariable(name)
self.assertTrue(var.IsValid())
self.assertEqual(var.GetNumChildren(), size)
for i in range(size):
child = var.GetChildAtIndex(i)
self.assertEqual(child.GetValueAsUnsigned(), self.primes[i],
"variable: %s, index: %d"%(name, size))
@add_test_categories(["libc++"])
def test(self):
"""Test that std::bitset is displayed correctly"""
self.build()
lldbutil.run_to_source_breakpoint(self, '// break here',
lldb.SBFileSpec("main.cpp", False))
self.check("empty", 0)
self.check("small", 13)
self.check("large", 200)

View File

@ -0,0 +1,20 @@
#include <bitset>
template<std::size_t N>
void fill(std::bitset<N> &b) {
b.set();
b[0] = b[1] = false;
for (std::size_t i = 2; i < N; ++i) {
for (std::size_t j = 2*i; j < N; j+=i)
b[j] = false;
}
}
int main() {
std::bitset<0> empty;
std::bitset<13> small;
fill(small);
std::bitset<200> large;
fill(large);
return 0; // break here
}

View File

@ -5,6 +5,7 @@ add_lldb_library(lldbPluginCPlusPlusLanguage PLUGIN
CxxStringTypes.cpp
LibCxx.cpp
LibCxxAtomic.cpp
LibCxxBitset.cpp
LibCxxInitializerList.cpp
LibCxxList.cpp
LibCxxMap.cpp

View File

@ -420,6 +420,12 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
stl_synth_flags.SetCascades(true).SetSkipPointers(false).SetSkipReferences(
false);
AddCXXSynthetic(
cpp_category_sp,
lldb_private::formatters::LibcxxBitsetSyntheticFrontEndCreator,
"libc++ std::bitset synthetic children",
ConstString("^std::__(ndk)?1::bitset<.+>(( )?&)?$"), stl_synth_flags,
true);
AddCXXSynthetic(
cpp_category_sp,
lldb_private::formatters::LibcxxStdVectorSyntheticFrontEndCreator,
@ -509,6 +515,11 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
stl_summary_flags.SetDontShowChildren(false);
stl_summary_flags.SetSkipPointers(false);
AddCXXSummary(cpp_category_sp,
lldb_private::formatters::LibcxxContainerSummaryProvider,
"libc++ std::bitset summary provider",
ConstString("^std::__(ndk)?1::bitset<.+>(( )?&)?$"),
stl_summary_flags, true);
AddCXXSummary(cpp_category_sp,
lldb_private::formatters::LibcxxContainerSummaryProvider,
"libc++ std::vector summary provider",

View File

@ -92,6 +92,10 @@ private:
lldb::ByteOrder m_byte_order;
};
SyntheticChildrenFrontEnd *
LibcxxBitsetSyntheticFrontEndCreator(CXXSyntheticChildren *,
lldb::ValueObjectSP);
SyntheticChildrenFrontEnd *
LibcxxSharedPtrSyntheticFrontEndCreator(CXXSyntheticChildren *,
lldb::ValueObjectSP);

View File

@ -0,0 +1,109 @@
//===-- LibCxxBitset.cpp ----------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "LibCxx.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Target/Target.h"
using namespace lldb;
using namespace lldb_private;
namespace {
class BitsetFrontEnd : public SyntheticChildrenFrontEnd {
public:
BitsetFrontEnd(ValueObject &valobj);
size_t GetIndexOfChildWithName(const ConstString &name) override {
return formatters::ExtractIndexFromString(name.GetCString());
}
bool MightHaveChildren() override { return true; }
bool Update() override;
size_t CalculateNumChildren() override { return m_elements.size(); }
ValueObjectSP GetChildAtIndex(size_t idx) override;
private:
std::vector<ValueObjectSP> m_elements;
ValueObjectSP m_first;
CompilerType m_bool_type;
ByteOrder m_byte_order = eByteOrderInvalid;
uint8_t m_byte_size = 0;
};
} // namespace
BitsetFrontEnd::BitsetFrontEnd(ValueObject &valobj)
: SyntheticChildrenFrontEnd(valobj) {
m_bool_type = valobj.GetCompilerType().GetBasicTypeFromAST(eBasicTypeBool);
if (auto target_sp = m_backend.GetTargetSP()) {
m_byte_order = target_sp->GetArchitecture().GetByteOrder();
m_byte_size = target_sp->GetArchitecture().GetAddressByteSize();
Update();
}
}
bool BitsetFrontEnd::Update() {
m_elements.clear();
m_first.reset();
TargetSP target_sp = m_backend.GetTargetSP();
if (!target_sp)
return false;
size_t capping_size = target_sp->GetMaximumNumberOfChildrenToDisplay();
size_t size = 0;
auto value_and_type =
m_backend.GetCompilerType().GetIntegralTemplateArgument(0);
if (value_and_type.second)
size = value_and_type.first.getLimitedValue(capping_size);
m_elements.assign(size, ValueObjectSP());
m_first = m_backend.GetChildMemberWithName(ConstString("__first_"), true);
return false;
}
ValueObjectSP BitsetFrontEnd::GetChildAtIndex(size_t idx) {
if (idx >= m_elements.size() || !m_first)
return ValueObjectSP();
if (m_elements[idx])
return m_elements[idx];
ExecutionContext ctx = m_backend.GetExecutionContextRef().Lock(false);
CompilerType type;
ValueObjectSP chunk;
// For small bitsets __first_ is not an array, but a plain size_t.
if (m_first->GetCompilerType().IsArrayType(&type, nullptr, nullptr))
chunk = m_first->GetChildAtIndex(
idx / type.GetBitSize(ctx.GetBestExecutionContextScope()), true);
else {
type = m_first->GetCompilerType();
chunk = m_first;
}
if (!type || !chunk)
return ValueObjectSP();
size_t chunk_idx = idx % type.GetBitSize(ctx.GetBestExecutionContextScope());
uint8_t value = !!(chunk->GetValueAsUnsigned(0) & (uint64_t(1) << chunk_idx));
DataExtractor data(&value, sizeof(value), m_byte_order, m_byte_size);
m_elements[idx] = CreateValueObjectFromData(llvm::formatv("[{0}]", idx).str(),
data, ctx, m_bool_type);
return m_elements[idx];
}
SyntheticChildrenFrontEnd *formatters::LibcxxBitsetSyntheticFrontEndCreator(
CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
if (valobj_sp)
return new BitsetFrontEnd(*valobj_sp);
return nullptr;
}