Skip to content
14 changes: 7 additions & 7 deletions lldb/source/Plugins/Language/CPlusPlus/CPlusPlusLanguage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1291,15 +1291,15 @@ 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);
category_sp->AddTypeSummary(
std::make_shared<lldb_private::TypeNameSpecifierImpl>(
string_ty, eFormatterMatchExact),
summary_sp);

category_sp->AddTypeSummary(
makeSpecifier(llvm::formatv("std::basic_string<{}>", char_ty).str()),
std::make_shared<lldb_private::TypeNameSpecifierImpl>(
llvm::formatv("std::basic_string<{}>", char_ty).str(),
eFormatterMatchExact),
summary_sp);

category_sp->AddTypeSummary(
Expand Down
20 changes: 17 additions & 3 deletions lldb/source/Plugins/Language/CPlusPlus/GenericList.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
}

Expand Down
16 changes: 10 additions & 6 deletions lldb/source/Plugins/Language/CPlusPlus/GenericOptional.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
26 changes: 24 additions & 2 deletions lldb/source/Plugins/Language/CPlusPlus/MsvcStlAtomic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "MsvcStl.h"

#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
#include "lldb/DataFormatters/TypeSynthetic.h"

using namespace lldb;
Expand Down Expand Up @@ -64,10 +65,31 @@ lldb_private::formatters::MsvcStlAtomicSyntheticFrontEnd::Update() {
if (!storage_sp)
return lldb::ChildCacheState::eRefetch;

m_element_type = m_backend.GetCompilerType().GetTypeTemplateArgument(0);
if (!m_element_type)
CompilerType backend_type = m_backend.GetCompilerType();
if (!backend_type)
return lldb::ChildCacheState::eRefetch;

m_element_type = backend_type.GetTypeTemplateArgument(0);
// PDB doesn't have info about templates, so this uses the return type of
// `load`. Which is equivalent to the template type.
if (!m_element_type) {
auto ast_ctx = backend_type.GetTypeSystem<TypeSystemClang>();
if (!ast_ctx)
return lldb::ChildCacheState::eRefetch;

clang::CXXRecordDecl *record_decl =
TypeSystemClang::GetAsCXXRecordDecl(backend_type.GetOpaqueQualType());
for (const auto *method : record_decl->methods()) {
if (method->getDeclName().isIdentifier() && method->getName() == "load") {
m_element_type = ast_ctx->GetType(method->getReturnType());
break;
}
}

if (!m_element_type)
return lldb::ChildCacheState::eRefetch;
}

m_storage = storage_sp.get();
return lldb::ChildCacheState::eRefetch;
}
Expand Down
17 changes: 10 additions & 7 deletions lldb/source/Plugins/Language/CPlusPlus/MsvcStlDeque.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand All @@ -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();
Expand Down
32 changes: 22 additions & 10 deletions lldb/source/Plugins/Language/CPlusPlus/MsvcStlVariant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;

