blob: 4edeaab6300030930a3b4bf044d9bded75e0a8cd [file] [log] [blame]
Tamas Berghammer07897222016-10-21 15:02:32 +00001//===-- LibStdcppSmartPointer.cpp -------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "LibStdcpp.h"
11
12#include "lldb/Core/ConstString.h"
13#include "lldb/Core/ValueObject.h"
14#include "lldb/DataFormatters/FormattersHelpers.h"
15#include "lldb/DataFormatters/TypeSynthetic.h"
16#include "lldb/Target/Target.h"
17
18#include <memory>
19#include <vector>
20
21using namespace lldb;
22using namespace lldb_private;
23using namespace lldb_private::formatters;
24
25namespace {
26
27class SharedPtrFrontEnd : public SyntheticChildrenFrontEnd {
28public:
29 explicit SharedPtrFrontEnd(lldb::ValueObjectSP valobj_sp);
30
31 size_t CalculateNumChildren() override;
32
33 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
34
35 bool Update() override;
36
37 bool MightHaveChildren() override;
38
39 size_t GetIndexOfChildWithName(const ConstString &name) override;
40
41 bool GetSummary(Stream &stream, const TypeSummaryOptions &options);
42
43private:
44 ValueObjectSP m_ptr_obj;
45 ValueObjectSP m_obj_obj;
46 ValueObjectSP m_use_obj;
47 ValueObjectSP m_weak_obj;
48
49 uint8_t m_ptr_size = 0;
50 lldb::ByteOrder m_byte_order = lldb::eByteOrderInvalid;
51
52 bool IsEmpty();
53 bool IsValid();
54};
55
56} // end of anonymous namespace
57
58SharedPtrFrontEnd::SharedPtrFrontEnd(lldb::ValueObjectSP valobj_sp)
59 : SyntheticChildrenFrontEnd(*valobj_sp) {
60 Update();
61}
62
63bool SharedPtrFrontEnd::Update() {
64 ValueObjectSP valobj_backend_sp = m_backend.GetSP();
65 if (!valobj_backend_sp)
66 return false;
67
68 ValueObjectSP valobj_sp = valobj_backend_sp->GetNonSyntheticValue();
69 if (!valobj_sp)
70 return false;
71
72 TargetSP target_sp(valobj_sp->GetTargetSP());
73 if (!target_sp)
74 return false;
75
76 m_byte_order = target_sp->GetArchitecture().GetByteOrder();
77 m_ptr_size = target_sp->GetArchitecture().GetAddressByteSize();
78
79 m_ptr_obj = valobj_sp->GetChildMemberWithName(ConstString("_M_ptr"), true);
80
81 m_use_obj = valobj_sp->GetChildAtNamePath({ConstString("_M_refcount"),
82 ConstString("_M_pi"),
83 ConstString("_M_use_count")});
84
85 m_weak_obj = valobj_sp->GetChildAtNamePath({ConstString("_M_refcount"),
86 ConstString("_M_pi"),
87 ConstString("_M_weak_count")});
88
89 // libstdc++ implements the weak usage count in a way that it is offset by 1
90 // if the strong count is not 0 (as part of a preformance optimization). We
91 // want to undo this before showing the weak count to the user as an offseted
92 // weak count would be very confusing.
93 if (m_use_obj && m_weak_obj && m_use_obj->GetValueAsUnsigned(0) > 0) {
94 bool success = false;
95 uint64_t count = m_weak_obj->GetValueAsUnsigned(0, &success) - 1;
96 if (success) {
97 auto data = std::make_shared<DataBufferHeap>(&count, sizeof(count));
98 m_weak_obj = CreateValueObjectFromData(
99 "weak_count", DataExtractor(data, m_byte_order, m_ptr_size),
100 m_weak_obj->GetExecutionContextRef(), m_weak_obj->GetCompilerType());
101 }
102 }
103
104 if (m_ptr_obj && !IsEmpty()) {
105 Error error;
106 m_obj_obj = m_ptr_obj->Dereference(error);
107 if (error.Success()) {
108 m_obj_obj->SetName(ConstString("object"));
109 }
110 }
111
112 return false;
113}
114
115bool SharedPtrFrontEnd::MightHaveChildren() { return true; }
116
117lldb::ValueObjectSP SharedPtrFrontEnd::GetChildAtIndex(size_t idx) {
118 if (idx == 0)
119 return m_obj_obj;
120 if (idx == 1)
121 return m_ptr_obj;
122 if (idx == 2)
123 return m_use_obj;
124 if (idx == 3)
125 return m_weak_obj;
126 return lldb::ValueObjectSP();
127}
128
129size_t SharedPtrFrontEnd::CalculateNumChildren() {
130 if (IsEmpty())
131 return 0;
132 return 1;
133}
134
135size_t SharedPtrFrontEnd::GetIndexOfChildWithName(const ConstString &name) {
136 if (name == ConstString("obj") || name == ConstString("object"))
137 return 0;
138 if (name == ConstString("ptr") || name == ConstString("pointer") ||
139 name == ConstString("_M_ptr"))
140 return 1;
141 if (name == ConstString("cnt") || name == ConstString("count") ||
142 name == ConstString("use_count") || name == ConstString("strong") ||
143 name == ConstString("_M_use_count"))
144 return 2;
145 if (name == ConstString("weak") || name == ConstString("weak_count") ||
146 name == ConstString("_M_weak_count"))
147 return 3;
148 return UINT32_MAX;
149}
150
151bool SharedPtrFrontEnd::GetSummary(Stream &stream,
152 const TypeSummaryOptions &options) {
153 if (!IsValid())
154 return false;
155
156 if (IsEmpty()) {
157 stream.Printf("nullptr");
158 } else {
159 Error error;
160 bool print_pointee = false;
161 if (m_obj_obj) {
162 if (m_obj_obj->DumpPrintableRepresentation(
163 stream, ValueObject::eValueObjectRepresentationStyleSummary,
164 lldb::eFormatInvalid,
165 ValueObject::ePrintableRepresentationSpecialCasesDisable,
166 false)) {
167 print_pointee = true;
168 }
169 }
170 if (!print_pointee)
171 stream.Printf("ptr = 0x%" PRIx64, m_ptr_obj->GetValueAsUnsigned(0));
172 }
173
174 if (m_use_obj && m_use_obj->GetError().Success())
175 stream.Printf(" strong=%" PRIu64, m_use_obj->GetValueAsUnsigned(0));
176
177 if (m_weak_obj && m_weak_obj->GetError().Success())
178 stream.Printf(" weak=%" PRIu64, m_weak_obj->GetValueAsUnsigned(0));
179
180 return true;
181}
182
183bool SharedPtrFrontEnd::IsValid() { return m_ptr_obj != nullptr; }
184
185bool SharedPtrFrontEnd::IsEmpty() {
186 return !IsValid() || m_ptr_obj->GetValueAsUnsigned(0) == 0 ||
187 (m_use_obj && m_use_obj->GetValueAsUnsigned(0) == 0);
188}
189
190SyntheticChildrenFrontEnd *
191lldb_private::formatters::LibStdcppSharedPtrSyntheticFrontEndCreator(
192 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
193 return valobj_sp ? new SharedPtrFrontEnd(valobj_sp) : nullptr;
194}
195
196bool lldb_private::formatters::LibStdcppSmartPointerSummaryProvider(
197 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
198 SharedPtrFrontEnd formatter(valobj.GetSP());
199 return formatter.GetSummary(stream, options);
200}