-
Notifications
You must be signed in to change notification settings - Fork 14.7k
[LLDB] Make MSVC STL formatters work with (Native/DIA) PDB #150513
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
@llvm/pr-subscribers-lldb Author: nerix (Nerixyz) ChangesSome formatters for the MSVC STL didn't work with the PDB symbol file plugins. They were only tested with DWARF. The individual changes are quite small (except for variant), so I'm not sure if they should be separate PRs. The changes are broadly:
It also adds tests for both plugins. They are shell tests, because API tests currently only test with DWARF and after #149305 they'd only test with one plugin. They're not as exhaustive as the API tests - their goal is to show that when using PDB, the STL types are still properly shown. For Native PDB I found two bugs which I haven't inspected closer:
Patch is 21.91 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/150513.diff 7 Files Affected:
diff --git a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
index e69f2f677e9ab..cd7cda4c91f04 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
@@ -1335,31 +1335,25 @@ static void LoadLibCxxFormatters(lldb::TypeCategoryImplSP cpp_category_sp) {
static void RegisterStdStringSummaryProvider(
const lldb::TypeCategoryImplSP &category_sp, llvm::StringRef string_ty,
llvm::StringRef char_ty, lldb::TypeSummaryImplSP summary_sp) {
- auto makeSpecifier = [](llvm::StringRef name) {
- return std::make_shared<lldb_private::TypeNameSpecifierImpl>(
- name, eFormatterMatchExact);
- };
-
- category_sp->AddTypeSummary(makeSpecifier(string_ty), summary_sp);
-
- // std::basic_string<char>
category_sp->AddTypeSummary(
- makeSpecifier(llvm::formatv("std::basic_string<{}>", char_ty).str()),
+ std::make_shared<lldb_private::TypeNameSpecifierImpl>(
+ string_ty, eFormatterMatchExact),
summary_sp);
- // std::basic_string<char,std::char_traits<char>,std::allocator<char> >
+
+ // std::basic_string<char>
category_sp->AddTypeSummary(
- makeSpecifier(llvm::formatv("std::basic_string<{0},std::char_traits<{0}>,"
- "std::allocator<{0}> >",
- char_ty)
- .str()),
+ std::make_shared<lldb_private::TypeNameSpecifierImpl>(
+ llvm::formatv("std::basic_string<{}>", char_ty).str(),
+ eFormatterMatchExact),
summary_sp);
- // std::basic_string<char, std::char_traits<char>, std::allocator<char> >
+ // std::basic_string<char, std::char_traits<char>, std::allocator<char>>
category_sp->AddTypeSummary(
- makeSpecifier(
- llvm::formatv("std::basic_string<{0}, std::char_traits<{0}>, "
- "std::allocator<{0}> >",
+ std::make_shared<lldb_private::TypeNameSpecifierImpl>(
+ llvm::formatv("std::basic_string<{0}, ?std::char_traits<{0}>, "
+ "?std::allocator<{0}> ?>",
char_ty)
- .str()),
+ .str(),
+ eFormatterMatchRegex),
summary_sp);
}
diff --git a/lldb/source/Plugins/Language/CPlusPlus/GenericList.cpp b/lldb/source/Plugins/Language/CPlusPlus/GenericList.cpp
index ea1edbfd3ac9b..3d4dcfa3b4ff5 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/GenericList.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/GenericList.cpp
@@ -526,9 +526,17 @@ ValueObjectSP MsvcStlForwardListFrontEnd::GetChildAtIndex(uint32_t idx) {
lldb::ChildCacheState MsvcStlForwardListFrontEnd::Update() {
AbstractListFrontEnd::Update();
- if (auto head_sp =
- m_backend.GetChildAtNamePath({"_Mypair", "_Myval2", "_Myhead"}))
- m_head = head_sp.get();
+ auto head_sp =
+ m_backend.GetChildAtNamePath({"_Mypair", "_Myval2", "_Myhead"});
+ if (!head_sp)
+ return ChildCacheState::eRefetch;
+
+ m_head = head_sp.get();
+ if (!m_element_type) {
+ auto val_sp = head_sp->GetChildMemberWithName("_Myval");
+ if (val_sp)
+ m_element_type = val_sp->GetCompilerType();
+ }
return ChildCacheState::eRefetch;
}
@@ -606,6 +614,12 @@ lldb::ChildCacheState MsvcStlListFrontEnd::Update() {
m_head = first.get();
m_tail = last.get();
+ if (!m_element_type) {
+ auto val_sp = m_head->GetChildMemberWithName("_Myval");
+ if (val_sp)
+ m_element_type = val_sp->GetCompilerType();
+ }
+
return lldb::ChildCacheState::eRefetch;
}
diff --git a/lldb/source/Plugins/Language/CPlusPlus/GenericOptional.cpp b/lldb/source/Plugins/Language/CPlusPlus/GenericOptional.cpp
index 7fc6eb55d4e3e..f9c8c0be7420d 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/GenericOptional.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/GenericOptional.cpp
@@ -117,12 +117,16 @@ ValueObjectSP GenericOptionalFrontend::GetChildAtIndex(uint32_t _idx) {
ValueObjectSP candidate = val_sp->GetChildMemberWithName("_M_value");
if (candidate)
val_sp = candidate;
- } else if (m_stdlib == StdLib::MsvcStl)
- // Same issue as with LibCxx
- val_sp = m_backend.GetChildMemberWithName("_Has_value")
- ->GetParent()
- ->GetChildAtIndex(0)
- ->GetChildMemberWithName("_Value");
+ } else if (m_stdlib == StdLib::MsvcStl) {
+ // PDB flattens anonymous unions to the parent
+ val_sp = m_backend.GetChildMemberWithName("_Value");
+ // With DWARF and NativePDB, same issue as with LibCxx
+ if (!val_sp)
+ val_sp = m_backend.GetChildMemberWithName("_Has_value")
+ ->GetParent()
+ ->GetChildAtIndex(0)
+ ->GetChildMemberWithName("_Value");
+ }
if (!val_sp)
return ValueObjectSP();
diff --git a/lldb/source/Plugins/Language/CPlusPlus/MsvcStlDeque.cpp b/lldb/source/Plugins/Language/CPlusPlus/MsvcStlDeque.cpp
index 873354381a6da..aa313abb04be2 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/MsvcStlDeque.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/MsvcStlDeque.cpp
@@ -111,13 +111,6 @@ lldb_private::formatters::MsvcStlDequeSyntheticFrontEnd::Update() {
if (!block_size.IsValid())
return lldb::eRefetch;
- auto element_type = deque_type.GetTypeTemplateArgument(0);
- if (!element_type)
- return lldb::eRefetch;
- auto element_size = element_type.GetByteSize(nullptr);
- if (!element_size)
- return lldb::eRefetch;
-
auto offset_sp = storage_sp->GetChildMemberWithName("_Myoff");
auto map_size_sp = storage_sp->GetChildMemberWithName("_Mapsize");
auto map_sp = storage_sp->GetChildMemberWithName("_Map");
@@ -138,6 +131,16 @@ lldb_private::formatters::MsvcStlDequeSyntheticFrontEnd::Update() {
if (!ok)
return lldb::eRefetch;
+ auto element_type = deque_type.GetTypeTemplateArgument(0);
+ if (!element_type) {
+ element_type = map_sp->GetCompilerType().GetPointeeType().GetPointeeType();
+ if (!element_type)
+ return lldb::eRefetch;
+ }
+ auto element_size = element_type.GetByteSize(nullptr);
+ if (!element_size)
+ return lldb::eRefetch;
+
m_map = map_sp.get();
m_exe_ctx_ref = m_backend.GetExecutionContextRef();
m_block_size = block_size.ULongLong();
diff --git a/lldb/source/Plugins/Language/CPlusPlus/MsvcStlVariant.cpp b/lldb/source/Plugins/Language/CPlusPlus/MsvcStlVariant.cpp
index 52a3d98d2af4b..b3a93a0786740 100644
--- a/lldb/source/Plugins/Language/CPlusPlus/MsvcStlVariant.cpp
+++ b/lldb/source/Plugins/Language/CPlusPlus/MsvcStlVariant.cpp
@@ -42,7 +42,11 @@ namespace {
// }
ValueObjectSP GetStorageMember(ValueObject &valobj, llvm::StringRef name) {
- // Find the union
+ // DIA PDB flattens the union into the storage
+ if (valobj.GetNumChildrenIgnoringErrors(3) >= 2)
+ return valobj.GetChildMemberWithName(name);
+
+ // DWARF and NativePDB: Find the union
ValueObjectSP union_sp = valobj.GetChildAtIndex(0);
if (!union_sp)
return nullptr;
@@ -65,14 +69,18 @@ std::optional<int64_t> GetIndexValue(ValueObject &valobj) {
}
ValueObjectSP GetNthStorage(ValueObject &outer, int64_t index) {
- // We need to find the std::_Variant_storage base class.
-
- // -> std::_SMF_control (typedef to std::_Variant_base)
- ValueObjectSP container_sp = outer.GetSP()->GetChildAtIndex(0);
- if (!container_sp)
+ // navigate "down" to std::_SMF_control/std::_Variant_base
+ // by finding the holder of "_Which". This might be down a few levels if a
+ // variant member isn't trivally destructible/copyable/etc.
+ ValueObjectSP which_sp = outer.GetChildMemberWithName("_Which");
+ if (!which_sp)
+ return nullptr;
+ ValueObject *parent = which_sp->GetParent();
+ if (!parent)
return nullptr;
- // -> std::_Variant_storage
- container_sp = container_sp->GetChildAtIndex(0);
+
+ // Now go to std::_Variant_storage
+ ValueObjectSP container_sp = parent->GetChildAtIndex(0);
if (!container_sp)
return nullptr;
@@ -119,8 +127,12 @@ bool formatters::MsvcStlVariantSummaryProvider(
storage_type = storage_type.GetTypedefedType();
CompilerType active_type = storage_type.GetTypeTemplateArgument(1, true);
- if (!active_type)
- return false;
+ if (!active_type) {
+ ValueObjectSP head = GetHead(*storage);
+ active_type = head->GetCompilerType();
+ if (!active_type)
+ return false;
+ }
stream << " Active Type = " << active_type.GetDisplayTypeName() << " ";
return true;
diff --git a/lldb/test/Shell/SymbolFile/NativePDB/stl_types.test b/lldb/test/Shell/SymbolFile/NativePDB/stl_types.test
new file mode 100644
index 0000000000000..45960a80211e0
--- /dev/null
+++ b/lldb/test/Shell/SymbolFile/NativePDB/stl_types.test
@@ -0,0 +1,188 @@
+# REQUIRES: target-windows
+
+# Test that LLDB can format types from MSVC's STL
+# RUN: split-file %s %t
+# RUN: %build --compiler=clang-cl --std c++20 -o %t.exe -- %t/main.cpp
+# RUN: %lldb -f %t.exe -s \
+# RUN: %t/commands.input 2>&1 | FileCheck %s
+
+#--- main.cpp
+
+#include <bitset>
+#include <coroutine>
+#include <deque>
+#include <forward_list>
+#include <list>
+#include <map>
+#include <memory>
+#include <optional>
+#include <set>
+#include <string>
+#include <tuple>
+#include <unordered_map>
+#include <unordered_set>
+#include <variant>
+#include <vector>
+
+int main() {
+ std::shared_ptr<int> sp = std::make_shared<int>(41);
+ std::weak_ptr<int> wp = sp;
+ std::unique_ptr<int> unique(new int(42));
+ std::optional<std::u16string> opt = u"abc";
+ std::string str = "str";
+ std::u8string u8str = u8"str";
+ std::wstring wStr = L"wstr";
+ std::tuple<int, bool, float> tuple{1, false, 4.2};
+ std::coroutine_handle<> coroHandle;
+ std::bitset<16> bitset(123);
+
+ std::map<int, int> map{{1, 2}, {2, 4}, {3, 6}};
+ auto mapIt = map.find(3);
+ std::set<int> set{1, 2, 3};
+ std::multimap<int, int> mMap{{1, 2}, {1, 1}, {2, 4}};
+ std::multiset<int> mSet{1, 2, 3};
+
+ std::variant<int, float, std::string, std::monostate> variant = "wow";
+ std::list<int> list{1, 2, 3};
+ std::forward_list<int> fwList{1, 2, 3};
+
+ std::unordered_map<int, int> uMap{{1, 2}, {2, 4}, {3, 6}};
+ std::unordered_set<int> uSet{1, 2, 4};
+ std::unordered_multimap<int, int> uMMap{{1, 2}, {1, 1}, {2, 4}};
+ std::unordered_multiset<int> uMSet{1, 1, 2};
+ std::deque<int> deque{1, 2, 3};
+ std::vector<int> vec{1, 2, 3};
+ return 0; // break here
+}
+
+#--- commands.input
+
+br s -p "break here"
+r
+
+fr v sp
+fr v wp
+fr v unique
+# FIXME: _Has_value is put into the anonymous union along with _Value
+# fr v opt
+fr v str
+fr v u8str
+fr v wStr
+fr v tuple
+fr v map
+fr v mapIt
+fr v set
+fr v mMap
+fr v mSet
+fr v variant
+fr v list
+fr v fwList
+fr v uMap
+fr v uSet
+fr v uMMap
+fr v uMSet
+# FIXME: Static _Block_size is found but doesn't have a value
+# fr v deque
+fr v vec
+
+quit
+
+# CHECK: (lldb) fr v sp
+# CHECK-NEXT: (std::shared_ptr<int>) sp = 41 strong=1 weak=1 {
+# CHECK-NEXT: pointer = 0x{{.*}}
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v wp
+# CHECK-NEXT: (std::weak_ptr<int>) wp = 41 strong=1 weak=1 {
+# CHECK-NEXT: pointer = 0x{{.*}}
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v unique
+# CHECK-NEXT: (std::unique_ptr<int, std::default_delete<int>>) unique = 42 {
+# CHECK-NEXT: pointer = 0x{{.*}}
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v str
+# CHECK-NEXT: (std::basic_string<char, std::char_traits<char>, std::allocator<char>>) str = "str"
+# CHECK-NEXT: (lldb) fr v u8str
+# CHECK-NEXT: (std::basic_string<char8_t, std::char_traits<char8_t>, std::allocator<char8_t>>) u8str = u8"str"
+# CHECK-NEXT: (lldb) fr v wStr
+# CHECK-NEXT: (std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t>>) wStr = L"wstr"
+# CHECK-NEXT: (lldb) fr v tuple
+# CHECK-NEXT: (std::tuple<int, bool, float>) tuple = size=3 {
+# CHECK-NEXT: [0] = 1
+# CHECK-NEXT: [1] = false
+# CHECK-NEXT: [2] = 4.{{.*}}
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v map
+# CHECK-NEXT: (std::map<int, int, std::less<int>, std::allocator<std::pair<int const, int>>>) map = size=3 {
+# CHECK-NEXT: [0] = (first = 1, second = 2)
+# CHECK-NEXT: [1] = (first = 2, second = 4)
+# CHECK-NEXT: [2] = (first = 3, second = 6)
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v mapIt
+# CHECK-NEXT: (std::_Tree_iterator<std::_Tree_val<std::_Tree_simple_types<std::pair<int const, int>>>>) mapIt = {
+# CHECK-NEXT: first = 3
+# CHECK-NEXT: second = 6
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v set
+# CHECK-NEXT: (std::set<int, std::less<int>, std::allocator<int>>) set = size=3 {
+# CHECK-NEXT: [0] = 1
+# CHECK-NEXT: [1] = 2
+# CHECK-NEXT: [2] = 3
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v mMap
+# CHECK-NEXT: (std::multimap<int, int, std::less<int>, std::allocator<std::pair<int const, int>>>) mMap = size=3 {
+# CHECK-NEXT: [0] = (first = 1, second = 2)
+# CHECK-NEXT: [1] = (first = 1, second = 1)
+# CHECK-NEXT: [2] = (first = 2, second = 4)
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v mSet
+# CHECK-NEXT: (std::multiset<int, std::less<int>, std::allocator<int>>) mSet = size=3 {
+# CHECK-NEXT: [0] = 1
+# CHECK-NEXT: [1] = 2
+# CHECK-NEXT: [2] = 3
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v variant
+# CHECK-NEXT: (std::variant<int, float, std::basic_string<char, std::char_traits<char>, std::allocator<char>>, std::monostate>) variant = Active Type = std::basic_string<char, std::char_traits<char>, std::allocator<char>> {
+# CHECK-NEXT: Value = "wow"
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v list
+# CHECK-NEXT: (std::list<int, std::allocator<int>>) list = size=3 {
+# CHECK-NEXT: [0] = 1
+# CHECK-NEXT: [1] = 2
+# CHECK-NEXT: [2] = 3
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v fwList
+# CHECK-NEXT: (std::forward_list<int, std::allocator<int>>) fwList = size=3 {
+# CHECK-NEXT: [0] = 1
+# CHECK-NEXT: [1] = 2
+# CHECK-NEXT: [2] = 3
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v uMap
+# CHECK-NEXT: (std::unordered_map<int, int, std::hash<int>, std::equal_to<int>, std::allocator<std::pair<int const, int>>>) uMap = size=3 {
+# CHECK-NEXT: [0] = (first = 1, second = 2)
+# CHECK-NEXT: [1] = (first = 2, second = 4)
+# CHECK-NEXT: [2] = (first = 3, second = 6)
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v uSet
+# CHECK-NEXT: (std::unordered_set<int, std::hash<int>, std::equal_to<int>, std::allocator<int>>) uSet = size=3 {
+# CHECK-NEXT: [0] = 1
+# CHECK-NEXT: [1] = 2
+# CHECK-NEXT: [2] = 4
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v uMMap
+# CHECK-NEXT: (std::unordered_multimap<int, int, std::hash<int>, std::equal_to<int>, std::allocator<std::pair<int const, int>>>) uMMap = size=3 {
+# CHECK-NEXT: [0] = (first = 1, second = 2)
+# CHECK-NEXT: [1] = (first = 1, second = 1)
+# CHECK-NEXT: [2] = (first = 2, second = 4)
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v uMSet
+# CHECK-NEXT: (std::unordered_multiset<int, std::hash<int>, std::equal_to<int>, std::allocator<int>>) uMSet = size=3 {
+# CHECK-NEXT: [0] = 1
+# CHECK-NEXT: [1] = 1
+# CHECK-NEXT: [2] = 2
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v vec
+# CHECK-NEXT: (std::vector<int, std::allocator<int>>) vec = size=3 {
+# CHECK-NEXT: [0] = 1
+# CHECK-NEXT: [1] = 2
+# CHECK-NEXT: [2] = 3
+# CHECK-NEXT: }
diff --git a/lldb/test/Shell/SymbolFile/PDB/stl_types.test b/lldb/test/Shell/SymbolFile/PDB/stl_types.test
new file mode 100644
index 0000000000000..0472bf5f27f06
--- /dev/null
+++ b/lldb/test/Shell/SymbolFile/PDB/stl_types.test
@@ -0,0 +1,197 @@
+# REQUIRES: target-windows
+
+# Test that LLDB can format types from MSVC's STL
+# RUN: split-file %s %t
+# RUN: %build --compiler=clang-cl --std c++20 -o %t.exe -- %t/main.cpp
+# RUN: %lldb -f %t.exe -s \
+# RUN: %t/commands.input 2>&1 | FileCheck %s
+
+#--- main.cpp
+
+#include <bitset>
+#include <coroutine>
+#include <deque>
+#include <forward_list>
+#include <list>
+#include <map>
+#include <memory>
+#include <optional>
+#include <set>
+#include <string>
+#include <tuple>
+#include <unordered_map>
+#include <unordered_set>
+#include <variant>
+#include <vector>
+
+int main() {
+ std::shared_ptr<int> sp = std::make_shared<int>(41);
+ std::weak_ptr<int> wp = sp;
+ std::unique_ptr<int> unique(new int(42));
+ std::optional<std::u16string> opt = u"abc";
+ std::string str = "str";
+ std::u8string u8str = u8"str";
+ std::wstring wStr = L"wstr";
+ std::tuple<int, bool, float> tuple{1, false, 4.2};
+ std::coroutine_handle<> coroHandle;
+ std::bitset<16> bitset(123);
+
+ std::map<int, int> map{{1, 2}, {2, 4}, {3, 6}};
+ auto mapIt = map.find(3);
+ std::set<int> set{1, 2, 3};
+ std::multimap<int, int> mMap{{1, 2}, {1, 1}, {2, 4}};
+ std::multiset<int> mSet{1, 2, 3};
+
+ std::variant<int, float, std::string, std::monostate> variant = "wow";
+ std::list<int> list{1, 2, 3};
+ std::forward_list<int> fwList{1, 2, 3};
+
+ std::unordered_map<int, int> uMap{{1, 2}, {2, 4}, {3, 6}};
+ std::unordered_set<int> uSet{1, 2, 4};
+ std::unordered_multimap<int, int> uMMap{{1, 2}, {1, 1}, {2, 4}};
+ std::unordered_multiset<int> uMSet{1, 1, 2};
+ std::deque<int> deque{1, 2, 3};
+ std::vector<int> vec{1, 2, 3};
+ return 0; // break here
+}
+
+#--- commands.input
+
+br s -p "break here"
+r
+
+fr v sp
+fr v wp
+fr v unique
+fr v opt
+fr v str
+# FIXME: char8_t is not recognized as a type -
+# the string has a void pointer/void array for SSO storage.
+# fr v u8str
+fr v wStr
+fr v tuple
+fr v map
+fr v mapIt
+fr v set
+fr v mMap
+fr v mSet
+fr v variant
+fr v list
+fr v fwList
+fr v uMap
+fr v uSet
+fr v uMMap
+fr v uMSet
+# FIXME: Static _Block_size is found but doesn't have a value
+fr v deque
+fr v vec
+
+quit
+
+# CHECK: (lldb) fr v sp
+# CHECK-NEXT: (std::shared_ptr<int>) sp = 41 strong=1 weak=1 {
+# CHECK-NEXT: pointer = 0x{{.*}}
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v wp
+# CHECK-NEXT: (std::weak_ptr<int>) wp = 41 strong=1 weak=1 {
+# CHECK-NEXT: pointer = 0x{{.*}}
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v unique
+# CHECK-NEXT: (std::unique_ptr<int,std::default_delete<int> >) unique = 42 {
+# CHECK-NEXT: pointer = 0x{{.*}}
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v opt
+# CHECK-NEXT: (std::optional<std::basic_string<char16_t,std::char_traits<char16_t>,std::allocator<char16_t> > >) opt = Has Value=true {
+# CHECK-NEXT: Value = u"abc"
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v str
+# CHECK-NEXT: (std::basic_string<char,std::char_traits<char>,std::allocator<char> >) str = "str"
+# CHECK-NEXT: (lldb) fr v wStr
+# CHECK-NEXT: (std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t> >) wStr = L"wstr"
+# CHECK-NEXT: (lldb) fr v tuple
+# CHECK-NEXT: (std::tuple<int,bool,float>) tuple = size=3 {
+# CHECK-NEXT: [0] = 1
+# CHECK-NEXT: [1] = false
+# CHECK-NEXT: [2] = 4.{{.*}}
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v map
+# CHECK-NEXT: (std::map<int,int,std::less<int>,std::allocator<std::pair<const int,int> > >) map = size=3 {
+# CHECK-NEXT: [0] = (first = 1, second = 2)
+# CHECK-NEXT: [1] = (first = 2, second = 4)
+# CHECK-NEXT: [2] = (first = 3, second = 6)
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v mapIt
+# CHECK-NEXT: (std::_Tree_iterator<std::_Tree_val<std::_Tree_simple_types<std::pair<const int,int> > > >) mapIt = {
+# CHECK-NEXT: first = 3
+# CHECK-NEXT: second = 6
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v set
+# CHECK-NEXT: (std::set<int,std::less<int>,std::allocator<int> >) set = size=3 {
+# CHECK-NEXT: [0] = 1
+# CHECK-NEXT: [1] = 2
+# CHECK-NEXT: [2] = 3
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v mMap
+# CHECK-NEXT: (std::multimap<int,int,std::less<int>,std::allocator<std::pair<const int,int> > >) mMap = size=3 {
+# CHECK-NEXT: [0] = (first = 1, second = 2)
+# CHECK-NEXT: [1] = (first = 1, second = 1)
+# CHECK-NEXT: [2] = (first = 2, second = 4)
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v mSet
+# CHECK-NEXT: (std::multiset<int,std::less<int>,std::allocator<int> >) mSet = size=3 {
+# CHECK-NEXT: [0] = 1
+# CHECK-NEXT: [1] = 2
+# CHECK-NEXT: [2] = 3
+# CHECK-NEXT: }
+# CHECK-NEXT: (lldb) fr v variant
+# CHECK-NEXT: (std::variant<int,float,std::basic_string<char,std::char_traits<char>,std::allocator<char> >,std::monostate>) variant = Active Type = std::basic_string<char,std::char_traits<char>,std::allocator<char> > {
+# CHECK-NEXT: Value = "...
[truncated]
|
So the idea here is to have something tested, while we decide how to solve the multiple plugin situation? If so, sounds sensible to me. A bit unwieldy maybe but also you said they're not so comprehensive so it works out about the same I guess. |
Some formatters for the MSVC STL didn't work with the PDB symbol file plugins. They were only tested with DWARF. The individual changes are quite small (except for variant), so I'm not sure if they should be separate PRs.
The changes are broadly:
It also adds tests for both plugins. They are shell tests, because API tests currently only test with DWARF and after #149305 they'd only test with one plugin. They're not as exhaustive as the API tests - their goal is to show that when using PDB, the STL types are still properly shown.
For Native PDB I found two bugs which I haven't inspected closer:
std::optional
,_Has_value
got put into the union into a new struct that contained_Value
and_Has_value
.std::deque
uses a static constexpr_Block_size
which doesn't have a value with native PDB (works with DIA).