Expand Down Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,13 @@ Error UdtRecordCompleter::visitKnownMember(
// Static constant members may be a const[expr] declaration.
// Query the symbol's value as the variable initializer if valid.
if (member_ct.IsConst() && member_ct.IsCompleteType()) {
std::string qual_name = decl->getQualifiedNameAsString();
std::string qual_name;
if (m_record.record.kind == Member::Struct)
qual_name = (m_cvr.cr.Name + "::" + static_data_member.Name).str();
else if (m_record.record.kind == Member::Union)
qual_name = (m_cvr.ur.Name + "::" + static_data_member.Name).str();
else
qual_name = decl->getQualifiedNameAsString();

auto results =
m_index.globals().findRecordsByName(qual_name, m_index.symrecords());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@


class StdAtomicTestCase(TestBase):
TEST_WITH_PDB_DEBUG_INFO = True

def get_variable(self, name):
var = self.frame().FindVariable(name)
var.SetPreferDynamicValue(lldb.eDynamicCanRunTarget)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@


class GenericDequeDataFormatterTestCase(TestBase):
TEST_WITH_PDB_DEBUG_INFO = True

def findVariable(self, name):
var = self.frame().FindVariable(name)
self.assertTrue(var.IsValid())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@


class TestDataFormatterGenericForwardList(TestBase):
TEST_WITH_PDB_DEBUG_INFO = True

def setUp(self):
TestBase.setUp(self)
self.line = line_number("main.cpp", "// break here")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@


class GenericListDataFormatterTestCase(TestBase):
TEST_WITH_PDB_DEBUG_INFO = True

def setUp(self):
# Call super's setUp().
TestBase.setUp(self)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@


class StdMapDataFormatterTestCase(TestBase):
TEST_WITH_PDB_DEBUG_INFO = True

def setUp(self):
TestBase.setUp(self)
ns = "ndk" if lldbplatformutil.target_is_android() else ""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@


class GenericMultiMapDataFormatterTestCase(TestBase):
TEST_WITH_PDB_DEBUG_INFO = True

def setUp(self):
TestBase.setUp(self)
self.namespace = "std"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@


class GenericMultiSetDataFormatterTestCase(TestBase):
TEST_WITH_PDB_DEBUG_INFO = True

def setUp(self):
TestBase.setUp(self)
self.namespace = "std"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@


class GenericOptionalDataFormatterTestCase(TestBase):
TEST_WITH_PDB_DEBUG_INFO = True

def do_test_with_run_command(self):
"""Test that that file and class static variables display correctly."""

Expand Down Expand Up @@ -55,7 +57,11 @@ def cleanup():
self.expect(
"frame var numbers",
substrs=[
"(optional_int_vect) numbers = Has Value=true {",
(
"(std::optional<std::vector<int, std::allocator<int>>>) numbers = Has Value=true {"
if self.getDebugInfo() == "pdb"
else "(optional_int_vect) numbers = Has Value=true {"
),
"Value = size=4 {",
"[0] = 1",
"[1] = 2",
Expand All @@ -69,7 +75,11 @@ def cleanup():
self.expect(
"frame var ostring",
substrs=[
"(optional_string) ostring = Has Value=true {",
(
"(std::optional<std::basic_string<char, std::char_traits<char>, std::allocator<char>>>) ostring = Has Value=true {"
if self.getDebugInfo() == "pdb"
else "(optional_string) ostring = Has Value=true {"
),
'Value = "hello"',
"}",
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@


class GenericSetDataFormatterTestCase(TestBase):
TEST_WITH_PDB_DEBUG_INFO = True

def setUp(self):
TestBase.setUp(self)
self.namespace = "std"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@


class TestCase(TestBase):
TEST_WITH_PDB_DEBUG_INFO = True

def do_test(self):
"""Test `frame variable` output for `std::shared_ptr` types."""
(_, process, _, bkpt) = lldbutil.run_to_source_breakpoint(
Expand Down Expand Up @@ -62,7 +64,7 @@ def do_test(self):
valobj = self.expect_var_path("sp_user", type="std::shared_ptr<User>")
self.assertRegex(
valobj.summary,
"element_type @ 0x0*[1-9a-f][0-9a-f]+( strong=1)? weak=0",
f"{"User" if self.getDebugInfo() == "pdb" else "element_type"} @ 0x0*[1-9a-f][0-9a-f]+( strong=1)? weak=0",
)
self.assertNotEqual(valobj.child[0].unsigned, 0)

Expand All @@ -77,7 +79,15 @@ def do_test(self):
self.assertEqual(str(valobj), '(User) *pointer = (id = 30, name = "steph")')

self.expect_var_path("sp_user->id", type="int", value="30")
self.expect_var_path("sp_user->name", type="std::string", summary='"steph"')
self.expect_var_path(
"sp_user->name",
type=(
"std::basic_string<char, std::char_traits<char>, std::allocator<char>>"
if self.getDebugInfo() == "pdb"
else "std::string"
),
summary='"steph"',
)

valobj = self.expect_var_path(
"si", type="std::shared_ptr<int>", summary="47 strong=2 weak=0"
Expand Down
Loading
Loading