[Lldb-commits] [lldb] r172282 - in /lldb/trunk: include/lldb/Core/ source/Core/ test/functionalities/data-formatter/data-formatter-stl/libcxx/string/

Enrico Granata egranata at apple.com
Fri Jan 11 17:00:22 PST 2013


Author: enrico
Date: Fri Jan 11 19:00:22 2013
New Revision: 172282

URL: http://llvm.org/viewvc/llvm-project?rev=172282&view=rev
Log:
<rdar://problem/12239827>

Providing a data formatter for libc++ std::wstring
In the process, refactoring the std::string data formatter to be written in C++ so that commonalities between the two can be exploited
Also, providing a new API on the ValueObject to navigate a hierarchy by index-path
Lastly, an appropriate test case is included


Added:
    lldb/trunk/test/functionalities/data-formatter/data-formatter-stl/libcxx/string/
    lldb/trunk/test/functionalities/data-formatter/data-formatter-stl/libcxx/string/Makefile
    lldb/trunk/test/functionalities/data-formatter/data-formatter-stl/libcxx/string/TestDataFormatterLibcxxString.py
    lldb/trunk/test/functionalities/data-formatter/data-formatter-stl/libcxx/string/main.cpp
Modified:
    lldb/trunk/include/lldb/Core/CXXFormatterFunctions.h
    lldb/trunk/include/lldb/Core/ValueObject.h
    lldb/trunk/source/Core/CXXFormatterFunctions.cpp
    lldb/trunk/source/Core/FormatManager.cpp
    lldb/trunk/source/Core/ValueObject.cpp

Modified: lldb/trunk/include/lldb/Core/CXXFormatterFunctions.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/CXXFormatterFunctions.h?rev=172282&r1=172281&r2=172282&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Core/CXXFormatterFunctions.h (original)
+++ lldb/trunk/include/lldb/Core/CXXFormatterFunctions.h Fri Jan 11 19:00:22 2013
@@ -49,6 +49,12 @@
         bool
         WCharStringSummaryProvider (ValueObject& valobj, Stream& stream); // wchar_t*
         
+        bool
+        LibcxxStringSummaryProvider (ValueObject& valobj, Stream& stream); // libc++ std::string
+
+        bool
+        LibcxxWStringSummaryProvider (ValueObject& valobj, Stream& stream); // libc++ std::wstring
+        
         template<bool name_entries>
         bool
         NSDictionarySummaryProvider (ValueObject& valobj, Stream& stream);

Modified: lldb/trunk/include/lldb/Core/ValueObject.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/ValueObject.h?rev=172282&r1=172281&r2=172282&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Core/ValueObject.h (original)
+++ lldb/trunk/include/lldb/Core/ValueObject.h Fri Jan 11 19:00:22 2013
@@ -734,6 +734,23 @@
     virtual lldb::ValueObjectSP
     GetChildAtIndex (uint32_t idx, bool can_create);
 
+    // this will always create the children if necessary
+    lldb::ValueObjectSP
+    GetChildAtIndexPath (const std::initializer_list<uint32_t> &idxs,
+                         uint32_t* index_of_error = NULL);
+    
+    lldb::ValueObjectSP
+    GetChildAtIndexPath (const std::vector<uint32_t> &idxs,
+                         uint32_t* index_of_error = NULL);
+    
+    lldb::ValueObjectSP
+    GetChildAtIndexPath (const std::initializer_list< std::pair<uint32_t, bool> > &idxs,
+                         uint32_t* index_of_error = NULL);
+
+    lldb::ValueObjectSP
+    GetChildAtIndexPath (const std::vector< std::pair<uint32_t, bool> > &idxs,
+                         uint32_t* index_of_error = NULL);
+    
     virtual lldb::ValueObjectSP
     GetChildMemberWithName (const ConstString &name, bool can_create);
 

Modified: lldb/trunk/source/Core/CXXFormatterFunctions.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/CXXFormatterFunctions.cpp?rev=172282&r1=172281&r2=172282&view=diff
==============================================================================
--- lldb/trunk/source/Core/CXXFormatterFunctions.cpp (original)
+++ lldb/trunk/source/Core/CXXFormatterFunctions.cpp Fri Jan 11 19:00:22 2013
@@ -158,8 +158,9 @@
     // if not UTF8, I need a conversion function to return proper UTF8
     if (origin_encoding != 8 && !ConvertFunction)
         return false;
