1 //===-- LibStdcpp.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 // C Includes
13 // C++ Includes
14 // Other libraries and framework includes
15 // Project includes
16 #include "lldb/Core/DataBufferHeap.h"
17 #include "lldb/Core/Error.h"
18 #include "lldb/Core/Stream.h"
19 #include "lldb/Core/ValueObject.h"
20 #include "lldb/Core/ValueObjectConstResult.h"
21 #include "lldb/DataFormatters/StringPrinter.h"
22 #include "lldb/DataFormatters/VectorIterator.h"
23 #include "lldb/Host/Endian.h"
24 #include "lldb/Symbol/ClangASTContext.h"
25 #include "lldb/Target/Target.h"
26 
27 using namespace lldb;
28 using namespace lldb_private;
29 using namespace lldb_private::formatters;
30 
31 namespace
32 {
33 
34 class LibstdcppMapIteratorSyntheticFrontEnd : public SyntheticChildrenFrontEnd
35 {
36     /*
37      (std::_Rb_tree_iterator<std::pair<const int, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >) ibeg = {
38      (_Base_ptr) _M_node = 0x0000000100103910 {
39      (std::_Rb_tree_color) _M_color = _S_black
40      (std::_Rb_tree_node_base::_Base_ptr) _M_parent = 0x00000001001038c0
41      (std::_Rb_tree_node_base::_Base_ptr) _M_left = 0x0000000000000000
42      (std::_Rb_tree_node_base::_Base_ptr) _M_right = 0x0000000000000000
43      }
44      }
45      */
46 
47 public:
48     explicit LibstdcppMapIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
49 
50     size_t
51     CalculateNumChildren() override;
52 
53     lldb::ValueObjectSP
54     GetChildAtIndex(size_t idx) override;
55 
56     bool
57     Update() override;
58 
59     bool
60     MightHaveChildren() override;
61 
62     size_t
63     GetIndexOfChildWithName (const ConstString &name) override;
64 
65 private:
66     ExecutionContextRef m_exe_ctx_ref;
67     lldb::addr_t m_pair_address;
68     CompilerType m_pair_type;
69     lldb::ValueObjectSP m_pair_sp;
70 };
71 
72 class LibStdcppSharedPtrSyntheticFrontEnd : public SyntheticChildrenFrontEnd
73 {
74 public:
75     explicit LibStdcppSharedPtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
76 
77     size_t
78     CalculateNumChildren() override;
79 
80     lldb::ValueObjectSP
81     GetChildAtIndex(size_t idx) override;
82 
83     bool
84     Update() override;
85 
86     bool
87     MightHaveChildren() override;
88 
89     size_t
90     GetIndexOfChildWithName(const ConstString &name) override;
91 };
92 
93 } // end of anonymous namespace
94 
95 LibstdcppMapIteratorSyntheticFrontEnd::LibstdcppMapIteratorSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
96     SyntheticChildrenFrontEnd(*valobj_sp),
97     m_exe_ctx_ref(),
98     m_pair_address(0),
99     m_pair_type(),
100     m_pair_sp()
101 {
102     if (valobj_sp)
103         Update();
104 }
105 
106 bool
107 LibstdcppMapIteratorSyntheticFrontEnd::Update()
108 {
109     ValueObjectSP valobj_sp = m_backend.GetSP();
110     if (!valobj_sp)
111         return false;
112 
113     TargetSP target_sp(valobj_sp->GetTargetSP());
114 
115     if (!target_sp)
116         return false;
117 
118     bool is_64bit = (target_sp->GetArchitecture().GetAddressByteSize() == 8);
119 
120     if (!valobj_sp)
121         return false;
122     m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
123 
124     ValueObjectSP _M_node_sp(valobj_sp->GetChildMemberWithName(ConstString("_M_node"), true));
125     if (!_M_node_sp)
126         return false;
127 
128     m_pair_address = _M_node_sp->GetValueAsUnsigned(0);
129     if (m_pair_address == 0)
130         return false;
131 
132     m_pair_address += (is_64bit ? 32 : 16);
133 
134     CompilerType my_type(valobj_sp->GetCompilerType());
135     if (my_type.GetNumTemplateArguments() >= 1)
136     {
137         TemplateArgumentKind kind;
138         CompilerType pair_type = my_type.GetTemplateArgument(0, kind);
139         if (kind != eTemplateArgumentKindType && kind != eTemplateArgumentKindTemplate && kind != eTemplateArgumentKindTemplateExpansion)
140             return false;
141         m_pair_type = pair_type;
142     }
143     else
144         return false;
145 
146     return true;
147 }
148 
149 size_t
150 LibstdcppMapIteratorSyntheticFrontEnd::CalculateNumChildren ()
151 {
152     return 2;
153 }
154 
155 lldb::ValueObjectSP
156 LibstdcppMapIteratorSyntheticFrontEnd::GetChildAtIndex (size_t idx)
157 {
158     if (m_pair_address != 0 && m_pair_type)
159     {
160         if (!m_pair_sp)
161             m_pair_sp = CreateValueObjectFromAddress("pair", m_pair_address, m_exe_ctx_ref, m_pair_type);
162         if (m_pair_sp)
163             return m_pair_sp->GetChildAtIndex(idx, true);
164     }
165     return lldb::ValueObjectSP();
166 }
167 
168 bool
169 LibstdcppMapIteratorSyntheticFrontEnd::MightHaveChildren ()
170 {
171     return true;
172 }
173 
174 size_t
175 LibstdcppMapIteratorSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
176 {
177     if (name == ConstString("first"))
178         return 0;
179     if (name == ConstString("second"))
180         return 1;
181     return UINT32_MAX;
182 }
183 
184 SyntheticChildrenFrontEnd*
185 lldb_private::formatters::LibstdcppMapIteratorSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
186 {
187     return (valobj_sp ? new LibstdcppMapIteratorSyntheticFrontEnd(valobj_sp) : nullptr);
188 }
189 
190 /*
191  (lldb) fr var ibeg --ptr-depth 1
192  (__gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > >) ibeg = {
193  _M_current = 0x00000001001037a0 {
194  *_M_current = 1
195  }
196  }
197  */
198 
199 SyntheticChildrenFrontEnd*
200 lldb_private::formatters::LibStdcppVectorIteratorSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
201 {
202     static ConstString g_item_name;
203     if (!g_item_name)
204         g_item_name.SetCString("_M_current");
205     return (valobj_sp ? new VectorIteratorSyntheticFrontEnd(valobj_sp, g_item_name) : nullptr);
206 }
207 
208 lldb_private::formatters::VectorIteratorSyntheticFrontEnd::VectorIteratorSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp,
209                                                                                             ConstString item_name) :
210     SyntheticChildrenFrontEnd(*valobj_sp),
211     m_exe_ctx_ref(),
212     m_item_name(item_name),
213     m_item_sp()
214 {
215     if (valobj_sp)
216         Update();
217 }
218 
219 bool
220 VectorIteratorSyntheticFrontEnd::Update()
221 {
222     m_item_sp.reset();
223 
224     ValueObjectSP valobj_sp = m_backend.GetSP();
225     if (!valobj_sp)
226         return false;
227 
228     if (!valobj_sp)
229         return false;
230 
231     ValueObjectSP item_ptr(valobj_sp->GetChildMemberWithName(m_item_name,true));
232     if (!item_ptr)
233         return false;
234     if (item_ptr->GetValueAsUnsigned(0) == 0)
235         return false;
236     Error err;
237     m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
238     m_item_sp = CreateValueObjectFromAddress("item", item_ptr->GetValueAsUnsigned(0), m_exe_ctx_ref, item_ptr->GetCompilerType().GetPointeeType());
239     if (err.Fail())
240         m_item_sp.reset();
241     return false;
242 }
243 
244 size_t
245 VectorIteratorSyntheticFrontEnd::CalculateNumChildren()
246 {
247     return 1;
248 }
249 
250 lldb::ValueObjectSP
251 VectorIteratorSyntheticFrontEnd::GetChildAtIndex(size_t idx)
252 {
253     if (idx == 0)
254         return m_item_sp;
255     return lldb::ValueObjectSP();
256 }
257 
258 bool
259 VectorIteratorSyntheticFrontEnd::MightHaveChildren()
260 {
261     return true;
262 }
263 
264 size_t
265 VectorIteratorSyntheticFrontEnd::GetIndexOfChildWithName(const ConstString &name)
266 {
267     if (name == ConstString("item"))
268         return 0;
269     return UINT32_MAX;
270 }
271 
272 bool
273 lldb_private::formatters::LibStdcppStringSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
274 {
275     const bool scalar_is_load_addr = true;
276     AddressType addr_type;
277     lldb::addr_t addr_of_string = valobj.GetAddressOf(scalar_is_load_addr, &addr_type);
278     if (addr_of_string != LLDB_INVALID_ADDRESS)
279     {
280         switch (addr_type)
281         {
282             case eAddressTypeLoad:
283             {
284                 ProcessSP process_sp(valobj.GetProcessSP());
285                 if (!process_sp)
286                     return false;
287 
288                 StringPrinter::ReadStringAndDumpToStreamOptions options(valobj);
289                 Error error;
290                 lldb::addr_t addr_of_data = process_sp->ReadPointerFromMemory(addr_of_string, error);
291                 if (error.Fail() || addr_of_data == 0 || addr_of_data == LLDB_INVALID_ADDRESS)
292                     return false;
293                 options.SetLocation(addr_of_data);
294                 options.SetProcessSP(process_sp);
295                 options.SetStream(&stream);
296                 options.SetNeedsZeroTermination(false);
297                 options.SetBinaryZeroIsTerminator(true);
298                 lldb::addr_t size_of_data = process_sp->ReadPointerFromMemory(addr_of_string + process_sp->GetAddressByteSize(), error);
299                 if (error.Fail())
300                     return false;
301                 options.SetSourceSize(size_of_data);
302 
303                 if (!StringPrinter::ReadStringAndDumpToStream<StringPrinter::StringElementType::UTF8>(options))
304                 {
305                     stream.Printf("Summary Unavailable");
306                     return true;
307                 }
308                 else
309                     return true;
310             }
311                 break;
312             case eAddressTypeHost:
313                 break;
314             case eAddressTypeInvalid:
315             case eAddressTypeFile:
316                 break;
317         }
318     }
319     return false;
320 }
321 
322 bool
323 lldb_private::formatters::LibStdcppWStringSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
324 {
325     const bool scalar_is_load_addr = true;
326     AddressType addr_type;
327     lldb::addr_t addr_of_string = valobj.GetAddressOf(scalar_is_load_addr, &addr_type);
328     if (addr_of_string != LLDB_INVALID_ADDRESS)
329     {
330         switch (addr_type)
331         {
332             case eAddressTypeLoad:
333             {
334                 ProcessSP process_sp(valobj.GetProcessSP());
335                 if (!process_sp)
336                     return false;
337 
338                 CompilerType wchar_compiler_type = valobj.GetCompilerType().GetBasicTypeFromAST(lldb::eBasicTypeWChar);
339 
340                 if (!wchar_compiler_type)
341                     return false;
342 
343                 const uint32_t wchar_size = wchar_compiler_type.GetBitSize(nullptr); // Safe to pass NULL for exe_scope here
344 
345                 StringPrinter::ReadStringAndDumpToStreamOptions options(valobj);
346                 Error error;
347                 lldb::addr_t addr_of_data = process_sp->ReadPointerFromMemory(addr_of_string, error);
348                 if (error.Fail() || addr_of_data == 0 || addr_of_data == LLDB_INVALID_ADDRESS)
349                     return false;
350                 options.SetLocation(addr_of_data);
351                 options.SetProcessSP(process_sp);
352                 options.SetStream(&stream);
353                 options.SetNeedsZeroTermination(false);
354                 options.SetBinaryZeroIsTerminator(false);
355                 lldb::addr_t size_of_data = process_sp->ReadPointerFromMemory(addr_of_string + process_sp->GetAddressByteSize(), error);
356                 if (error.Fail())
357                     return false;
358                 options.SetSourceSize(size_of_data);
359                 options.SetPrefixToken("L");
360 
361                 switch (wchar_size)
362                 {
363                     case 8:
364                         return StringPrinter::ReadStringAndDumpToStream<StringPrinter::StringElementType::UTF8>(options);
365                     case 16:
366                         return StringPrinter::ReadStringAndDumpToStream<StringPrinter::StringElementType::UTF16>(options);
367                     case 32:
368                         return StringPrinter::ReadStringAndDumpToStream<StringPrinter::StringElementType::UTF32>(options);
369                     default:
370                         stream.Printf("size for wchar_t is not valid");
371                         return true;
372                 }
373                 return true;
374             }
375                 break;
376             case eAddressTypeHost:
377                 break;
378             case eAddressTypeInvalid:
379             case eAddressTypeFile:
380                 break;
381         }
382     }
383     return false;
384 }
385 
386 LibStdcppSharedPtrSyntheticFrontEnd::LibStdcppSharedPtrSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
387     : SyntheticChildrenFrontEnd(*valobj_sp)
388 {
389     if (valobj_sp)
390         Update();
391 }
392 
393 size_t
394 LibStdcppSharedPtrSyntheticFrontEnd::CalculateNumChildren()
395 {
396     return 1;
397 }
398 
399 lldb::ValueObjectSP
400 LibStdcppSharedPtrSyntheticFrontEnd::GetChildAtIndex(size_t idx)
401 {
402     ValueObjectSP valobj_sp = m_backend.GetSP();
403     if (!valobj_sp)
404         return lldb::ValueObjectSP();
405 
406     if (idx == 0)
407         return valobj_sp->GetChildMemberWithName(ConstString("_M_ptr"), true);
408     else
409         return lldb::ValueObjectSP();
410 }
411 
412 bool
413 LibStdcppSharedPtrSyntheticFrontEnd::Update()
414 {
415     return false;
416 }
417 
418 bool
419 LibStdcppSharedPtrSyntheticFrontEnd::MightHaveChildren()
420 {
421     return true;
422 }
423 
424 size_t
425 LibStdcppSharedPtrSyntheticFrontEnd::GetIndexOfChildWithName(const ConstString &name)
426 {
427     if (name == ConstString("_M_ptr"))
428         return 0;
429     return UINT32_MAX;
430 }
431 
432 SyntheticChildrenFrontEnd *
433 lldb_private::formatters::LibStdcppSharedPtrSyntheticFrontEndCreator(CXXSyntheticChildren *,
434                                                                      lldb::ValueObjectSP valobj_sp)
435 {
436     return (valobj_sp ? new LibStdcppSharedPtrSyntheticFrontEnd(valobj_sp) : nullptr);
437 }
438 
439 bool
440 lldb_private::formatters::LibStdcppSmartPointerSummaryProvider(ValueObject &valobj, Stream &stream,
441                                                                const TypeSummaryOptions &options)
442 {
443     ValueObjectSP valobj_sp(valobj.GetNonSyntheticValue());
444     if (!valobj_sp)
445         return false;
446 
447     ValueObjectSP ptr_sp(valobj_sp->GetChildMemberWithName(ConstString("_M_ptr"), true));
448     if (!ptr_sp)
449         return false;
450 
451     ValueObjectSP usecount_sp(
452         valobj_sp->GetChildAtNamePath({ConstString("_M_refcount"), ConstString("_M_pi"), ConstString("_M_use_count")}));
453     if (!usecount_sp)
454         return false;
455 
456     if (ptr_sp->GetValueAsUnsigned(0) == 0 || usecount_sp->GetValueAsUnsigned(0) == 0)
457     {
458         stream.Printf("nullptr");
459         return true;
460     }
461 
462     Error error;
463     ValueObjectSP pointee_sp = ptr_sp->Dereference(error);
464     if (pointee_sp && error.Success())
465     {
466         if (pointee_sp->DumpPrintableRepresentation(stream, ValueObject::eValueObjectRepresentationStyleSummary,
467                                                     lldb::eFormatInvalid,
468                                                     ValueObject::ePrintableRepresentationSpecialCasesDisable, false))
469         {
470             return true;
471         }
472     }
473 
474     stream.Printf("ptr = 0x%" PRIx64, ptr_sp->GetValueAsUnsigned(0));
475     return true;
476 }
477