1314564Sdim//===-- CF.cpp ----------------------------------------------------*- C++ 2314564Sdim//-*-===// 3292932Sdim// 4353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 5353358Sdim// See https://llvm.org/LICENSE.txt for license information. 6353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 7292932Sdim// 8292932Sdim//===----------------------------------------------------------------------===// 9292932Sdim 10292932Sdim#include "CF.h" 11292932Sdim 12292932Sdim#include "lldb/Core/ValueObject.h" 13292932Sdim#include "lldb/Core/ValueObjectConstResult.h" 14292932Sdim#include "lldb/DataFormatters/FormattersHelpers.h" 15292932Sdim#include "lldb/Symbol/ClangASTContext.h" 16292932Sdim#include "lldb/Target/Language.h" 17292932Sdim#include "lldb/Target/StackFrame.h" 18292932Sdim#include "lldb/Target/Target.h" 19321369Sdim#include "lldb/Utility/DataBufferHeap.h" 20321369Sdim#include "lldb/Utility/Endian.h" 21321369Sdim#include "lldb/Utility/Status.h" 22321369Sdim#include "lldb/Utility/Stream.h" 23292932Sdim 24353358Sdim#include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h" 25353358Sdim 26292932Sdimusing namespace lldb; 27292932Sdimusing namespace lldb_private; 28292932Sdimusing namespace lldb_private::formatters; 29292932Sdim 30314564Sdimbool lldb_private::formatters::CFAbsoluteTimeSummaryProvider( 31314564Sdim ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { 32314564Sdim time_t epoch = GetOSXEpoch(); 33314564Sdim epoch = epoch + (time_t)valobj.GetValueAsUnsigned(0); 34314564Sdim tm *tm_date = localtime(&epoch); 35314564Sdim if (!tm_date) 36314564Sdim return false; 37314564Sdim std::string buffer(1024, 0); 38314564Sdim if (strftime(&buffer[0], 1023, "%Z", tm_date) == 0) 39314564Sdim return false; 40314564Sdim stream.Printf("%04d-%02d-%02d %02d:%02d:%02d %s", tm_date->tm_year + 1900, 41314564Sdim tm_date->tm_mon + 1, tm_date->tm_mday, tm_date->tm_hour, 42314564Sdim tm_date->tm_min, tm_date->tm_sec, buffer.c_str()); 43314564Sdim return true; 44292932Sdim} 45292932Sdim 46314564Sdimbool lldb_private::formatters::CFBagSummaryProvider( 47314564Sdim ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { 48314564Sdim static ConstString g_TypeHint("CFBag"); 49314564Sdim 50314564Sdim ProcessSP process_sp = valobj.GetProcessSP(); 51314564Sdim if (!process_sp) 52314564Sdim return false; 53314564Sdim 54353358Sdim ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp); 55314564Sdim 56314564Sdim if (!runtime) 57314564Sdim return false; 58314564Sdim 59314564Sdim ObjCLanguageRuntime::ClassDescriptorSP descriptor( 60314564Sdim runtime->GetClassDescriptor(valobj)); 61314564Sdim 62314564Sdim if (!descriptor.get() || !descriptor->IsValid()) 63314564Sdim return false; 64314564Sdim 65314564Sdim uint32_t ptr_size = process_sp->GetAddressByteSize(); 66314564Sdim 67314564Sdim lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 68314564Sdim 69314564Sdim if (!valobj_addr) 70314564Sdim return false; 71314564Sdim 72314564Sdim uint32_t count = 0; 73314564Sdim 74314564Sdim bool is_type_ok = false; // check to see if this is a CFBag we know about 75314564Sdim if (descriptor->IsCFType()) { 76314564Sdim ConstString type_name(valobj.GetTypeName()); 77314564Sdim 78314564Sdim static ConstString g___CFBag("__CFBag"); 79314564Sdim static ConstString g_conststruct__CFBag("const struct __CFBag"); 80314564Sdim 81314564Sdim if (type_name == g___CFBag || type_name == g_conststruct__CFBag) { 82314564Sdim if (valobj.IsPointerType()) 83314564Sdim is_type_ok = true; 84292932Sdim } 85314564Sdim } 86314564Sdim 87314564Sdim if (is_type_ok) { 88314564Sdim lldb::addr_t offset = 2 * ptr_size + 4 + valobj_addr; 89321369Sdim Status error; 90314564Sdim count = process_sp->ReadUnsignedIntegerFromMemory(offset, 4, 0, error); 91314564Sdim if (error.Fail()) 92314564Sdim return false; 93314564Sdim } else 94314564Sdim return false; 95314564Sdim 96314564Sdim std::string prefix, suffix; 97314564Sdim if (Language *language = Language::FindPlugin(options.GetLanguage())) { 98314564Sdim if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix, 99314564Sdim suffix)) { 100314564Sdim prefix.clear(); 101314564Sdim suffix.clear(); 102292932Sdim } 103314564Sdim } 104314564Sdim 105314564Sdim stream.Printf("%s\"%u value%s\"%s", prefix.c_str(), count, 106314564Sdim (count == 1 ? "" : "s"), suffix.c_str()); 107314564Sdim return true; 108292932Sdim} 109292932Sdim 110314564Sdimbool lldb_private::formatters::CFBitVectorSummaryProvider( 111314564Sdim ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { 112314564Sdim ProcessSP process_sp = valobj.GetProcessSP(); 113314564Sdim if (!process_sp) 114314564Sdim return false; 115314564Sdim 116353358Sdim ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp); 117314564Sdim 118314564Sdim if (!runtime) 119314564Sdim return false; 120314564Sdim 121314564Sdim ObjCLanguageRuntime::ClassDescriptorSP descriptor( 122314564Sdim runtime->GetClassDescriptor(valobj)); 123314564Sdim 124314564Sdim if (!descriptor.get() || !descriptor->IsValid()) 125314564Sdim return false; 126314564Sdim 127314564Sdim uint32_t ptr_size = process_sp->GetAddressByteSize(); 128314564Sdim 129314564Sdim lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 130314564Sdim 131314564Sdim if (!valobj_addr) 132314564Sdim return false; 133314564Sdim 134314564Sdim uint32_t count = 0; 135314564Sdim 136314564Sdim bool is_type_ok = false; // check to see if this is a CFBag we know about 137314564Sdim if (descriptor->IsCFType()) { 138314564Sdim ConstString type_name(valobj.GetTypeName()); 139353358Sdim if (type_name == "__CFMutableBitVector" || type_name == "__CFBitVector" || 140353358Sdim type_name == "CFMutableBitVectorRef" || type_name == "CFBitVectorRef") { 141314564Sdim if (valobj.IsPointerType()) 142314564Sdim is_type_ok = true; 143292932Sdim } 144314564Sdim } 145314564Sdim 146344779Sdim if (!is_type_ok) 147314564Sdim return false; 148314564Sdim 149321369Sdim Status error; 150314564Sdim count = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + 2 * ptr_size, 151314564Sdim ptr_size, 0, error); 152314564Sdim if (error.Fail()) 153314564Sdim return false; 154314564Sdim uint64_t num_bytes = count / 8 + ((count & 7) ? 1 : 0); 155314564Sdim addr_t data_ptr = process_sp->ReadPointerFromMemory( 156314564Sdim valobj_addr + 2 * ptr_size + 2 * ptr_size, error); 157314564Sdim if (error.Fail()) 158314564Sdim return false; 159314564Sdim // make sure we do not try to read huge amounts of data 160314564Sdim if (num_bytes > 1024) 161314564Sdim num_bytes = 1024; 162314564Sdim DataBufferSP buffer_sp(new DataBufferHeap(num_bytes, 0)); 163314564Sdim num_bytes = 164314564Sdim process_sp->ReadMemory(data_ptr, buffer_sp->GetBytes(), num_bytes, error); 165314564Sdim if (error.Fail() || num_bytes == 0) 166314564Sdim return false; 167314564Sdim uint8_t *bytes = buffer_sp->GetBytes(); 168314564Sdim for (uint64_t byte_idx = 0; byte_idx < num_bytes - 1; byte_idx++) { 169314564Sdim uint8_t byte = bytes[byte_idx]; 170314564Sdim bool bit0 = (byte & 1) == 1; 171314564Sdim bool bit1 = (byte & 2) == 2; 172314564Sdim bool bit2 = (byte & 4) == 4; 173314564Sdim bool bit3 = (byte & 8) == 8; 174314564Sdim bool bit4 = (byte & 16) == 16; 175314564Sdim bool bit5 = (byte & 32) == 32; 176314564Sdim bool bit6 = (byte & 64) == 64; 177314564Sdim bool bit7 = (byte & 128) == 128; 178314564Sdim stream.Printf("%c%c%c%c %c%c%c%c ", (bit7 ? '1' : '0'), (bit6 ? '1' : '0'), 179314564Sdim (bit5 ? '1' : '0'), (bit4 ? '1' : '0'), (bit3 ? '1' : '0'), 180314564Sdim (bit2 ? '1' : '0'), (bit1 ? '1' : '0'), (bit0 ? '1' : '0')); 181314564Sdim count -= 8; 182314564Sdim } 183314564Sdim { 184314564Sdim // print the last byte ensuring we do not print spurious bits 185314564Sdim uint8_t byte = bytes[num_bytes - 1]; 186314564Sdim bool bit0 = (byte & 1) == 1; 187314564Sdim bool bit1 = (byte & 2) == 2; 188314564Sdim bool bit2 = (byte & 4) == 4; 189314564Sdim bool bit3 = (byte & 8) == 8; 190314564Sdim bool bit4 = (byte & 16) == 16; 191314564Sdim bool bit5 = (byte & 32) == 32; 192314564Sdim bool bit6 = (byte & 64) == 64; 193314564Sdim bool bit7 = (byte & 128) == 128; 194314564Sdim if (count) { 195314564Sdim stream.Printf("%c", bit7 ? '1' : '0'); 196314564Sdim count -= 1; 197292932Sdim } 198314564Sdim if (count) { 199314564Sdim stream.Printf("%c", bit6 ? '1' : '0'); 200314564Sdim count -= 1; 201292932Sdim } 202314564Sdim if (count) { 203314564Sdim stream.Printf("%c", bit5 ? '1' : '0'); 204314564Sdim count -= 1; 205314564Sdim } 206314564Sdim if (count) { 207314564Sdim stream.Printf("%c", bit4 ? '1' : '0'); 208314564Sdim count -= 1; 209314564Sdim } 210314564Sdim if (count) { 211314564Sdim stream.Printf("%c", bit3 ? '1' : '0'); 212314564Sdim count -= 1; 213314564Sdim } 214314564Sdim if (count) { 215314564Sdim stream.Printf("%c", bit2 ? '1' : '0'); 216314564Sdim count -= 1; 217314564Sdim } 218314564Sdim if (count) { 219314564Sdim stream.Printf("%c", bit1 ? '1' : '0'); 220314564Sdim count -= 1; 221314564Sdim } 222314564Sdim if (count) 223314564Sdim stream.Printf("%c", bit0 ? '1' : '0'); 224314564Sdim } 225314564Sdim return true; 226292932Sdim} 227292932Sdim 228314564Sdimbool lldb_private::formatters::CFBinaryHeapSummaryProvider( 229314564Sdim ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) { 230314564Sdim static ConstString g_TypeHint("CFBinaryHeap"); 231309124Sdim 232314564Sdim ProcessSP process_sp = valobj.GetProcessSP(); 233314564Sdim if (!process_sp) 234314564Sdim return false; 235314564Sdim 236353358Sdim ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp); 237314564Sdim 238314564Sdim if (!runtime) 239314564Sdim return false; 240314564Sdim 241314564Sdim ObjCLanguageRuntime::ClassDescriptorSP descriptor( 242314564Sdim runtime->GetClassDescriptor(valobj)); 243314564Sdim 244314564Sdim if (!descriptor.get() || !descriptor->IsValid()) 245314564Sdim return false; 246314564Sdim 247314564Sdim uint32_t ptr_size = process_sp->GetAddressByteSize(); 248314564Sdim 249314564Sdim lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 250314564Sdim 251314564Sdim if (!valobj_addr) 252314564Sdim return false; 253314564Sdim 254314564Sdim uint32_t count = 0; 255314564Sdim 256314564Sdim bool is_type_ok = 257314564Sdim false; // check to see if this is a CFBinaryHeap we know about 258314564Sdim if (descriptor->IsCFType()) { 259314564Sdim ConstString type_name(valobj.GetTypeName()); 260314564Sdim 261314564Sdim static ConstString g___CFBinaryHeap("__CFBinaryHeap"); 262314564Sdim static ConstString g_conststruct__CFBinaryHeap( 263314564Sdim "const struct __CFBinaryHeap"); 264314564Sdim static ConstString g_CFBinaryHeapRef("CFBinaryHeapRef"); 265314564Sdim 266314564Sdim if (type_name == g___CFBinaryHeap || 267314564Sdim type_name == g_conststruct__CFBinaryHeap || 268314564Sdim type_name == g_CFBinaryHeapRef) { 269314564Sdim if (valobj.IsPointerType()) 270314564Sdim is_type_ok = true; 271292932Sdim } 272314564Sdim } 273314564Sdim 274314564Sdim if (is_type_ok) { 275314564Sdim lldb::addr_t offset = 2 * ptr_size + valobj_addr; 276321369Sdim Status error; 277314564Sdim count = process_sp->ReadUnsignedIntegerFromMemory(offset, 4, 0, error); 278314564Sdim if (error.Fail()) 279314564Sdim return false; 280314564Sdim } else 281314564Sdim return false; 282314564Sdim 283314564Sdim std::string prefix, suffix; 284314564Sdim if (Language *language = Language::FindPlugin(options.GetLanguage())) { 285314564Sdim if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix, 286314564Sdim suffix)) { 287314564Sdim prefix.clear(); 288314564Sdim suffix.clear(); 289292932Sdim } 290314564Sdim } 291314564Sdim 292314564Sdim stream.Printf("%s\"%u item%s\"%s", prefix.c_str(), count, 293314564Sdim (count == 1 ? "" : "s"), suffix.c_str()); 294314564Sdim return true; 295292932Sdim} 296