Skip to content

Commit

Permalink
Add data formatter for libstdc++ tuple
Browse files Browse the repository at this point in the history
Differential revision: https://reviews.llvm.org/D25733

llvm-svn: 284829
  • Loading branch information
Tamas Berghammer committed Oct 21, 2016
1 parent 0789722 commit 7f15dba
Show file tree
Hide file tree
Showing 7 changed files with 185 additions and 0 deletions.
@@ -0,0 +1,8 @@
LEVEL = ../../../../../make

CXX_SOURCES := main.cpp

USE_LIBSTDCPP := 1
CFLAGS_EXTRAS += $(NO_LIMIT_DEBUG_INFO_FLAGS)

include $(LEVEL)/Makefile.rules
@@ -0,0 +1,49 @@
"""
Test lldb data formatter subsystem.
"""

from __future__ import print_function

import os
import time
import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil


class StdTupleDataFormatterTestCase(TestBase):
mydir = TestBase.compute_mydir(__file__)

@skipIfFreeBSD
@skipIfWindows # libstdcpp not ported to Windows
@skipIfDarwin # doesn't compile on Darwin
def test_with_run_command(self):
self.build()
self.runCmd("file a.out", CURRENT_EXECUTABLE_SET)

lldbutil.run_break_set_by_source_regexp(
self, "Set break point at this line.")
self.runCmd("run", RUN_SUCCEEDED)

# The stop reason of the thread should be breakpoint.
self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
substrs=['stopped', 'stop reason = breakpoint'])

frame = self.frame()
self.assertTrue(frame.IsValid())

self.expect("frame variable ti", substrs=['[0] = 1'])
self.expect("frame variable ts", substrs=['[0] = "foobar"'])
self.expect("frame variable tt", substrs=['[0] = 1', '[1] = "baz"', '[2] = 2'])

self.assertEqual(1, frame.GetValueForVariablePath("ti[0]").GetValueAsUnsigned())
self.assertFalse(frame.GetValueForVariablePath("ti[1]").IsValid())

self.assertEqual('"foobar"', frame.GetValueForVariablePath("ts[0]").GetSummary())
self.assertFalse(frame.GetValueForVariablePath("ts[1]").IsValid())

self.assertEqual(1, frame.GetValueForVariablePath("tt[0]").GetValueAsUnsigned())
self.assertEqual('"baz"', frame.GetValueForVariablePath("tt[1]").GetSummary())
self.assertEqual(2, frame.GetValueForVariablePath("tt[2]").GetValueAsUnsigned())
self.assertFalse(frame.GetValueForVariablePath("tt[3]").IsValid())
@@ -0,0 +1,9 @@
#include <memory>
#include <string>

int main() {
std::tuple<int> ti{1};
std::tuple<std::string> ts{"foobar"};
std::tuple<int, std::string, int> tt{1, "baz", 2};
return 0; // Set break point at this line.
}
1 change: 1 addition & 0 deletions lldb/source/Plugins/Language/CPlusPlus/CMakeLists.txt
Expand Up @@ -11,4 +11,5 @@ add_lldb_library(lldbPluginCPlusPlusLanguage
LibCxxVector.cpp
LibStdcpp.cpp
LibStdcppSmartPointer.cpp
LibStdcppTuple.cpp
)
5 changes: 5 additions & 0 deletions lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
Expand Up @@ -811,6 +811,11 @@ static void LoadLibStdcppFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
lldb_private::formatters::LibStdcppSharedPtrSyntheticFrontEndCreator,
"std::weak_ptr synthetic children",
ConstString("^std::weak_ptr<.+>(( )?&)?$"), stl_synth_flags, true);
AddCXXSynthetic(
cpp_category_sp,
lldb_private::formatters::LibStdcppTupleSyntheticFrontEndCreator,
"std::tuple synthetic children", ConstString("^std::tuple<.+>(( )?&)?$"),
stl_synth_flags, true);

