1 //===-- LibCxxVector.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 "LibCxx.h"
11 
12 #include "lldb/Core/ConstString.h"
13 #include "lldb/Core/ValueObject.h"
14 #include "lldb/DataFormatters/FormattersHelpers.h"
15 
16 using namespace lldb;
17 using namespace lldb_private;
18 using namespace lldb_private::formatters;
19 
20 namespace lldb_private {
21     namespace formatters {
22         class LibcxxStdVectorSyntheticFrontEnd : public SyntheticChildrenFrontEnd
23         {
24         public:
25             LibcxxStdVectorSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp);
26 
27             virtual size_t
28             CalculateNumChildren ();
29 
30             virtual lldb::ValueObjectSP
31             GetChildAtIndex (size_t idx);
32 
33             virtual bool
34             Update();
35 
36             virtual bool
37             MightHaveChildren ();
38 
39             virtual size_t
40             GetIndexOfChildWithName (const ConstString &name);
41 
42             virtual
43             ~LibcxxStdVectorSyntheticFrontEnd ();
44         private:
45             ValueObject* m_start;
46             ValueObject* m_finish;
47             CompilerType m_element_type;
48             uint32_t m_element_size;
49             std::map<size_t,lldb::ValueObjectSP> m_children;
50         };
51     }
52 }
53 
54 lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::LibcxxStdVectorSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
55 SyntheticChildrenFrontEnd(*valobj_sp.get()),
56 m_start(NULL),
57 m_finish(NULL),
58 m_element_type(),
59 m_element_size(0),
60 m_children()
61 {
62     if (valobj_sp)
63         Update();
64 }
65 
66 size_t
67 lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::CalculateNumChildren ()
68 {
69     if (!m_start || !m_finish)
70         return 0;
71     uint64_t start_val = m_start->GetValueAsUnsigned(0);
72     uint64_t finish_val = m_finish->GetValueAsUnsigned(0);
73 
74     if (start_val == 0 || finish_val == 0)
75         return 0;
76 
77     if (start_val >= finish_val)
78         return 0;
79 
80     size_t num_children = (finish_val - start_val);
81     if (num_children % m_element_size)
82         return 0;
83     return num_children/m_element_size;
84 }
85 
86 lldb::ValueObjectSP
87 lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::GetChildAtIndex (size_t idx)
88 {
89     if (!m_start || !m_finish)
90         return lldb::ValueObjectSP();
91 
92     auto cached = m_children.find(idx);
93     if (cached != m_children.end())
94         return cached->second;
95 
96     uint64_t offset = idx * m_element_size;
97     offset = offset + m_start->GetValueAsUnsigned(0);
98     StreamString name;
99     name.Printf("[%" PRIu64 "]", (uint64_t)idx);
100     ValueObjectSP child_sp = CreateValueObjectFromAddress(name.GetData(), offset, m_backend.GetExecutionContextRef(), m_element_type);
101     m_children[idx] = child_sp;
102     return child_sp;
103 }
104 
105 bool
106 lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::Update()
107 {
108     m_start = m_finish = NULL;
109     m_children.clear();
110     ValueObjectSP data_type_finder_sp(m_backend.GetChildMemberWithName(ConstString("__end_cap_"),true));
111     if (!data_type_finder_sp)
112         return false;
113     data_type_finder_sp = data_type_finder_sp->GetChildMemberWithName(ConstString("__first_"),true);
114     if (!data_type_finder_sp)
115         return false;
116     m_element_type = data_type_finder_sp->GetCompilerType().GetPointeeType();
117     m_element_size = m_element_type.GetByteSize(nullptr);
118 
119     if (m_element_size > 0)
120     {
121         // store raw pointers or end up with a circular dependency
122         m_start = m_backend.GetChildMemberWithName(ConstString("__begin_"),true).get();
123         m_finish = m_backend.GetChildMemberWithName(ConstString("__end_"),true).get();
124     }
125     return false;
126 }
127 
128 bool
129 lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::MightHaveChildren ()
130 {
131     return true;
132 }
133 
134 size_t
135 lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
136 {
137     if (!m_start || !m_finish)
138         return UINT32_MAX;
139     return ExtractIndexFromString(name.GetCString());
140 }
141 
142 lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::~LibcxxStdVectorSyntheticFrontEnd ()
143 {
144     // these need to stay around because they are child objects who will follow their parent's life cycle
145     // delete m_start;
146     // delete m_finish;
147 }
148 
149 lldb_private::SyntheticChildrenFrontEnd*
150 lldb_private::formatters::LibcxxStdVectorSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
151 {
152     if (!valobj_sp)
153         return NULL;
154     return (new LibcxxStdVectorSyntheticFrontEnd(valobj_sp));
155 }
156 
157