-    const int bufferSPSize = 1024;
-    const int sourceSize = (bufferSPSize / (origin_encoding >> 2));
+
+    const int sourceSize = process_sp->GetTarget().GetMaximumSizeOfStringSummary();
+    const int bufferSPSize = sourceSize * (origin_encoding >> 2);
 
     Error error;
     lldb::DataBufferSP buffer_sp(new DataBufferHeap(bufferSPSize,0));
@@ -218,6 +219,9 @@
             utf8_data_end_ptr = (UTF8*)data_end_ptr;
         }
         
+        // since we tend to accept partial data (and even partially malformed data)
+        // we might end up with no NULL terminator before the end_ptr
+        // hence we need to take a slower route and ensure we stay within boundaries
         for (;utf8_data_ptr != utf8_data_end_ptr; utf8_data_ptr++)
         {
             if (!*utf8_data_ptr)
@@ -290,9 +294,14 @@
     if (!process_sp)
         return false;
 
-    lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
+    lldb::addr_t data_addr = 0;
+    
+    if (valobj.IsPointerType())
+        data_addr = valobj.GetValueAsUnsigned(0);
+    else if (valobj.IsArrayType())
+        data_addr = valobj.GetAddressOf();
 
-    if (!valobj_addr)
+    if (data_addr == 0 || data_addr == LLDB_INVALID_ADDRESS)
         return false;
 
     clang::ASTContext* ast = valobj.GetClangAST();
@@ -306,21 +315,21 @@
     {
         case 8:
             // utf 8
-            return ReadUTFBufferAndDumpToStream<UTF8, nullptr>(valobj_addr,
+            return ReadUTFBufferAndDumpToStream<UTF8, nullptr>(data_addr,
                                                                process_sp,
                                                                stream,
                                                                'L',
                                                                true); // but use quotes
         case 16:
             // utf 16
-            return ReadUTFBufferAndDumpToStream<UTF16, ConvertUTF16toUTF8>(valobj_addr,
+            return ReadUTFBufferAndDumpToStream<UTF16, ConvertUTF16toUTF8>(data_addr,
                                                                            process_sp,
                                                                            stream,
                                                                            'L',
                                                                            true); // but use quotes
         case 32:
             // utf 32
-            return ReadUTFBufferAndDumpToStream<UTF32, ConvertUTF32toUTF8>(valobj_addr,
+            return ReadUTFBufferAndDumpToStream<UTF32, ConvertUTF32toUTF8>(data_addr,
                                                                            process_sp,
                                                                            stream,
                                                                            'L',
@@ -332,6 +341,86 @@
     return true;
 }
 
+// this function extracts information from a libcxx std::basic_string<>
+// irregardless of template arguments. it reports the size (in item count not bytes)
+// and the location in memory where the string data can be found
+static bool
+ExtractLibcxxStringInfo (ValueObject& valobj,
+                         ValueObjectSP &location_sp,
+                         uint64_t& size)
+{
+    ValueObjectSP D(valobj.GetChildAtIndexPath({0,0,0,0}));
+    if (!D)
+        return false;
+    
+    ValueObjectSP size_mode(D->GetChildAtIndexPath({1,0,0}));
+    if (!size_mode)
+        return false;
+    
+    uint64_t size_mode_value(size_mode->GetValueAsUnsigned(0));
+    
+    if ((size_mode_value & 1) == 0) // this means the string is in short-mode and the data is stored inline
+    {
+        ValueObjectSP s(D->GetChildAtIndex(1, true));
+        if (!s)
+            return false;
+        size = ((size_mode_value >> 1) % 256);
+        location_sp = s->GetChildAtIndex(1, true);
+        return (location_sp.get() != nullptr);
+    }
+    else
+    {
+        ValueObjectSP l(D->GetChildAtIndex(0, true));
+        if (!l)
+            return false;
+        location_sp = l->GetChildAtIndex(2, true);
+        ValueObjectSP size_vo(l->GetChildAtIndex(1, true));
+        if (!size_vo || !location_sp)
+            return false;
+        size = size_vo->GetValueAsUnsigned(0);
+        return true;
+    }
+}
+
+bool
+lldb_private::formatters::LibcxxWStringSummaryProvider (ValueObject& valobj, Stream& stream)
+{
+    uint64_t size = 0;
+    ValueObjectSP location_sp((ValueObject*)nullptr);
+    if (!ExtractLibcxxStringInfo(valobj, location_sp, size))
+        return false;
+    if (size == 0)
+    {
+        stream.Printf("L\"\"");
+        return true;
+    }
+    if (!location_sp)
+        return false;
+    return WCharStringSummaryProvider(*location_sp.get(), stream);
+}
+
+bool
+lldb_private::formatters::LibcxxStringSummaryProvider (ValueObject& valobj, Stream& stream)
+{
+    uint64_t size = 0;
+    ValueObjectSP location_sp((ValueObject*)nullptr);
+    if (!ExtractLibcxxStringInfo(valobj, location_sp, size))
+        return false;
+    if (size == 0)
+    {
+        stream.Printf("\"\"");
+        return true;
+    }
+    if (!location_sp)
+        return false;
+    Error error;
+    location_sp->ReadPointedString(stream,
+                                   error,
+                                   0, // max length is decided by the settings
+                                   false); // do not honor array (terminates on first 0 byte even for a char[])
+    return error.Success();
+}
+
 template<bool name_entries>
 bool
 lldb_private::formatters::NSDictionarySummaryProvider (ValueObject& valobj, Stream& stream)

Modified: lldb/trunk/source/Core/FormatManager.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/FormatManager.cpp?rev=172282&r1=172281&r2=172282&view=diff
==============================================================================
--- lldb/trunk/source/Core/FormatManager.cpp (original)
+++ lldb/trunk/source/Core/FormatManager.cpp Fri Jan 11 19:00:22 2013
@@ -844,9 +844,12 @@
     .SetHideItemNames(false);
     
 #ifndef LLDB_DISABLE_PYTHON
-    std::string code("     lldb.formatters.cpp.libcxx.stdstring_SummaryProvider(valobj,internal_dict)");
-    lldb::TypeSummaryImplSP std_string_summary_sp(new ScriptSummaryFormat(stl_summary_flags, "lldb.formatters.cpp.libcxx.stdstring_SummaryProvider",code.c_str()));
+    //std::string code("     lldb.formatters.cpp.libcxx.stdstring_SummaryProvider(valobj,internal_dict)");
+    //lldb::TypeSummaryImplSP std_string_summary_sp(new ScriptSummaryFormat(stl_summary_flags, "lldb.formatters.cpp.libcxx.stdstring_SummaryProvider",code.c_str()));
     
+    lldb::TypeSummaryImplSP std_string_summary_sp(new CXXFunctionSummaryFormat(stl_summary_flags, lldb_private::formatters::LibcxxStringSummaryProvider, "std::string summary provider"));
+    lldb::TypeSummaryImplSP std_wstring_summary_sp(new CXXFunctionSummaryFormat(stl_summary_flags, lldb_private::formatters::LibcxxWStringSummaryProvider, "std::wstring summary provider"));
+
     TypeCategoryImpl::SharedPointer libcxx_category_sp = GetCategory(m_libcxx_category_name);
     
     libcxx_category_sp->GetSummaryNavigator()->Add(ConstString("std::__1::string"),
@@ -854,6 +857,11 @@
     libcxx_category_sp->GetSummaryNavigator()->Add(ConstString("std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >"),
                                                    std_string_summary_sp);
 
+    libcxx_category_sp->GetSummaryNavigator()->Add(ConstString("std::__1::wstring"),
+                                                   std_wstring_summary_sp);
+    libcxx_category_sp->GetSummaryNavigator()->Add(ConstString("std::__1::basic_string<wchar_t, std::__1::char_traits<wchar_t>, std::__1::allocator<wchar_t> >"),
+                                                   std_wstring_summary_sp);
+    
     SyntheticChildren::Flags stl_synth_flags;
     stl_synth_flags.SetCascades(true).SetSkipPointers(false).SetSkipReferences(false);
     

Modified: lldb/trunk/source/Core/ValueObject.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/ValueObject.cpp?rev=172282&r1=172281&r2=172282&view=diff
==============================================================================
--- lldb/trunk/source/Core/ValueObject.cpp (original)
+++ lldb/trunk/source/Core/ValueObject.cpp Fri Jan 11 19:00:22 2013
@@ -533,6 +533,86 @@
     return child_sp;
 }
 
+ValueObjectSP
+ValueObject::GetChildAtIndexPath (const std::initializer_list<uint32_t>& idxs,
+                                  uint32_t* index_of_error)
+{
+    if (idxs.size() == 0)
+        return GetSP();
+    ValueObjectSP root(GetSP());
+    for (uint32_t idx : idxs)
+    {
+        root = root->GetChildAtIndex(idx, true);
+        if (!root)
+        {
+            if (index_of_error)
+                *index_of_error = idx;
+            return root;
+        }
+    }
+    return root;
+}
+
+ValueObjectSP
+ValueObject::GetChildAtIndexPath (const std::initializer_list< std::pair<uint32_t, bool> >& idxs,
+                                  uint32_t* index_of_error)
+{
+    if (idxs.size() == 0)
+        return GetSP();
+    ValueObjectSP root(GetSP());
+    for (std::pair<uint32_t, bool> idx : idxs)
+    {
+        root = root->GetChildAtIndex(idx.first, idx.second);
+        if (!root)
+        {
+            if (index_of_error)
+                *index_of_error = idx.first;
+            return root;
+        }
+    }
+    return root;
+}
+
+lldb::ValueObjectSP
+ValueObject::GetChildAtIndexPath (const std::vector<uint32_t> &idxs,
+                                  uint32_t* index_of_error)
+{
+    if (idxs.size() == 0)
+        return GetSP();
+    ValueObjectSP root(GetSP());
+    for (uint32_t idx : idxs)
+    {
+        root = root->GetChildAtIndex(idx, true);
+        if (!root)
+        {
+            if (index_of_error)
+                *index_of_error = idx;
+            return root;
+        }
+    }
+    return root;
+}
+
+lldb::ValueObjectSP
+ValueObject::GetChildAtIndexPath (const std::vector< std::pair<uint32_t, bool> > &idxs,
+                                  uint32_t* index_of_error)
+{
+    if (idxs.size() == 0)
+        return GetSP();
+    ValueObjectSP root(GetSP());
+    for (std::pair<uint32_t, bool> idx : idxs)
+    {
+        root = root->GetChildAtIndex(idx.first, idx.second);
+        if (!root)
+        {
+            if (index_of_error)
+                *index_of_error = idx.first;
+            return root;
+        }
+    }
+    return root;
+}
+
 uint32_t
 ValueObject::GetIndexOfChildWithName (const ConstString &name)
 {

Added: lldb/trunk/test/functionalities/data-formatter/data-formatter-stl/libcxx/string/Makefile
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/data-formatter/data-formatter-stl/libcxx/string/Makefile?rev=172282&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/data-formatter/data-formatter-stl/libcxx/string/Makefile (added)
+++ lldb/trunk/test/functionalities/data-formatter/data-formatter-stl/libcxx/string/Makefile Fri Jan 11 19:00:22 2013
@@ -0,0 +1,8 @@
+LEVEL = ../../../../../make
+
+CXX_SOURCES := main.cpp
+
+include $(LEVEL)/Makefile.rules
+
+CXXFLAGS += -stdlib=libc++ -O0
+LDFLAGS += -stdlib=libc++
\ No newline at end of file

Added: lldb/trunk/test/functionalities/data-formatter/data-formatter-stl/libcxx/string/TestDataFormatterLibcxxString.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/data-formatter/data-formatter-stl/libcxx/string/TestDataFormatterLibcxxString.py?rev=172282&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/data-formatter/data-formatter-stl/libcxx/string/TestDataFormatterLibcxxString.py (added)
+++ lldb/trunk/test/functionalities/data-formatter/data-formatter-stl/libcxx/string/TestDataFormatterLibcxxString.py Fri Jan 11 19:00:22 2013
@@ -0,0 +1,81 @@
+#coding=utf8
+"""
+Test lldb data formatter subsystem.
+"""
+
+import os, time
+import unittest2
+import lldb
+from lldbtest import *
+import lldbutil
+
+class LibcxxStringDataFormatterTestCase(TestBase):
+
+    mydir = os.path.join("functionalities", "data-formatter", "data-formatter-stl", "libcxx", "string")
+
+    @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
+    @dsym_test
+    def test_with_dsym_and_run_command(self):
+        """Test data formatter commands."""
+        self.buildDsym()
+        self.data_formatter_commands()
+
+    @skipOnLinux # No standard locations for libc++ on Linux, so skip for now 
+    @dwarf_test
+    def test_with_dwarf_and_run_command(self):
+        """Test data formatter commands."""
+        self.buildDwarf()
+        self.data_formatter_commands()
+
+    def setUp(self):
+        # Call super's setUp().
+        TestBase.setUp(self)
+        # Find the line number to break at.
+        self.line = line_number('main.cpp', '// Set break point at this line.')
+
+    def data_formatter_commands(self):
+        """Test that that file and class static variables display correctly."""
+        self.runCmd("file a.out", CURRENT_EXECUTABLE_SET)
+
+        lldbutil.run_break_set_by_file_and_line (self, "main.cpp", self.line, num_expected_locations=-1)
+
+        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'])
+
+        # This is the function to remove the custom formats in order to have a
+        # clean slate for the next test case.
+        def cleanup():
+            self.runCmd('type format clear', check=False)
+            self.runCmd('type summary clear', check=False)
+            self.runCmd('type filter clear', check=False)
+            self.runCmd('type synth clear', check=False)
+            self.runCmd("settings set target.max-children-count 256", check=False)
+
+        # Execute the cleanup function during test case tear down.
+        self.addTearDownHook(cleanup)
+
+        self.expect("frame variable",
+                    substrs = ['(std::__1::wstring) s = L"hello world! מזל טוב!"',
+                    '(std::__1::wstring) S = L"!!!!"',
+                    '(const wchar_t *) mazeltov = 0x','L"מזל טוב"',
+                    '(std::__1::string) q = "hello world"',
+                    '(std::__1::string) Q = "quite a long std::strin with lots of info inside it"'])
+
+        self.runCmd("n")
+
+        self.expect("frame variable",
+                    substrs = ['(std::__1::wstring) s = L"hello world! מזל טוב!"',
+                    '(std::__1::wstring) S = L"!!!!!"',
+                    '(const wchar_t *) mazeltov = 0x','L"מזל טוב"',
+                    '(std::__1::string) q = "hello world"',
+                    '(std::__1::string) Q = "quite a long std::strin with lots of info inside it"'])
+
+if __name__ == '__main__':
+    import atexit
+    lldb.SBDebugger.Initialize()
+    atexit.register(lambda: lldb.SBDebugger.Terminate())
+    unittest2.main()

Added: lldb/trunk/test/functionalities/data-formatter/data-formatter-stl/libcxx/string/main.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/test/functionalities/data-formatter/data-formatter-stl/libcxx/string/main.cpp?rev=172282&view=auto
==============================================================================
--- lldb/trunk/test/functionalities/data-formatter/data-formatter-stl/libcxx/string/main.cpp (added)
+++ lldb/trunk/test/functionalities/data-formatter/data-formatter-stl/libcxx/string/main.cpp Fri Jan 11 19:00:22 2013
@@ -0,0 +1,12 @@
+#include <string>
+
+int main()
+{
+    std::wstring s(L"hello world! מזל טוב!");
+    std::wstring S(L"!!!!");
+    const wchar_t *mazeltov = L"מזל טוב";
+    std::string q("hello world");
+    std::string Q("quite a long std::strin with lots of info inside it");
+    S.assign(L"!!!!!"); // Set break point at this line.
+    return 0;
+}
\ No newline at end of file





More information about the lldb-commits mailing list