1 #include "CFBasicHash.h"
2 
3 #include "lldb/Utility/Endian.h"
4 
5 using namespace lldb;
6 using namespace lldb_private;
7 
8 bool CFBasicHash::IsValid() const {
9   if (m_address != LLDB_INVALID_ADDRESS) {
10     if (m_ptr_size == 4 && m_ht_32)
11       return true;
12     else if (m_ptr_size == 8 && m_ht_64)
13       return true;
14     else
15       return false;
16   }
17   return false;
18 }
19 
20 bool CFBasicHash::Update(addr_t addr, ExecutionContextRef exe_ctx_rf) {
21   if (addr == LLDB_INVALID_ADDRESS || !addr)
22     return false;
23 
24   m_address = addr;
25   m_exe_ctx_ref = exe_ctx_rf;
26   m_ptr_size =
27       m_exe_ctx_ref.GetTargetSP()->GetArchitecture().GetAddressByteSize();
28   m_byte_order = m_exe_ctx_ref.GetTargetSP()->GetArchitecture().GetByteOrder();
29 
30   if (m_ptr_size == 4)
31     return UpdateFor(m_ht_32);
32   else if (m_ptr_size == 8)
33     return UpdateFor(m_ht_64);
34   return false;
35 
36   llvm_unreachable(
37       "Unsupported architecture. Only 32bits and 64bits supported.");
38 }
39 
40 template <typename T>
41 bool CFBasicHash::UpdateFor(std::unique_ptr<__CFBasicHash<T>> &m_ht) {
42   if (m_byte_order != endian::InlHostByteOrder())
43     return false;
44 
45   Status error;
46   Target *target = m_exe_ctx_ref.GetTargetSP().get();
47   addr_t addr = m_address.GetLoadAddress(target);
48   size_t size = sizeof(typename __CFBasicHash<T>::RuntimeBase) +
49                 sizeof(typename __CFBasicHash<T>::Bits);
50 
51   m_ht = std::make_unique<__CFBasicHash<T>>();
52   m_exe_ctx_ref.GetProcessSP()->ReadMemory(addr, m_ht.get(),
53                                            size, error);
54   if (error.Fail())
55     return false;
56 
57   m_mutable = !(m_ht->base.cfinfoa & (1 << 6));
58   m_multi = m_ht->bits.counts_offset;
59   m_type = static_cast<HashType>(m_ht->bits.keys_offset);
60   addr_t ptr_offset = addr + size;
61   size_t ptr_count = GetPointerCount();
62   size = ptr_count * sizeof(T);
63 
64   m_exe_ctx_ref.GetProcessSP()->ReadMemory(ptr_offset, m_ht->pointers, size,
65                                            error);
66 
67   if (error.Fail()) {
68     m_ht = nullptr;
69     return false;
70   }
71 
72   return true;
73 }
74 
75 size_t CFBasicHash::GetCount() const {
76   if (!IsValid())
77     return 0;
78 
79   if (!m_multi)
80     return (m_ptr_size == 4) ? m_ht_32->bits.used_buckets
81                              : m_ht_64->bits.used_buckets;
82 
83   //  FIXME: Add support for multi
84   return 0;
85 }
86 
87 size_t CFBasicHash::GetPointerCount() const {
88   if (!IsValid())
89     return 0;
90 
91   if (m_multi)
92     return 3; // Bits::counts_offset;
93   return (m_type == HashType::dict) + 1;
94 }
95 
96 addr_t CFBasicHash::GetKeyPointer() const {
97   if (!IsValid())
98     return LLDB_INVALID_ADDRESS;
99 
100   if (m_ptr_size == 4)
101     return m_ht_32->pointers[m_ht_32->bits.keys_offset];
102 
103   return m_ht_64->pointers[m_ht_64->bits.keys_offset];
104 }
105 
106 addr_t CFBasicHash::GetValuePointer() const {
107   if (!IsValid())
108     return LLDB_INVALID_ADDRESS;
109 
110   if (m_ptr_size == 4)
111     return m_ht_32->pointers[0];
112 
113   return m_ht_64->pointers[0];
114 }
115