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 class LibstdcppMapIteratorSyntheticFrontEnd : public SyntheticChildrenFrontEnd
32 {
33 public:
34     LibstdcppMapIteratorSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);
35 
36     ~LibstdcppMapIteratorSyntheticFrontEnd() override = default;
37 
38     size_t
39     CalculateNumChildren() override;
40 
41     lldb::ValueObjectSP
42     GetChildAtIndex(size_t idx) override;
43 
44     bool
45     Update() override;
46 
47     bool
48     MightHaveChildren() override;
49 
50     size_t
51     GetIndexOfChildWithName (const ConstString &name) override;
52 
53 private:
54     ExecutionContextRef m_exe_ctx_ref;
55     lldb::addr_t m_pair_address;
56     CompilerType m_pair_type;
57     lldb::ValueObjectSP m_pair_sp;
58 };
59 
60 /*
61  (std::_Rb_tree_iterator<std::pair<const int, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >) ibeg = {
62  (_Base_ptr) _M_node = 0x0000000100103910 {
63  (std::_Rb_tree_color) _M_color = _S_black
64  (std::_Rb_tree_node_base::_Base_ptr) _M_parent = 0x00000001001038c0
65  (std::_Rb_tree_node_base::_Base_ptr) _M_left = 0x0000000000000000
66  (std::_Rb_tree_node_base::_Base_ptr) _M_right = 0x0000000000000000
67  }
68  }
69  */
70 
71 LibstdcppMapIteratorSyntheticFrontEnd::LibstdcppMapIteratorSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
72     SyntheticChildrenFrontEnd(*valobj_sp),
73     m_exe_ctx_ref(),
74     m_pair_address(0),
75     m_pair_type(),
76     m_pair_sp()
77 {
78     if (valobj_sp)
79         Update();
80 }
81 
82 bool
83 LibstdcppMapIteratorSyntheticFrontEnd::Update()
84 {
85     ValueObjectSP valobj_sp = m_backend.GetSP();
86     if (!valobj_sp)
87         return false;
88 
89     TargetSP target_sp(valobj_sp->GetTargetSP());
90 
91     if (!target_sp)
92         return false;
93 
94     bool is_64bit = (target_sp->GetArchitecture().GetAddressByteSize() == 8);
95 
96     if (!valobj_sp)
97         return false;
98     m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
99 
100     ValueObjectSP _M_node_sp(valobj_sp->GetChildMemberWithName(ConstString("_M_node"), true));
101     if (!_M_node_sp)
102         return false;
103 
104     m_pair_address = _M_node_sp->GetValueAsUnsigned(0);
105     if (m_pair_address == 0)
106         return false;
107 
108     m_pair_address += (is_64bit ? 32 : 16);
109 
110     CompilerType my_type(valobj_sp->GetCompilerType());
111     if (my_type.GetNumTemplateArguments() >= 1)
112     {
113         TemplateArgumentKind kind;
114         CompilerType pair_type = my_type.GetTemplateArgument(0, kind);
115         if (kind != eTemplateArgumentKindType && kind != eTemplateArgumentKindTemplate && kind != eTemplateArgumentKindTemplateExpansion)
116             return false;
117         m_pair_type = pair_type;
118     }
119     else
120         return false;
121 
122     return true;
123 }
124 
125 size_t
126 LibstdcppMapIteratorSyntheticFrontEnd::CalculateNumChildren ()
127 {
128     return 2;
129 }
130 
131 lldb::ValueObjectSP
132 LibstdcppMapIteratorSyntheticFrontEnd::GetChildAtIndex (size_t idx)
133 {
134     if (m_pair_address != 0 && m_pair_type)
135     {
136         if (!m_pair_sp)
137             m_pair_sp = CreateValueObjectFromAddress("pair", m_pair_address, m_exe_ctx_ref, m_pair_type);
138         if (m_pair_sp)
139             return m_pair_sp->GetChildAtIndex(idx, true);
140     }
141     return lldb::ValueObjectSP();
142 }
143 
144 bool
145 LibstdcppMapIteratorSyntheticFrontEnd::MightHaveChildren ()
146 {
147     return true;
148 }
149 
150 size_t
151 LibstdcppMapIteratorSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
152 {
153     if (name == ConstString("first"))
154         return 0;
155     if (name == ConstString("second"))
156         return 1;
157     return UINT32_MAX;
158 }
159 
160 SyntheticChildrenFrontEnd*
161 lldb_private::formatters::LibstdcppMapIteratorSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
162 {
163     return (valobj_sp ? new LibstdcppMapIteratorSyntheticFrontEnd(valobj_sp) : nullptr);
164 }
165 
166 /*
167  (lldb) fr var ibeg --ptr-depth 1
168  (__gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > >) ibeg = {
169  _M_current = 0x00000001001037a0 {
170  *_M_current = 1
171  }
172  }
173  */
174 
175 SyntheticChildrenFrontEnd*
176 lldb_private::formatters::LibStdcppVectorIteratorSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
177 {
178     static ConstString g_item_name;
179     if (!g_item_name)
180         g_item_name.SetCString("_M_current");
181     return (valobj_sp ? new VectorIteratorSyntheticFrontEnd(valobj_sp, g_item_name) : nullptr);
182 }
183 
184 lldb_private::formatters::VectorIteratorSyntheticFrontEnd::VectorIteratorSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp,
185                                                                                             ConstString item_name) :
186     SyntheticChildrenFrontEnd(*valobj_sp),
187     m_exe_ctx_ref(),
188     m_item_name(item_name),
189     m_item_sp()
190 {
191     if (valobj_sp)
192         Update();
193 }
194 
195 bool
196 lldb_private::formatters::VectorIteratorSyntheticFrontEnd::Update()
197 {
198     m_item_sp.reset();
199 
200     ValueObjectSP valobj_sp = m_backend.GetSP();
201     if (!valobj_sp)
202         return false;
203 
204     if (!valobj_sp)
205         return false;
206 
207     ValueObjectSP item_ptr(valobj_sp->GetChildMemberWithName(m_item_name,true));
208     if (!item_ptr)
209         return false;
210     if (item_ptr->GetValueAsUnsigned(0) == 0)
211         return false;
212     Error err;
213     m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
214     m_item_sp = CreateValueObjectFromAddress("item", item_ptr->GetValueAsUnsigned(0), m_exe_ctx_ref, item_ptr->GetCompilerType().GetPointeeType());
215     if (err.Fail())
216         m_item_sp.reset();
217     return false;
218 }
219 
220 size_t
221 lldb_private::formatters::VectorIteratorSyntheticFrontEnd::CalculateNumChildren ()
222 {
223     return 1;
224 }
225 
226 lldb::ValueObjectSP
227 lldb_private::formatters::VectorIteratorSyntheticFrontEnd::GetChildAtIndex (size_t idx)
228 {
229     if (idx == 0)
230         return m_item_sp;
231     return lldb::ValueObjectSP();
232 }
233 
234 bool
235 lldb_private::formatters::VectorIteratorSyntheticFrontEnd::MightHaveChildren ()
236 {
237     return true;
238 }
239 
240 size_t
241 lldb_private::formatters::VectorIteratorSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
242 {
243     if (name == ConstString("item"))
244         return 0;
245     return UINT32_MAX;
246 }
247 
248 lldb_private::formatters::VectorIteratorSyntheticFrontEnd::~VectorIteratorSyntheticFrontEnd() = default;
249 
250 bool
251 lldb_private::formatters::LibStdcppStringSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
252 {
253     const bool scalar_is_load_addr = true;
254     AddressType addr_type;
255     lldb::addr_t addr_of_string = valobj.GetAddressOf(scalar_is_load_addr, &addr_type);
256     if (addr_of_string != LLDB_INVALID_ADDRESS)
257     {
258         switch (addr_type)
259         {
260             case eAddressTypeLoad:
261             {
262                 ProcessSP process_sp(valobj.GetProcessSP());
263                 if (!process_sp)
264                     return false;
265 
266                 StringPrinter::ReadStringAndDumpToStreamOptions options(valobj);
267                 Error error;
268                 lldb::addr_t addr_of_data = process_sp->ReadPointerFromMemory(addr_of_string, error);
269                 if (error.Fail() || addr_of_data == 0 || addr_of_data == LLDB_INVALID_ADDRESS)
270                     return false;
271                 options.SetLocation(addr_of_data);
272                 options.SetProcessSP(process_sp);
273                 options.SetStream(&stream);
274                 options.SetNeedsZeroTermination(false);
275                 options.SetBinaryZeroIsTerminator(true);
276                 lldb::addr_t size_of_data = process_sp->ReadPointerFromMemory(addr_of_string + process_sp->GetAddressByteSize(), error);
277                 if (error.Fail())
278                     return false;
279                 options.SetSourceSize(size_of_data);
280 
281                 if (!StringPrinter::ReadStringAndDumpToStream<StringPrinter::StringElementType::UTF8>(options))
282                 {
283                     stream.Printf("Summary Unavailable");
284                     return true;
285                 }
286                 else
287                     return true;
288             }
289                 break;
290             case eAddressTypeHost:
291                 break;
292             case eAddressTypeInvalid:
293             case eAddressTypeFile:
294                 break;
295         }
296     }
297     return false;
298 }
299 
300 bool
301 lldb_private::formatters::LibStdcppWStringSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
302 {
303     const bool scalar_is_load_addr = true;
304     AddressType addr_type;
305     lldb::addr_t addr_of_string = valobj.GetAddressOf(scalar_is_load_addr, &addr_type);
306     if (addr_of_string != LLDB_INVALID_ADDRESS)
307     {
308         switch (addr_type)
309         {
310             case eAddressTypeLoad:
311             {
312                 ProcessSP process_sp(valobj.GetProcessSP());
313                 if (!process_sp)
314                     return false;
315 
316                 CompilerType wchar_compiler_type = valobj.GetCompilerType().GetBasicTypeFromAST(lldb::eBasicTypeWChar);
317 
318                 if (!wchar_compiler_type)
319                     return false;
320 
321                 const uint32_t wchar_size = wchar_compiler_type.GetBitSize(nullptr); // Safe to pass NULL for exe_scope here
322 
323                 StringPrinter::ReadStringAndDumpToStreamOptions options(valobj);
324                 Error error;
325                 lldb::addr_t addr_of_data = process_sp->ReadPointerFromMemory(addr_of_string, error);
326                 if (error.Fail() || addr_of_data == 0 || addr_of_data == LLDB_INVALID_ADDRESS)
327                     return false;
328                 options.SetLocation(addr_of_data);
329                 options.SetProcessSP(process_sp);
330                 options.SetStream(&stream);
331                 options.SetNeedsZeroTermination(false);
332                 options.SetBinaryZeroIsTerminator(false);
333                 lldb::addr_t size_of_data = process_sp->ReadPointerFromMemory(addr_of_string + process_sp->GetAddressByteSize(), error);
334                 if (error.Fail())
335                     return false;
336                 options.SetSourceSize(size_of_data);
337                 options.SetPrefixToken("L");
338 
339                 switch (wchar_size)
340                 {
341                     case 8:
342                         return StringPrinter::ReadStringAndDumpToStream<StringPrinter::StringElementType::UTF8>(options);
343                     case 16:
344                         return StringPrinter::ReadStringAndDumpToStream<StringPrinter::StringElementType::UTF16>(options);
345                     case 32:
346                         return StringPrinter::ReadStringAndDumpToStream<StringPrinter::StringElementType::UTF32>(options);
347                     default:
348                         stream.Printf("size for wchar_t is not valid");
349                         return true;
350                 }
351                 return true;
352             }
353                 break;
354             case eAddressTypeHost:
355                 break;
356             case eAddressTypeInvalid:
357             case eAddressTypeFile:
358                 break;
359         }
360     }
361     return false;
362 }
363