forked from OSchip/llvm-project
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:
parent
42bfedd935
commit
5269875ef9
|
@ -0,0 +1,6 @@
|
|||
LEVEL = ../../../../../make
|
||||
|
||||
CXX_SOURCES := main.cpp
|
||||
|
||||
USE_LIBCPP := 1
|
||||
include $(LEVEL)/Makefile.rules
|
|
@ -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)
|
|
@ -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
|
||||
}
|
|
@ -5,6 +5,7 @@ add_lldb_library(lldbPluginCPlusPlusLanguage PLUGIN
|
|||
CxxStringTypes.cpp
|
||||
LibCxx.cpp
|
||||
LibCxxAtomic.cpp
|
||||
LibCxxBitset.cpp
|
||||
LibCxxInitializerList.cpp
|
||||
LibCxxList.cpp
|
||||
LibCxxMap.cpp
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -92,6 +92,10 @@ private:
|
|||
lldb::ByteOrder m_byte_order;
|
||||
};
|
||||
|
||||
SyntheticChildrenFrontEnd *
|
||||
LibcxxBitsetSyntheticFrontEndCreator(CXXSyntheticChildren *,
|
||||
lldb::ValueObjectSP);
|
||||
|
||||
SyntheticChildrenFrontEnd *
|
||||
LibcxxSharedPtrSyntheticFrontEndCreator(CXXSyntheticChildren *,
|
||||
lldb::ValueObjectSP);
|
||||
|
|
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue