Med Ismail Bennani 8f5beb4c4b
[lldb/Dataformatter] Add support for CoreFoundation Dictionaries and Sets.
This patch improves data formatting for CoreFoundation containers:
CFDictionary and CFSet.

These data formatters make the containers and their children appear in Xcode's
variables view (and on the command line) without having to expand the
data structure.

Previous implementation only supported showing the container's element count.

```
(lldb) frame var dict
(__NSCFDictionary *) dict = 0x00000001004062b0 2 key/value pairs

(lldb) frame var set
(__NSCFSet *) set = 0x0000000100406330 2 elements
```
Now the variable can be dereferenced to dispaly the container's children:

```
(lldb) frame var *dict
(__NSCFDictionary) *dict = {
  [0] = {
    key = 0x0000000100004050 @"123"
    value = 0x0000000100004090 @"456"
  }
  [1] = {
    key = 0x0000000100004030 @"abc"
    value = 0x0000000100004070 @"def"
  }
}

(lldb) frame var *set
(__NSCFSet) *set = {
  [0] = 0x0000000100004050 @"123"
  [1] = 0x0000000100004030 @"abc"
}
```

rdar://39882287

Differential Revision: https://reviews.llvm.org/D78396

Signed-off-by: Med Ismail Bennani <medismail.bennani@gmail.com>
2020-04-27 22:10:11 +02:00

115 lines
2.8 KiB
C++

#include "CFBasicHash.h"
#include "lldb/Utility/Endian.h"
using namespace lldb;
using namespace lldb_private;
bool CFBasicHash::IsValid() const {
if (m_address != LLDB_INVALID_ADDRESS) {
if (m_ptr_size == 4 && m_ht_32)
return true;
else if (m_ptr_size == 8 && m_ht_64)
return true;
else
return false;
}
return false;
}
bool CFBasicHash::Update(addr_t addr, ExecutionContextRef exe_ctx_rf) {
if (addr == LLDB_INVALID_ADDRESS || !addr)
return false;
m_address = addr;
m_exe_ctx_ref = exe_ctx_rf;
m_ptr_size =
m_exe_ctx_ref.GetTargetSP()->GetArchitecture().GetAddressByteSize();
m_byte_order = m_exe_ctx_ref.GetTargetSP()->GetArchitecture().GetByteOrder();
if (m_ptr_size == 4)
return UpdateFor(m_ht_32);
else if (m_ptr_size == 8)
return UpdateFor(m_ht_64);
return false;
llvm_unreachable(
"Unsupported architecture. Only 32bits and 64bits supported.");
}
template <typename T>
bool CFBasicHash::UpdateFor(std::unique_ptr<__CFBasicHash<T>> &m_ht) {
if (m_byte_order != endian::InlHostByteOrder())
return false;
Status error;
Target *target = m_exe_ctx_ref.GetTargetSP().get();
addr_t addr = m_address.GetLoadAddress(target);
size_t size = sizeof(typename __CFBasicHash<T>::RuntimeBase) +
sizeof(typename __CFBasicHash<T>::Bits);
m_ht = std::make_unique<__CFBasicHash<T>>();
m_exe_ctx_ref.GetProcessSP()->ReadMemory(addr, m_ht.get(),
size, error);
if (error.Fail())
return false;
m_mutable = !(m_ht->base.cfinfoa & (1 << 6));
m_multi = m_ht->bits.counts_offset;
m_type = static_cast<HashType>(m_ht->bits.keys_offset);
addr_t ptr_offset = addr + size;
size_t ptr_count = GetPointerCount();
size = ptr_count * sizeof(T);
m_exe_ctx_ref.GetProcessSP()->ReadMemory(ptr_offset, m_ht->pointers, size,
error);
if (error.Fail()) {
m_ht = nullptr;
return false;
}
return true;
}
size_t CFBasicHash::GetCount() const {
if (!IsValid())
return 0;
if (!m_multi)
return (m_ptr_size == 4) ? m_ht_32->bits.used_buckets
: m_ht_64->bits.used_buckets;
// FIXME: Add support for multi
return 0;
}
size_t CFBasicHash::GetPointerCount() const {
if (!IsValid())
return 0;
if (m_multi)
return 3; // Bits::counts_offset;
return (m_type == HashType::dict) + 1;
}
addr_t CFBasicHash::GetKeyPointer() const {
if (!IsValid())
return LLDB_INVALID_ADDRESS;
if (m_ptr_size == 4)
return m_ht_32->pointers[m_ht_32->bits.keys_offset];
return m_ht_64->pointers[m_ht_64->bits.keys_offset];
}
addr_t CFBasicHash::GetValuePointer() const {
if (!IsValid())
return LLDB_INVALID_ADDRESS;
if (m_ptr_size == 4)
return m_ht_32->pointers[0];
return m_ht_64->pointers[0];
}