AddCXXSummary(cpp_category_sp,
lldb_private::formatters::LibStdcppSmartPointerSummaryProvider,
Expand Down
4 changes: 4 additions & 0 deletions lldb/source/Plugins/Language/CPlusPlus/LibStdcpp.h
Expand Up @@ -35,6 +35,10 @@ SyntheticChildrenFrontEnd *
LibstdcppMapIteratorSyntheticFrontEndCreator(CXXSyntheticChildren *,
lldb::ValueObjectSP);

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

SyntheticChildrenFrontEnd *
LibStdcppVectorIteratorSyntheticFrontEndCreator(CXXSyntheticChildren *,
lldb::ValueObjectSP);
Expand Down
109 changes: 109 additions & 0 deletions lldb/source/Plugins/Language/CPlusPlus/LibStdcppTuple.cpp
@@ -0,0 +1,109 @@
//===-- LibStdcppTuple.cpp --------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "LibStdcpp.h"

#include <memory>
#include <vector>

#include "lldb/Core/ConstString.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/DataFormatters/FormattersHelpers.h"
#include "lldb/DataFormatters/TypeSynthetic.h"

using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::formatters;

namespace {

class LibStdcppTupleSyntheticFrontEnd : public SyntheticChildrenFrontEnd {
public:
explicit LibStdcppTupleSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);

size_t CalculateNumChildren() override;

lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;

bool Update() override;

bool MightHaveChildren() override;

size_t GetIndexOfChildWithName(const ConstString &name) override;

private:
std::vector<ValueObjectSP> m_members;
};

} // end of anonymous namespace

LibStdcppTupleSyntheticFrontEnd::LibStdcppTupleSyntheticFrontEnd(
lldb::ValueObjectSP valobj_sp)
: SyntheticChildrenFrontEnd(*valobj_sp) {
Update();
}

bool LibStdcppTupleSyntheticFrontEnd::Update() {
m_members.clear();

ValueObjectSP valobj_backend_sp = m_backend.GetSP();
if (!valobj_backend_sp)
return false;

ValueObjectSP next_child_sp = valobj_backend_sp->GetNonSyntheticValue();
while (next_child_sp != nullptr) {
ValueObjectSP current_child = next_child_sp;
next_child_sp = nullptr;

size_t child_count = current_child->GetNumChildren();
for (size_t i = 0; i < child_count; ++i) {
ValueObjectSP child_sp = current_child->GetChildAtIndex(i, true);
llvm::StringRef name_str = child_sp->GetName().GetStringRef();
if (name_str.startswith("std::_Tuple_impl<")) {
next_child_sp = child_sp;
} else if (name_str.startswith("std::_Head_base<")) {
ValueObjectSP value_sp =
child_sp->GetChildMemberWithName(ConstString("_M_head_impl"), true);
if (value_sp) {
StreamString name;
name.Printf("[%zd]", m_members.size());
value_sp->SetName(ConstString(name.GetData()));

m_members.push_back(value_sp);
}
}
}
}

return false;
}

bool LibStdcppTupleSyntheticFrontEnd::MightHaveChildren() { return true; }

lldb::ValueObjectSP
LibStdcppTupleSyntheticFrontEnd::GetChildAtIndex(size_t idx) {
if (idx < m_members.size())
return m_members[idx];
return lldb::ValueObjectSP();
}

size_t LibStdcppTupleSyntheticFrontEnd::CalculateNumChildren() {
return m_members.size();
}

size_t LibStdcppTupleSyntheticFrontEnd::GetIndexOfChildWithName(
const ConstString &name) {
return ExtractIndexFromString(name.GetCString());
}

SyntheticChildrenFrontEnd *
lldb_private::formatters::LibStdcppTupleSyntheticFrontEndCreator(
CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
return (valobj_sp ? new LibStdcppTupleSyntheticFrontEnd(valobj_sp) : nullptr);
}

0 comments on commit 7f15dba

Please sign in to comment.