15ffd83dbSDimitry Andric //===-- CF.cpp ------------------------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "CF.h"
100b57cec5SDimitry Andric 
115ffd83dbSDimitry Andric #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
120b57cec5SDimitry Andric #include "lldb/Core/ValueObject.h"
130b57cec5SDimitry Andric #include "lldb/Core/ValueObjectConstResult.h"
140b57cec5SDimitry Andric #include "lldb/DataFormatters/FormattersHelpers.h"
150b57cec5SDimitry Andric #include "lldb/Target/Language.h"
160b57cec5SDimitry Andric #include "lldb/Target/StackFrame.h"
170b57cec5SDimitry Andric #include "lldb/Target/Target.h"
180b57cec5SDimitry Andric #include "lldb/Utility/DataBufferHeap.h"
190b57cec5SDimitry Andric #include "lldb/Utility/Endian.h"
200b57cec5SDimitry Andric #include "lldb/Utility/Status.h"
210b57cec5SDimitry Andric #include "lldb/Utility/Stream.h"
220b57cec5SDimitry Andric 
230b57cec5SDimitry Andric #include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
240b57cec5SDimitry Andric 
250b57cec5SDimitry Andric using namespace lldb;
260b57cec5SDimitry Andric using namespace lldb_private;
270b57cec5SDimitry Andric using namespace lldb_private::formatters;
280b57cec5SDimitry Andric 
CFAbsoluteTimeSummaryProvider(ValueObject & valobj,Stream & stream,const TypeSummaryOptions & options)290b57cec5SDimitry Andric bool lldb_private::formatters::CFAbsoluteTimeSummaryProvider(
300b57cec5SDimitry Andric     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
310b57cec5SDimitry Andric   time_t epoch = GetOSXEpoch();
325ffd83dbSDimitry Andric   epoch = epoch + (time_t)valobj.GetValueAsSigned(0);
330b57cec5SDimitry Andric   tm *tm_date = localtime(&epoch);
340b57cec5SDimitry Andric   if (!tm_date)
350b57cec5SDimitry Andric     return false;
360b57cec5SDimitry Andric   std::string buffer(1024, 0);
370b57cec5SDimitry Andric   if (strftime(&buffer[0], 1023, "%Z", tm_date) == 0)
380b57cec5SDimitry Andric     return false;
390b57cec5SDimitry Andric   stream.Printf("%04d-%02d-%02d %02d:%02d:%02d %s", tm_date->tm_year + 1900,
400b57cec5SDimitry Andric                 tm_date->tm_mon + 1, tm_date->tm_mday, tm_date->tm_hour,
410b57cec5SDimitry Andric                 tm_date->tm_min, tm_date->tm_sec, buffer.c_str());
420b57cec5SDimitry Andric   return true;
430b57cec5SDimitry Andric }
440b57cec5SDimitry Andric 
CFBagSummaryProvider(ValueObject & valobj,Stream & stream,const TypeSummaryOptions & options)450b57cec5SDimitry Andric bool lldb_private::formatters::CFBagSummaryProvider(
460b57cec5SDimitry Andric     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
4706c3fb27SDimitry Andric   static constexpr llvm::StringLiteral g_TypeHint("CFBag");
480b57cec5SDimitry Andric 
490b57cec5SDimitry Andric   ProcessSP process_sp = valobj.GetProcessSP();
500b57cec5SDimitry Andric   if (!process_sp)
510b57cec5SDimitry Andric     return false;
520b57cec5SDimitry Andric 
530b57cec5SDimitry Andric   ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
540b57cec5SDimitry Andric 
550b57cec5SDimitry Andric   if (!runtime)
560b57cec5SDimitry Andric     return false;
570b57cec5SDimitry Andric 
580b57cec5SDimitry Andric   ObjCLanguageRuntime::ClassDescriptorSP descriptor(
590b57cec5SDimitry Andric       runtime->GetClassDescriptor(valobj));
600b57cec5SDimitry Andric 
610b57cec5SDimitry Andric   if (!descriptor.get() || !descriptor->IsValid())
620b57cec5SDimitry Andric     return false;
630b57cec5SDimitry Andric 
640b57cec5SDimitry Andric   uint32_t ptr_size = process_sp->GetAddressByteSize();
650b57cec5SDimitry Andric 
660b57cec5SDimitry Andric   lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
670b57cec5SDimitry Andric 
680b57cec5SDimitry Andric   if (!valobj_addr)
690b57cec5SDimitry Andric     return false;
700b57cec5SDimitry Andric 
710b57cec5SDimitry Andric   uint32_t count = 0;
720b57cec5SDimitry Andric 
730b57cec5SDimitry Andric   bool is_type_ok = false; // check to see if this is a CFBag we know about
740b57cec5SDimitry Andric   if (descriptor->IsCFType()) {
750b57cec5SDimitry Andric     ConstString type_name(valobj.GetTypeName());
760b57cec5SDimitry Andric 
7781ad6265SDimitry Andric     static ConstString g_CFBag("__CFBag");
780b57cec5SDimitry Andric     static ConstString g_conststruct__CFBag("const struct __CFBag");
790b57cec5SDimitry Andric 
8081ad6265SDimitry Andric     if (type_name == g_CFBag || type_name == g_conststruct__CFBag) {
810b57cec5SDimitry Andric       if (valobj.IsPointerType())
820b57cec5SDimitry Andric         is_type_ok = true;
830b57cec5SDimitry Andric     }
840b57cec5SDimitry Andric   }
850b57cec5SDimitry Andric 
860b57cec5SDimitry Andric   if (is_type_ok) {
870b57cec5SDimitry Andric     lldb::addr_t offset = 2 * ptr_size + 4 + valobj_addr;
880b57cec5SDimitry Andric     Status error;
890b57cec5SDimitry Andric     count = process_sp->ReadUnsignedIntegerFromMemory(offset, 4, 0, error);
900b57cec5SDimitry Andric     if (error.Fail())
910b57cec5SDimitry Andric       return false;
920b57cec5SDimitry Andric   } else
930b57cec5SDimitry Andric     return false;
940b57cec5SDimitry Andric 
9506c3fb27SDimitry Andric   llvm::StringRef prefix, suffix;
9606c3fb27SDimitry Andric   if (Language *language = Language::FindPlugin(options.GetLanguage()))
9706c3fb27SDimitry Andric     std::tie(prefix, suffix) = language->GetFormatterPrefixSuffix(g_TypeHint);
980b57cec5SDimitry Andric 
9906c3fb27SDimitry Andric   stream << prefix;
10006c3fb27SDimitry Andric   stream.Printf("\"%u value%s\"", count, (count == 1 ? "" : "s"));
10106c3fb27SDimitry Andric   stream << suffix;
1020b57cec5SDimitry Andric   return true;
1030b57cec5SDimitry Andric }
1040b57cec5SDimitry Andric 
CFBitVectorSummaryProvider(ValueObject & valobj,Stream & stream,const TypeSummaryOptions & options)1050b57cec5SDimitry Andric bool lldb_private::formatters::CFBitVectorSummaryProvider(
1060b57cec5SDimitry Andric     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
1070b57cec5SDimitry Andric   ProcessSP process_sp = valobj.GetProcessSP();
1080b57cec5SDimitry Andric   if (!process_sp)
1090b57cec5SDimitry Andric     return false;
1100b57cec5SDimitry Andric 
1110b57cec5SDimitry Andric   ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
1120b57cec5SDimitry Andric 
1130b57cec5SDimitry Andric   if (!runtime)
1140b57cec5SDimitry Andric     return false;
1150b57cec5SDimitry Andric 
1160b57cec5SDimitry Andric   ObjCLanguageRuntime::ClassDescriptorSP descriptor(
1170b57cec5SDimitry Andric       runtime->GetClassDescriptor(valobj));
1180b57cec5SDimitry Andric 
1190b57cec5SDimitry Andric   if (!descriptor.get() || !descriptor->IsValid())
1200b57cec5SDimitry Andric     return false;
1210b57cec5SDimitry Andric 
1220b57cec5SDimitry Andric   uint32_t ptr_size = process_sp->GetAddressByteSize();
1230b57cec5SDimitry Andric 
1240b57cec5SDimitry Andric   lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
1250b57cec5SDimitry Andric 
1260b57cec5SDimitry Andric   if (!valobj_addr)
1270b57cec5SDimitry Andric     return false;
1280b57cec5SDimitry Andric 
1290b57cec5SDimitry Andric   uint32_t count = 0;
1300b57cec5SDimitry Andric 
1310b57cec5SDimitry Andric   bool is_type_ok = false; // check to see if this is a CFBag we know about
1320b57cec5SDimitry Andric   if (descriptor->IsCFType()) {
1330b57cec5SDimitry Andric     ConstString type_name(valobj.GetTypeName());
1340b57cec5SDimitry Andric     if (type_name == "__CFMutableBitVector" || type_name == "__CFBitVector" ||
1350b57cec5SDimitry Andric         type_name == "CFMutableBitVectorRef" || type_name == "CFBitVectorRef") {
1360b57cec5SDimitry Andric       if (valobj.IsPointerType())
1370b57cec5SDimitry Andric         is_type_ok = true;
1380b57cec5SDimitry Andric     }
1390b57cec5SDimitry Andric   }
1400b57cec5SDimitry Andric 
1410b57cec5SDimitry Andric   if (!is_type_ok)
1420b57cec5SDimitry Andric     return false;
1430b57cec5SDimitry Andric 
1440b57cec5SDimitry Andric   Status error;
1450b57cec5SDimitry Andric   count = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + 2 * ptr_size,
1460b57cec5SDimitry Andric                                                     ptr_size, 0, error);
1470b57cec5SDimitry Andric   if (error.Fail())
1480b57cec5SDimitry Andric     return false;
1490b57cec5SDimitry Andric   uint64_t num_bytes = count / 8 + ((count & 7) ? 1 : 0);
1500b57cec5SDimitry Andric   addr_t data_ptr = process_sp->ReadPointerFromMemory(
1510b57cec5SDimitry Andric       valobj_addr + 2 * ptr_size + 2 * ptr_size, error);
1520b57cec5SDimitry Andric   if (error.Fail())
1530b57cec5SDimitry Andric     return false;
1540b57cec5SDimitry Andric   // make sure we do not try to read huge amounts of data
1550b57cec5SDimitry Andric   if (num_bytes > 1024)
1560b57cec5SDimitry Andric     num_bytes = 1024;
15781ad6265SDimitry Andric   WritableDataBufferSP buffer_sp(new DataBufferHeap(num_bytes, 0));
1580b57cec5SDimitry Andric   num_bytes =
1590b57cec5SDimitry Andric       process_sp->ReadMemory(data_ptr, buffer_sp->GetBytes(), num_bytes, error);
1600b57cec5SDimitry Andric   if (error.Fail() || num_bytes == 0)
1610b57cec5SDimitry Andric     return false;
1620b57cec5SDimitry Andric   uint8_t *bytes = buffer_sp->GetBytes();
1630b57cec5SDimitry Andric   for (uint64_t byte_idx = 0; byte_idx < num_bytes - 1; byte_idx++) {
1640b57cec5SDimitry Andric     uint8_t byte = bytes[byte_idx];
1650b57cec5SDimitry Andric     bool bit0 = (byte & 1) == 1;
1660b57cec5SDimitry Andric     bool bit1 = (byte & 2) == 2;
1670b57cec5SDimitry Andric     bool bit2 = (byte & 4) == 4;
1680b57cec5SDimitry Andric     bool bit3 = (byte & 8) == 8;
1690b57cec5SDimitry Andric     bool bit4 = (byte & 16) == 16;
1700b57cec5SDimitry Andric     bool bit5 = (byte & 32) == 32;
1710b57cec5SDimitry Andric     bool bit6 = (byte & 64) == 64;
1720b57cec5SDimitry Andric     bool bit7 = (byte & 128) == 128;
1730b57cec5SDimitry Andric     stream.Printf("%c%c%c%c %c%c%c%c ", (bit7 ? '1' : '0'), (bit6 ? '1' : '0'),
1740b57cec5SDimitry Andric                   (bit5 ? '1' : '0'), (bit4 ? '1' : '0'), (bit3 ? '1' : '0'),
1750b57cec5SDimitry Andric                   (bit2 ? '1' : '0'), (bit1 ? '1' : '0'), (bit0 ? '1' : '0'));
1760b57cec5SDimitry Andric     count -= 8;
1770b57cec5SDimitry Andric   }
1780b57cec5SDimitry Andric   {
1790b57cec5SDimitry Andric     // print the last byte ensuring we do not print spurious bits
1800b57cec5SDimitry Andric     uint8_t byte = bytes[num_bytes - 1];
1810b57cec5SDimitry Andric     bool bit0 = (byte & 1) == 1;
1820b57cec5SDimitry Andric     bool bit1 = (byte & 2) == 2;
1830b57cec5SDimitry Andric     bool bit2 = (byte & 4) == 4;
1840b57cec5SDimitry Andric     bool bit3 = (byte & 8) == 8;
1850b57cec5SDimitry Andric     bool bit4 = (byte & 16) == 16;
1860b57cec5SDimitry Andric     bool bit5 = (byte & 32) == 32;
1870b57cec5SDimitry Andric     bool bit6 = (byte & 64) == 64;
1880b57cec5SDimitry Andric     bool bit7 = (byte & 128) == 128;
1890b57cec5SDimitry Andric     if (count) {
1900b57cec5SDimitry Andric       stream.Printf("%c", bit7 ? '1' : '0');
1910b57cec5SDimitry Andric       count -= 1;
1920b57cec5SDimitry Andric     }
1930b57cec5SDimitry Andric     if (count) {
1940b57cec5SDimitry Andric       stream.Printf("%c", bit6 ? '1' : '0');
1950b57cec5SDimitry Andric       count -= 1;
1960b57cec5SDimitry Andric     }
1970b57cec5SDimitry Andric     if (count) {
1980b57cec5SDimitry Andric       stream.Printf("%c", bit5 ? '1' : '0');
1990b57cec5SDimitry Andric       count -= 1;
2000b57cec5SDimitry Andric     }
2010b57cec5SDimitry Andric     if (count) {
2020b57cec5SDimitry Andric       stream.Printf("%c", bit4 ? '1' : '0');
2030b57cec5SDimitry Andric       count -= 1;
2040b57cec5SDimitry Andric     }
2050b57cec5SDimitry Andric     if (count) {
2060b57cec5SDimitry Andric       stream.Printf("%c", bit3 ? '1' : '0');
2070b57cec5SDimitry Andric       count -= 1;
2080b57cec5SDimitry Andric     }
2090b57cec5SDimitry Andric     if (count) {
2100b57cec5SDimitry Andric       stream.Printf("%c", bit2 ? '1' : '0');
2110b57cec5SDimitry Andric       count -= 1;
2120b57cec5SDimitry Andric     }
2130b57cec5SDimitry Andric     if (count) {
2140b57cec5SDimitry Andric       stream.Printf("%c", bit1 ? '1' : '0');
2150b57cec5SDimitry Andric       count -= 1;
2160b57cec5SDimitry Andric     }
2170b57cec5SDimitry Andric     if (count)
2180b57cec5SDimitry Andric       stream.Printf("%c", bit0 ? '1' : '0');
2190b57cec5SDimitry Andric   }
2200b57cec5SDimitry Andric   return true;
2210b57cec5SDimitry Andric }
2220b57cec5SDimitry Andric 
CFBinaryHeapSummaryProvider(ValueObject & valobj,Stream & stream,const TypeSummaryOptions & options)2230b57cec5SDimitry Andric bool lldb_private::formatters::CFBinaryHeapSummaryProvider(
2240b57cec5SDimitry Andric     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
22506c3fb27SDimitry Andric   static constexpr llvm::StringLiteral g_TypeHint("CFBinaryHeap");
2260b57cec5SDimitry Andric 
2270b57cec5SDimitry Andric   ProcessSP process_sp = valobj.GetProcessSP();
2280b57cec5SDimitry Andric   if (!process_sp)
2290b57cec5SDimitry Andric     return false;
2300b57cec5SDimitry Andric 
2310b57cec5SDimitry Andric   ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
2320b57cec5SDimitry Andric 
2330b57cec5SDimitry Andric   if (!runtime)
2340b57cec5SDimitry Andric     return false;
2350b57cec5SDimitry Andric 
2360b57cec5SDimitry Andric   ObjCLanguageRuntime::ClassDescriptorSP descriptor(
2370b57cec5SDimitry Andric       runtime->GetClassDescriptor(valobj));
2380b57cec5SDimitry Andric 
2390b57cec5SDimitry Andric   if (!descriptor.get() || !descriptor->IsValid())
2400b57cec5SDimitry Andric     return false;
2410b57cec5SDimitry Andric 
2420b57cec5SDimitry Andric   uint32_t ptr_size = process_sp->GetAddressByteSize();
2430b57cec5SDimitry Andric 
2440b57cec5SDimitry Andric   lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
2450b57cec5SDimitry Andric 
2460b57cec5SDimitry Andric   if (!valobj_addr)
2470b57cec5SDimitry Andric     return false;
2480b57cec5SDimitry Andric 
2490b57cec5SDimitry Andric   uint32_t count = 0;
2500b57cec5SDimitry Andric 
2510b57cec5SDimitry Andric   bool is_type_ok =
2520b57cec5SDimitry Andric       false; // check to see if this is a CFBinaryHeap we know about
2530b57cec5SDimitry Andric   if (descriptor->IsCFType()) {
2540b57cec5SDimitry Andric     ConstString type_name(valobj.GetTypeName());
2550b57cec5SDimitry Andric 
25681ad6265SDimitry Andric     static ConstString g_CFBinaryHeap("__CFBinaryHeap");
2570b57cec5SDimitry Andric     static ConstString g_conststruct__CFBinaryHeap(
2580b57cec5SDimitry Andric         "const struct __CFBinaryHeap");
2590b57cec5SDimitry Andric     static ConstString g_CFBinaryHeapRef("CFBinaryHeapRef");
2600b57cec5SDimitry Andric 
26181ad6265SDimitry Andric     if (type_name == g_CFBinaryHeap ||
2620b57cec5SDimitry Andric         type_name == g_conststruct__CFBinaryHeap ||
2630b57cec5SDimitry Andric         type_name == g_CFBinaryHeapRef) {
2640b57cec5SDimitry Andric       if (valobj.IsPointerType())
2650b57cec5SDimitry Andric         is_type_ok = true;
2660b57cec5SDimitry Andric     }
2670b57cec5SDimitry Andric   }
2680b57cec5SDimitry Andric 
2690b57cec5SDimitry Andric   if (is_type_ok) {
2700b57cec5SDimitry Andric     lldb::addr_t offset = 2 * ptr_size + valobj_addr;
2710b57cec5SDimitry Andric     Status error;
2720b57cec5SDimitry Andric     count = process_sp->ReadUnsignedIntegerFromMemory(offset, 4, 0, error);
2730b57cec5SDimitry Andric     if (error.Fail())
2740b57cec5SDimitry Andric       return false;
2750b57cec5SDimitry Andric   } else
2760b57cec5SDimitry Andric     return false;
2770b57cec5SDimitry Andric 
27806c3fb27SDimitry Andric   llvm::StringRef prefix, suffix;
27906c3fb27SDimitry Andric   if (Language *language = Language::FindPlugin(options.GetLanguage()))
28006c3fb27SDimitry Andric     std::tie(prefix, suffix) = language->GetFormatterPrefixSuffix(g_TypeHint);
2810b57cec5SDimitry Andric 
28206c3fb27SDimitry Andric   stream << prefix;
28306c3fb27SDimitry Andric   stream.Printf("\"%u item%s\"", count, (count == 1 ? "" : "s"));
28406c3fb27SDimitry Andric   stream << suffix;
2850b57cec5SDimitry Andric   return true;
2860b57cec5SDimitry Andric }
287