diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/string/simulator/Makefile b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/string/simulator/Makefile new file mode 100644 index 0000000000000..38cfa81053488 --- /dev/null +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/string/simulator/Makefile @@ -0,0 +1,3 @@ +CXX_SOURCES := main.cpp +override CXXFLAGS_EXTRAS += -std=c++14 +include Makefile.rules diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/string/simulator/TestDataFormatterLibcxxStringSimulator.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/string/simulator/TestDataFormatterLibcxxStringSimulator.py new file mode 100644 index 0000000000000..76cd64660aab0 --- /dev/null +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/string/simulator/TestDataFormatterLibcxxStringSimulator.py @@ -0,0 +1,45 @@ +""" +Test we can understand various layouts of the libc++'s std::string +""" + + + +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class LibcxxStringDataFormatterSimulatorTestCase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + NO_DEBUG_INFO_TESTCASE = True + + def _run_test(self, defines): + cxxflags_extras = " ".join(["-D%s" % d for d in defines]) + self.build(dictionary=dict(CXXFLAGS_EXTRAS=cxxflags_extras)) + lldbutil.run_to_source_breakpoint(self, '// Break here', + lldb.SBFileSpec("main.cpp")) + self.expect_var_path("shortstring", summary='"short"') + self.expect_var_path("longstring", summary='"I am a very long string"') + + def test_v1_layout(self): + """ Current v1 layout. """ + self._run_test([]) + + def test_v2_layout(self): + """ Current v2 layout. """ + self._run_test(["ALTERNATE_LAYOUT"]) + + def test_v1_layout_bitmasks(self): + """ Pre-D123580 v1 layout. """ + self._run_test(["BITMASKS"]) + + def test_v2_layout_bitmasks(self): + """ Pre-D123580 v2 layout. """ + self._run_test(["ALTERNATE_LAYOUT", "BITMASKS"]) + + def test_v2_layout_subclass_padding(self): + """ Pre-c3d0205ee771 v2 layout. """ + self._run_test(["ALTERNATE_LAYOUT", "BITMASKS", "SUBCLASS_PADDING"]) + diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/string/simulator/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/string/simulator/main.cpp new file mode 100644 index 0000000000000..4852dfd456687 --- /dev/null +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/string/simulator/main.cpp @@ -0,0 +1,217 @@ +#include +#include +#include + +namespace std { +namespace __lldb { + +template ::value && !std::is_final<_Tp>::value> +struct __compressed_pair_elem { + explicit __compressed_pair_elem(_Tp __t) : __value_(__t) {} + + _Tp &__get() { return __value_; } + +private: + _Tp __value_; +}; + +template +struct __compressed_pair_elem<_Tp, _Idx, true> : private _Tp { + explicit __compressed_pair_elem(_Tp __t) : _Tp(__t) {} + + _Tp &__get() { return *this; } +}; + +template +class __compressed_pair : private __compressed_pair_elem<_T1, 0>, + private __compressed_pair_elem<_T2, 1> { +public: + using _Base1 = __compressed_pair_elem<_T1, 0>; + using _Base2 = __compressed_pair_elem<_T2, 1>; + + explicit __compressed_pair(_T1 __t1, _T2 __t2) : _Base1(__t1), _Base2(__t2) {} + + _T1 &first() { return static_cast<_Base1 &>(*this).__get(); } +}; + +#if defined(ALTERNATE_LAYOUT) && defined(SUBCLASS_PADDING) +template struct __padding { + unsigned char __xx[sizeof(_CharT) - 1]; +}; + +template struct __padding<_CharT, 1> {}; +#endif + +template class basic_string { +public: + typedef _CharT value_type; + typedef _Allocator allocator_type; + typedef allocator_traits __alloc_traits; + typedef typename __alloc_traits::size_type size_type; + typedef typename __alloc_traits::pointer pointer; + +#ifdef ALTERNATE_LAYOUT + + struct __long { + pointer __data_; + size_type __size_; +#ifdef BITMASKS + size_type __cap_; +#else + size_type __cap_ : sizeof(size_type) * CHAR_BIT - 1; + size_type __is_long_ : 1; +#endif + }; + + enum { + __min_cap = (sizeof(__long) - 1) / sizeof(value_type) > 2 + ? (sizeof(__long) - 1) / sizeof(value_type) + : 2 + }; + + struct __short { + value_type __data_[__min_cap]; +#ifdef BITMASKS +#ifdef SUBCLASS_PADDING + struct : __padding { + unsigned char __size_; + }; +#else + unsigned char __padding[sizeof(value_type) - 1]; + unsigned char __size_; +#endif +#else // !BITMASKS + unsigned char __size_ : 7; + unsigned char __is_long_ : 1; +#endif + }; + +#ifdef BITMASKS +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + static const size_type __short_shift = 1; + static const size_type __long_mask = 0x1ul; +#else + static const size_type __short_shift = 0; + static const size_type __long_mask = ~(size_type(~0) >> 1); +#endif +#else // !BITMASKS +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + static const size_type __endian_factor = 2; +#else + static const size_type __endian_factor = 1; +#endif +#endif // BITMASKS + +#else // !ALTERNATE_LAYOUT + + struct __long { +#ifdef BITMASKS + size_type __cap_; +#else + size_type __is_long_ : 1; + size_type __cap_ : sizeof(size_type) * CHAR_BIT - 1; +#endif + size_type __size_; + pointer __data_; + }; + + enum { + __min_cap = (sizeof(__long) - 1) / sizeof(value_type) > 2 + ? (sizeof(__long) - 1) / sizeof(value_type) + : 2 + }; + + struct __short { + union { +#ifdef BITMASKS + unsigned char __size_; +#else + struct { + unsigned char __is_long_ : 1; + unsigned char __size_ : 7; + }; +#endif + value_type __lx; + }; + value_type __data_[__min_cap]; + }; + +#ifdef BITMASKS +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + static const size_type __short_shift = 0; + static const size_type __long_mask = ~(size_type(~0) >> 1); +#else + static const size_type __short_shift = 1; + static const size_type __long_mask = 0x1ul; +#endif +#else // !BITMASKS +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + static const size_type __endian_factor = 1; +#else + static const size_type __endian_factor = 2; +#endif +#endif + +#endif // ALTERNATE_LAYOUT + + union __ulx { + __long __lx; + __short __lxx; + }; + + enum { __n_words = sizeof(__ulx) / sizeof(size_type) }; + + struct __raw { + size_type __words[__n_words]; + }; + + struct __rep { + union { + __long __l; + __short __s; + __raw __r; + }; + }; + + __compressed_pair<__rep, allocator_type> __r_; + +public: + template + basic_string(unsigned char __size, const value_type (&__data)[__N]) + : __r_({}, {}) { + static_assert(__N < __min_cap, ""); +#ifdef BITMASKS + __r_.first().__s.__size_ = __size << __short_shift; +#else + __r_.first().__s.__size_ = __size; + __r_.first().__s.__is_long_ = false; +#endif + for (size_t __i = 0; __i < __N; ++__i) + __r_.first().__s.__data_[__i] = __data[__i]; + } + basic_string(size_t __cap, size_type __size, pointer __data) : __r_({}, {}) { +#ifdef BITMASKS + __r_.first().__l.__cap_ = __cap | __long_mask; +#else + __r_.first().__l.__cap_ = __cap / __endian_factor; + __r_.first().__l.__is_long_ = true; +#endif + __r_.first().__l.__size_ = __size; + __r_.first().__l.__data_ = __data; + } +}; + +using string = basic_string, std::allocator>; + +} // namespace __lldb +} // namespace std + +int main() { + char longdata[] = "I am a very long string"; + std::__lldb::string longstring(sizeof(longdata), sizeof(longdata) - 1, + longdata); + std::__lldb::string shortstring(5, "short"); + return 0; // Break here +}