180814287SRaphael Isemann //===-- LibCxxUnorderedMap.cpp --------------------------------------------===//
233e97e63SEnrico Granata //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
633e97e63SEnrico Granata //
733e97e63SEnrico Granata //===----------------------------------------------------------------------===//
833e97e63SEnrico Granata 
933e97e63SEnrico Granata #include "LibCxx.h"
1033e97e63SEnrico Granata 
118be30215SAlex Langford #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
1233e97e63SEnrico Granata #include "lldb/Core/ValueObject.h"
1333e97e63SEnrico Granata #include "lldb/Core/ValueObjectConstResult.h"
1433e97e63SEnrico Granata #include "lldb/DataFormatters/FormattersHelpers.h"
1533e97e63SEnrico Granata #include "lldb/Target/Target.h"
16666cc0b2SZachary Turner #include "lldb/Utility/DataBufferHeap.h"
1701c3243fSZachary Turner #include "lldb/Utility/Endian.h"
1897206d57SZachary Turner #include "lldb/Utility/Status.h"
19bf9a7730SZachary Turner #include "lldb/Utility/Stream.h"
2033e97e63SEnrico Granata 
2133e97e63SEnrico Granata using namespace lldb;
2233e97e63SEnrico Granata using namespace lldb_private;
2333e97e63SEnrico Granata using namespace lldb_private::formatters;
2433e97e63SEnrico Granata 
2533e97e63SEnrico Granata namespace lldb_private {
2633e97e63SEnrico Granata namespace formatters {
27b9c1b51eSKate Stone class LibcxxStdUnorderedMapSyntheticFrontEnd
28b9c1b51eSKate Stone     : public SyntheticChildrenFrontEnd {
2933e97e63SEnrico Granata public:
3033e97e63SEnrico Granata   LibcxxStdUnorderedMapSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);
3133e97e63SEnrico Granata 
328d15f33bSEugene Zelenko   ~LibcxxStdUnorderedMapSyntheticFrontEnd() override = default;
3333e97e63SEnrico Granata 
34b9c1b51eSKate Stone   size_t CalculateNumChildren() override;
3533e97e63SEnrico Granata 
36b9c1b51eSKate Stone   lldb::ValueObjectSP GetChildAtIndex(size_t idx) override;
3733e97e63SEnrico Granata 
38b9c1b51eSKate Stone   bool Update() override;
3933e97e63SEnrico Granata 
40b9c1b51eSKate Stone   bool MightHaveChildren() override;
4133e97e63SEnrico Granata 
420e4c4821SAdrian Prantl   size_t GetIndexOfChildWithName(ConstString name) override;
438d15f33bSEugene Zelenko 
4433e97e63SEnrico Granata private:
45d22a9437SEnrico Granata   CompilerType m_element_type;
46d22a9437SEnrico Granata   CompilerType m_node_type;
47*28c878aeSShafik Yaghmour   ValueObject *m_tree = nullptr;
48*28c878aeSShafik Yaghmour   size_t m_num_elements = 0;
49*28c878aeSShafik Yaghmour   ValueObject *m_next_element = nullptr;
5033e97e63SEnrico Granata   std::vector<std::pair<ValueObject *, uint64_t>> m_elements_cache;
5133e97e63SEnrico Granata };
528d15f33bSEugene Zelenko } // namespace formatters
538d15f33bSEugene Zelenko } // namespace lldb_private
5433e97e63SEnrico Granata 
55b9c1b51eSKate Stone lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::
LibcxxStdUnorderedMapSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)56b9c1b51eSKate Stone     LibcxxStdUnorderedMapSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)
57*28c878aeSShafik Yaghmour     : SyntheticChildrenFrontEnd(*valobj_sp), m_element_type(),
58*28c878aeSShafik Yaghmour       m_elements_cache() {
5933e97e63SEnrico Granata   if (valobj_sp)
6033e97e63SEnrico Granata     Update();
6133e97e63SEnrico Granata }
6233e97e63SEnrico Granata 
63b9c1b51eSKate Stone size_t lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::
CalculateNumChildren()64b9c1b51eSKate Stone     CalculateNumChildren() {
6533e97e63SEnrico Granata   return m_num_elements;
6633e97e63SEnrico Granata }
6733e97e63SEnrico Granata 
68b9c1b51eSKate Stone lldb::ValueObjectSP lldb_private::formatters::
GetChildAtIndex(size_t idx)69b9c1b51eSKate Stone     LibcxxStdUnorderedMapSyntheticFrontEnd::GetChildAtIndex(size_t idx) {
7033e97e63SEnrico Granata   if (idx >= CalculateNumChildren())
7133e97e63SEnrico Granata     return lldb::ValueObjectSP();
72bbd16815SEugene Zelenko   if (m_tree == nullptr)
7333e97e63SEnrico Granata     return lldb::ValueObjectSP();
7433e97e63SEnrico Granata 
75b9c1b51eSKate Stone   while (idx >= m_elements_cache.size()) {
7633e97e63SEnrico Granata     if (m_next_element == nullptr)
7733e97e63SEnrico Granata       return lldb::ValueObjectSP();
7833e97e63SEnrico Granata 
7997206d57SZachary Turner     Status error;
8033e97e63SEnrico Granata     ValueObjectSP node_sp = m_next_element->Dereference(error);
8133e97e63SEnrico Granata     if (!node_sp || error.Fail())
8233e97e63SEnrico Granata       return lldb::ValueObjectSP();
8333e97e63SEnrico Granata 
84b9c1b51eSKate Stone     ValueObjectSP value_sp =
85b9c1b51eSKate Stone         node_sp->GetChildMemberWithName(ConstString("__value_"), true);
86b9c1b51eSKate Stone     ValueObjectSP hash_sp =
87b9c1b51eSKate Stone         node_sp->GetChildMemberWithName(ConstString("__hash_"), true);
88d22a9437SEnrico Granata     if (!hash_sp || !value_sp) {
89d22a9437SEnrico Granata       if (!m_element_type) {
906cc3354dSLang Hames         auto p1_sp = m_backend.GetChildAtNamePath({ConstString("__table_"),
916cc3354dSLang Hames                                                    ConstString("__p1_")});
926cc3354dSLang Hames         if (!p1_sp)
936cc3354dSLang Hames           return nullptr;
946cc3354dSLang Hames 
956cc3354dSLang Hames         ValueObjectSP first_sp = nullptr;
966cc3354dSLang Hames         switch (p1_sp->GetCompilerType().GetNumDirectBaseClasses()) {
976cc3354dSLang Hames         case 1:
986cc3354dSLang Hames           // Assume a pre llvm r300140 __compressed_pair implementation:
996cc3354dSLang Hames           first_sp = p1_sp->GetChildMemberWithName(ConstString("__first_"),
1006cc3354dSLang Hames                                                    true);
1016cc3354dSLang Hames           break;
1026cc3354dSLang Hames         case 2: {
1036cc3354dSLang Hames           // Assume a post llvm r300140 __compressed_pair implementation:
1046cc3354dSLang Hames           ValueObjectSP first_elem_parent_sp =
1056cc3354dSLang Hames             p1_sp->GetChildAtIndex(0, true);
1066cc3354dSLang Hames           first_sp = p1_sp->GetChildMemberWithName(ConstString("__value_"),
1076cc3354dSLang Hames                                                    true);
1086cc3354dSLang Hames           break;
1096cc3354dSLang Hames         }
1106cc3354dSLang Hames         default:
1116cc3354dSLang Hames           return nullptr;
1126cc3354dSLang Hames         }
1136cc3354dSLang Hames 
114d22a9437SEnrico Granata         if (!first_sp)
115d22a9437SEnrico Granata           return nullptr;
116d22a9437SEnrico Granata         m_element_type = first_sp->GetCompilerType();
117769b21eaSPavel Labath         m_element_type = m_element_type.GetTypeTemplateArgument(0);
118d22a9437SEnrico Granata         m_element_type = m_element_type.GetPointeeType();
119d22a9437SEnrico Granata         m_node_type = m_element_type;
120769b21eaSPavel Labath         m_element_type = m_element_type.GetTypeTemplateArgument(0);
121d22a9437SEnrico Granata         std::string name;
122d22a9437SEnrico Granata         m_element_type =
123d22a9437SEnrico Granata             m_element_type.GetFieldAtIndex(0, name, nullptr, nullptr, nullptr);
124d22a9437SEnrico Granata         m_element_type = m_element_type.GetTypedefedType();
125d22a9437SEnrico Granata       }
126d22a9437SEnrico Granata       if (!m_node_type)
127d22a9437SEnrico Granata         return nullptr;
128d22a9437SEnrico Granata       node_sp = node_sp->Cast(m_node_type);
129d22a9437SEnrico Granata       value_sp = node_sp->GetChildMemberWithName(ConstString("__value_"), true);
130d22a9437SEnrico Granata       hash_sp = node_sp->GetChildMemberWithName(ConstString("__hash_"), true);
131d22a9437SEnrico Granata       if (!value_sp || !hash_sp)
132d22a9437SEnrico Granata         return nullptr;
133d22a9437SEnrico Granata     }
134b9c1b51eSKate Stone     m_elements_cache.push_back(
135b9c1b51eSKate Stone         {value_sp.get(), hash_sp->GetValueAsUnsigned(0)});
136b9c1b51eSKate Stone     m_next_element =
137b9c1b51eSKate Stone         node_sp->GetChildMemberWithName(ConstString("__next_"), true).get();
13833e97e63SEnrico Granata     if (!m_next_element || m_next_element->GetValueAsUnsigned(0) == 0)
13933e97e63SEnrico Granata       m_next_element = nullptr;
14033e97e63SEnrico Granata   }
14133e97e63SEnrico Granata 
14233e97e63SEnrico Granata   std::pair<ValueObject *, uint64_t> val_hash = m_elements_cache[idx];
14333e97e63SEnrico Granata   if (!val_hash.first)
14433e97e63SEnrico Granata     return lldb::ValueObjectSP();
14533e97e63SEnrico Granata   StreamString stream;
14633e97e63SEnrico Granata   stream.Printf("[%" PRIu64 "]", (uint64_t)idx);
14733e97e63SEnrico Granata   DataExtractor data;
14897206d57SZachary Turner   Status error;
14933e97e63SEnrico Granata   val_hash.first->GetData(data, error);
15033e97e63SEnrico Granata   if (error.Fail())
15133e97e63SEnrico Granata     return lldb::ValueObjectSP();
15233e97e63SEnrico Granata   const bool thread_and_frame_only_if_stopped = true;
153b9c1b51eSKate Stone   ExecutionContext exe_ctx = val_hash.first->GetExecutionContextRef().Lock(
154b9c1b51eSKate Stone       thread_and_frame_only_if_stopped);
155c156427dSZachary Turner   return CreateValueObjectFromData(stream.GetString(), data, exe_ctx,
156106aae51SEnrico Granata                                    val_hash.first->GetCompilerType());
15733e97e63SEnrico Granata }
15833e97e63SEnrico Granata 
159b9c1b51eSKate Stone bool lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::
Update()160b9c1b51eSKate Stone     Update() {
161a4850115SWalter Erquinigo   m_num_elements = 0;
16233e97e63SEnrico Granata   m_next_element = nullptr;
16333e97e63SEnrico Granata   m_elements_cache.clear();
164b9c1b51eSKate Stone   ValueObjectSP table_sp =
165b9c1b51eSKate Stone       m_backend.GetChildMemberWithName(ConstString("__table_"), true);
16633e97e63SEnrico Granata   if (!table_sp)
16733e97e63SEnrico Granata     return false;
1686cc3354dSLang Hames 
1696cc3354dSLang Hames   ValueObjectSP p2_sp = table_sp->GetChildMemberWithName(
1706cc3354dSLang Hames     ConstString("__p2_"), true);
1716cc3354dSLang Hames   ValueObjectSP num_elements_sp = nullptr;
1726cc3354dSLang Hames   llvm::SmallVector<ConstString, 3> next_path;
1736cc3354dSLang Hames   switch (p2_sp->GetCompilerType().GetNumDirectBaseClasses()) {
1746cc3354dSLang Hames   case 1:
1756cc3354dSLang Hames     // Assume a pre llvm r300140 __compressed_pair implementation:
1766cc3354dSLang Hames     num_elements_sp = p2_sp->GetChildMemberWithName(
1776cc3354dSLang Hames       ConstString("__first_"), true);
1786cc3354dSLang Hames     next_path.append({ConstString("__p1_"), ConstString("__first_"),
1796cc3354dSLang Hames                       ConstString("__next_")});
1806cc3354dSLang Hames     break;
1816cc3354dSLang Hames   case 2: {
1826cc3354dSLang Hames     // Assume a post llvm r300140 __compressed_pair implementation:
1836cc3354dSLang Hames     ValueObjectSP first_elem_parent = p2_sp->GetChildAtIndex(0, true);
1846cc3354dSLang Hames     num_elements_sp = first_elem_parent->GetChildMemberWithName(
1856cc3354dSLang Hames       ConstString("__value_"), true);
1866cc3354dSLang Hames     next_path.append({ConstString("__p1_"), ConstString("__value_"),
1876cc3354dSLang Hames                       ConstString("__next_")});
1886cc3354dSLang Hames     break;
1896cc3354dSLang Hames   }
1906cc3354dSLang Hames   default:
1916cc3354dSLang Hames     return false;
1926cc3354dSLang Hames   }
1936cc3354dSLang Hames 
19433e97e63SEnrico Granata   if (!num_elements_sp)
19533e97e63SEnrico Granata     return false;
196a4850115SWalter Erquinigo 
1976cc3354dSLang Hames   m_tree = table_sp->GetChildAtNamePath(next_path).get();
198a4850115SWalter Erquinigo   if (m_tree == nullptr)
199a4850115SWalter Erquinigo     return false;
200a4850115SWalter Erquinigo 
201a4850115SWalter Erquinigo   m_num_elements = num_elements_sp->GetValueAsUnsigned(0);
202a4850115SWalter Erquinigo 
20333e97e63SEnrico Granata   if (m_num_elements > 0)
204b9c1b51eSKate Stone     m_next_element =
2056cc3354dSLang Hames         table_sp->GetChildAtNamePath(next_path).get();
20633e97e63SEnrico Granata   return false;
20733e97e63SEnrico Granata }
20833e97e63SEnrico Granata 
209b9c1b51eSKate Stone bool lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::
MightHaveChildren()210b9c1b51eSKate Stone     MightHaveChildren() {
21133e97e63SEnrico Granata   return true;
21233e97e63SEnrico Granata }
21333e97e63SEnrico Granata 
214b9c1b51eSKate Stone size_t lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEnd::
GetIndexOfChildWithName(ConstString name)2150e4c4821SAdrian Prantl     GetIndexOfChildWithName(ConstString name) {
21633e97e63SEnrico Granata   return ExtractIndexFromString(name.GetCString());
21733e97e63SEnrico Granata }
21833e97e63SEnrico Granata 
21933e97e63SEnrico Granata SyntheticChildrenFrontEnd *
LibcxxStdUnorderedMapSyntheticFrontEndCreator(CXXSyntheticChildren *,lldb::ValueObjectSP valobj_sp)220b9c1b51eSKate Stone lldb_private::formatters::LibcxxStdUnorderedMapSyntheticFrontEndCreator(
221b9c1b51eSKate Stone     CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
222b9c1b51eSKate Stone   return (valobj_sp ? new LibcxxStdUnorderedMapSyntheticFrontEnd(valobj_sp)
223b9c1b51eSKate Stone                     : nullptr);
22433e97e63SEnrico Granata }
225