1 //===-- LibCxxUnorderedMap.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 // C Includes
11 // C++ Includes
12 // Other libraries and framework includes
13 // Project includes
14 #include "LibCxx.h"
15 
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/FormattersHelpers.h"
22 #include "lldb/Host/Endian.h"
23 #include "lldb/Symbol/ClangASTContext.h"
24 #include "lldb/Target/Target.h"
25 
26 using namespace lldb;
27 using namespace lldb_private;
28 using namespace lldb_private::formatters;
29 
30 namespace lldb_private {
31 namespace formatters {
32 class LibcxxStdUnorderedMapSyntheticFrontEnd
33     : public SyntheticChildrenFrontEnd {
34 public:
35   LibcxxStdUnorderedMapSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
36 
37   ~LibcxxStdUnorderedMapSyntheticFrontEnd() override = default;
38 
39   size_t CalculateNumChildren() override;
40 
41   lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
42 
43   bool Update() override;
44 
45   bool MightHaveChildren() override;
46 
47   size_t GetIndexOfChildWithName(const ConstString &name) override;
48 
49 private:
50   ValueObject *m_tree;
51   size_t m_num_elements;
52   ValueObject *m_next_element;
53   std::vector<std::pair<ValueObject *, uint64_t>> m_elements_cache;
54 };
55 } // namespace formatters
56 } // namespace lldb_private
57 
58 lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::
59     LibcxxStdUnorderedMapSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
60     : SyntheticChildrenFrontEnd(*valobj_sp), m_tree(nullptr), m_num_elements(0),
61       m_next_element(nullptr), m_elements_cache() {
62   if (valobj_sp)
63     Update();
64 }
65 
66 size_t lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::
67     CalculateNumChildren() {
68   if (m_num_elements != UINT32_MAX)
69     return m_num_elements;
70   return 0;
71 }
72 
73 lldb::ValueObjectSP lldb_private::formatters::
74     LibcxxStdUnorderedMapSyntheticFrontEnd::GetChildAtIndex(size_t idx) {
75   if (idx >= CalculateNumChildren())
76     return lldb::ValueObjectSP();
77   if (m_tree == nullptr)
78     return lldb::ValueObjectSP();
79 
80   while (idx >= m_elements_cache.size()) {
81     if (m_next_element == nullptr)
82       return lldb::ValueObjectSP();
83 
84     Error error;
85     ValueObjectSP node_sp = m_next_element->Dereference(error);
86     if (!node_sp || error.Fail())
87       return lldb::ValueObjectSP();
88 
89     ValueObjectSP value_sp =
90         node_sp->GetChildMemberWithName(ConstString("__value_"), true);
91     ValueObjectSP hash_sp =
92         node_sp->GetChildMemberWithName(ConstString("__hash_"), true);
93     if (!hash_sp || !value_sp)
94       return lldb::ValueObjectSP();
95     m_elements_cache.push_back(
96         {value_sp.get(), hash_sp->GetValueAsUnsigned(0)});
97     m_next_element =
98         node_sp->GetChildMemberWithName(ConstString("__next_"), true).get();
99     if (!m_next_element || m_next_element->GetValueAsUnsigned(0) == 0)
100       m_next_element = nullptr;
101   }
102 
103   std::pair<ValueObject *, uint64_t> val_hash = m_elements_cache[idx];
104   if (!val_hash.first)
105     return lldb::ValueObjectSP();
106   StreamString stream;
107   stream.Printf("[%" PRIu64 "]", (uint64_t)idx);
108   DataExtractor data;
109   Error error;
110   val_hash.first->GetData(data, error);
111   if (error.Fail())
112     return lldb::ValueObjectSP();
113   const bool thread_and_frame_only_if_stopped = true;
114   ExecutionContext exe_ctx = val_hash.first->GetExecutionContextRef().Lock(
115       thread_and_frame_only_if_stopped);
116   return CreateValueObjectFromData(stream.GetData(), data, exe_ctx,
117                                    val_hash.first->GetCompilerType());
118 }
119 
120 bool lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::
121     Update() {
122   m_num_elements = UINT32_MAX;
123   m_next_element = nullptr;
124   m_elements_cache.clear();
125   ValueObjectSP table_sp =
126       m_backend.GetChildMemberWithName(ConstString("__table_"), true);
127   if (!table_sp)
128     return false;
129   ValueObjectSP num_elements_sp = table_sp->GetChildAtNamePath(
130       {ConstString("__p2_"), ConstString("__first_")});
131   if (!num_elements_sp)
132     return false;
133   m_num_elements = num_elements_sp->GetValueAsUnsigned(0);
134   m_tree =
135       table_sp
136           ->GetChildAtNamePath({ConstString("__p1_"), ConstString("__first_"),
137                                 ConstString("__next_")})
138           .get();
139   if (m_num_elements > 0)
140     m_next_element =
141         table_sp
142             ->GetChildAtNamePath({ConstString("__p1_"), ConstString("__first_"),
143                                   ConstString("__next_")})
144             .get();
145   return false;
146 }
147 
148 bool lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::
149     MightHaveChildren() {
150   return true;
151 }
152 
153 size_t lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::
154     GetIndexOfChildWithName(const ConstString &name) {
155   return ExtractIndexFromString(name.GetCString());
156 }
157 
158 SyntheticChildrenFrontEnd *
159 lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEndCreator(
160     CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
161   return (valobj_sp ? new LibcxxStdUnorderedMapSyntheticFrontEnd(valobj_sp)
162                     : nullptr);
163 }
164