180814287SRaphael Isemann //===-- CF.cpp ------------------------------------------------------------===//
2170c395eSEnrico 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
6170c395eSEnrico Granata //
7170c395eSEnrico Granata //===----------------------------------------------------------------------===//
8170c395eSEnrico Granata 
9170c395eSEnrico Granata #include "CF.h"
10170c395eSEnrico Granata 
118be30215SAlex Langford #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
12170c395eSEnrico Granata #include "lldb/Core/ValueObject.h"
13170c395eSEnrico Granata #include "lldb/Core/ValueObjectConstResult.h"
14170c395eSEnrico Granata #include "lldb/DataFormatters/FormattersHelpers.h"
15675f49bbSEnrico Granata #include "lldb/Target/Language.h"
16a309efefSJim Ingham #include "lldb/Target/StackFrame.h"
17170c395eSEnrico Granata #include "lldb/Target/Target.h"
18666cc0b2SZachary Turner #include "lldb/Utility/DataBufferHeap.h"
1901c3243fSZachary Turner #include "lldb/Utility/Endian.h"
2097206d57SZachary Turner #include "lldb/Utility/Status.h"
21bf9a7730SZachary Turner #include "lldb/Utility/Stream.h"
22170c395eSEnrico Granata 
23b5701710SAlex Langford #include "Plugins/LanguageRuntime/ObjC/ObjCLanguageRuntime.h"
24b5701710SAlex Langford 
25170c395eSEnrico Granata using namespace lldb;
26170c395eSEnrico Granata using namespace lldb_private;
27170c395eSEnrico Granata using namespace lldb_private::formatters;
28170c395eSEnrico Granata 
CFAbsoluteTimeSummaryProvider(ValueObject & valobj,Stream & stream,const TypeSummaryOptions & options)29b9c1b51eSKate Stone bool lldb_private::formatters::CFAbsoluteTimeSummaryProvider(
30b9c1b51eSKate Stone     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
31170c395eSEnrico Granata   time_t epoch = GetOSXEpoch();
32f3b5bf3eSRaphael Isemann   epoch = epoch + (time_t)valobj.GetValueAsSigned(0);
33170c395eSEnrico Granata   tm *tm_date = localtime(&epoch);
34170c395eSEnrico Granata   if (!tm_date)
35170c395eSEnrico Granata     return false;
36170c395eSEnrico Granata   std::string buffer(1024, 0);
37170c395eSEnrico Granata   if (strftime(&buffer[0], 1023, "%Z", tm_date) == 0)
38170c395eSEnrico Granata     return false;
39b9c1b51eSKate Stone   stream.Printf("%04d-%02d-%02d %02d:%02d:%02d %s", tm_date->tm_year + 1900,
40b9c1b51eSKate Stone                 tm_date->tm_mon + 1, tm_date->tm_mday, tm_date->tm_hour,
41b9c1b51eSKate Stone                 tm_date->tm_min, tm_date->tm_sec, buffer.c_str());
42170c395eSEnrico Granata   return true;
43170c395eSEnrico Granata }
44170c395eSEnrico Granata 
CFBagSummaryProvider(ValueObject & valobj,Stream & stream,const TypeSummaryOptions & options)45b9c1b51eSKate Stone bool lldb_private::formatters::CFBagSummaryProvider(
46b9c1b51eSKate Stone     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
47675f49bbSEnrico Granata   static ConstString g_TypeHint("CFBag");
48675f49bbSEnrico Granata 
49170c395eSEnrico Granata   ProcessSP process_sp = valobj.GetProcessSP();
50170c395eSEnrico Granata   if (!process_sp)
51170c395eSEnrico Granata     return false;
52170c395eSEnrico Granata 
53e823bbe8SAlex Langford   ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
54170c395eSEnrico Granata 
55170c395eSEnrico Granata   if (!runtime)
56170c395eSEnrico Granata     return false;
57170c395eSEnrico Granata 
58b9c1b51eSKate Stone   ObjCLanguageRuntime::ClassDescriptorSP descriptor(
59b9c1b51eSKate Stone       runtime->GetClassDescriptor(valobj));
60170c395eSEnrico Granata 
61170c395eSEnrico Granata   if (!descriptor.get() || !descriptor->IsValid())
62170c395eSEnrico Granata     return false;
63170c395eSEnrico Granata 
64170c395eSEnrico Granata   uint32_t ptr_size = process_sp->GetAddressByteSize();
65170c395eSEnrico Granata 
66170c395eSEnrico Granata   lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
67170c395eSEnrico Granata 
68170c395eSEnrico Granata   if (!valobj_addr)
69170c395eSEnrico Granata     return false;
70170c395eSEnrico Granata 
71170c395eSEnrico Granata   uint32_t count = 0;
72170c395eSEnrico Granata 
73170c395eSEnrico Granata   bool is_type_ok = false; // check to see if this is a CFBag we know about
74b9c1b51eSKate Stone   if (descriptor->IsCFType()) {
75170c395eSEnrico Granata     ConstString type_name(valobj.GetTypeName());
76f96fd0ddSEnrico Granata 
7780a11e08SShafik Yaghmour     static ConstString g_CFBag("__CFBag");
78f96fd0ddSEnrico Granata     static ConstString g_conststruct__CFBag("const struct __CFBag");
79f96fd0ddSEnrico Granata 
8080a11e08SShafik Yaghmour     if (type_name == g_CFBag || type_name == g_conststruct__CFBag) {
81170c395eSEnrico Granata       if (valobj.IsPointerType())
82170c395eSEnrico Granata         is_type_ok = true;
83170c395eSEnrico Granata     }
84170c395eSEnrico Granata   }
85170c395eSEnrico Granata 
86b9c1b51eSKate Stone   if (is_type_ok) {
87f96fd0ddSEnrico Granata     lldb::addr_t offset = 2 * ptr_size + 4 + valobj_addr;
8897206d57SZachary Turner     Status error;
89170c395eSEnrico Granata     count = process_sp->ReadUnsignedIntegerFromMemory(offset, 4, 0, error);
90170c395eSEnrico Granata     if (error.Fail())
91170c395eSEnrico Granata       return false;
92b9c1b51eSKate Stone   } else
93f96fd0ddSEnrico Granata     return false;
94675f49bbSEnrico Granata 
95675f49bbSEnrico Granata   std::string prefix, suffix;
96b9c1b51eSKate Stone   if (Language *language = Language::FindPlugin(options.GetLanguage())) {
97b9c1b51eSKate Stone     if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
98b9c1b51eSKate Stone                                             suffix)) {
99675f49bbSEnrico Granata       prefix.clear();
100675f49bbSEnrico Granata       suffix.clear();
101675f49bbSEnrico Granata     }
102675f49bbSEnrico Granata   }
103675f49bbSEnrico Granata 
104b9c1b51eSKate Stone   stream.Printf("%s\"%u value%s\"%s", prefix.c_str(), count,
105b9c1b51eSKate Stone                 (count == 1 ? "" : "s"), suffix.c_str());
106170c395eSEnrico Granata   return true;
107170c395eSEnrico Granata }
108170c395eSEnrico Granata 
CFBitVectorSummaryProvider(ValueObject & valobj,Stream & stream,const TypeSummaryOptions & options)109b9c1b51eSKate Stone bool lldb_private::formatters::CFBitVectorSummaryProvider(
110b9c1b51eSKate Stone     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
111170c395eSEnrico Granata   ProcessSP process_sp = valobj.GetProcessSP();
112170c395eSEnrico Granata   if (!process_sp)
113170c395eSEnrico Granata     return false;
114170c395eSEnrico Granata 
115e823bbe8SAlex Langford   ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
116170c395eSEnrico Granata 
117170c395eSEnrico Granata   if (!runtime)
118170c395eSEnrico Granata     return false;
119170c395eSEnrico Granata 
120b9c1b51eSKate Stone   ObjCLanguageRuntime::ClassDescriptorSP descriptor(
121b9c1b51eSKate Stone       runtime->GetClassDescriptor(valobj));
122170c395eSEnrico Granata 
123170c395eSEnrico Granata   if (!descriptor.get() || !descriptor->IsValid())
124170c395eSEnrico Granata     return false;
125170c395eSEnrico Granata 
126170c395eSEnrico Granata   uint32_t ptr_size = process_sp->GetAddressByteSize();
127170c395eSEnrico Granata 
128170c395eSEnrico Granata   lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
129170c395eSEnrico Granata 
130170c395eSEnrico Granata   if (!valobj_addr)
131170c395eSEnrico Granata     return false;
132170c395eSEnrico Granata 
133170c395eSEnrico Granata   uint32_t count = 0;
134170c395eSEnrico Granata 
135170c395eSEnrico Granata   bool is_type_ok = false; // check to see if this is a CFBag we know about
136b9c1b51eSKate Stone   if (descriptor->IsCFType()) {
137170c395eSEnrico Granata     ConstString type_name(valobj.GetTypeName());
13805cfdb0eSRaphael Isemann     if (type_name == "__CFMutableBitVector" || type_name == "__CFBitVector" ||
13905cfdb0eSRaphael Isemann         type_name == "CFMutableBitVectorRef" || type_name == "CFBitVectorRef") {
140170c395eSEnrico Granata       if (valobj.IsPointerType())
141170c395eSEnrico Granata         is_type_ok = true;
142170c395eSEnrico Granata     }
143170c395eSEnrico Granata   }
144170c395eSEnrico Granata 
145a6682a41SJonas Devlieghere   if (!is_type_ok)
146170c395eSEnrico Granata     return false;
147170c395eSEnrico Granata 
14897206d57SZachary Turner   Status error;
149b9c1b51eSKate Stone   count = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + 2 * ptr_size,
150b9c1b51eSKate Stone                                                     ptr_size, 0, error);
151170c395eSEnrico Granata   if (error.Fail())
152170c395eSEnrico Granata     return false;
153170c395eSEnrico Granata   uint64_t num_bytes = count / 8 + ((count & 7) ? 1 : 0);
154b9c1b51eSKate Stone   addr_t data_ptr = process_sp->ReadPointerFromMemory(
155b9c1b51eSKate Stone       valobj_addr + 2 * ptr_size + 2 * ptr_size, error);
156170c395eSEnrico Granata   if (error.Fail())
157170c395eSEnrico Granata     return false;
158170c395eSEnrico Granata   // make sure we do not try to read huge amounts of data
159170c395eSEnrico Granata   if (num_bytes > 1024)
160170c395eSEnrico Granata     num_bytes = 1024;
161*fc54427eSJonas Devlieghere   WritableDataBufferSP buffer_sp(new DataBufferHeap(num_bytes, 0));
162b9c1b51eSKate Stone   num_bytes =
163b9c1b51eSKate Stone       process_sp->ReadMemory(data_ptr, buffer_sp->GetBytes(), num_bytes, error);
164170c395eSEnrico Granata   if (error.Fail() || num_bytes == 0)
165170c395eSEnrico Granata     return false;
166170c395eSEnrico Granata   uint8_t *bytes = buffer_sp->GetBytes();
167b9c1b51eSKate Stone   for (uint64_t byte_idx = 0; byte_idx < num_bytes - 1; byte_idx++) {
168170c395eSEnrico Granata     uint8_t byte = bytes[byte_idx];
169170c395eSEnrico Granata     bool bit0 = (byte & 1) == 1;
170170c395eSEnrico Granata     bool bit1 = (byte & 2) == 2;
171170c395eSEnrico Granata     bool bit2 = (byte & 4) == 4;
172170c395eSEnrico Granata     bool bit3 = (byte & 8) == 8;
173170c395eSEnrico Granata     bool bit4 = (byte & 16) == 16;
174170c395eSEnrico Granata     bool bit5 = (byte & 32) == 32;
175170c395eSEnrico Granata     bool bit6 = (byte & 64) == 64;
176170c395eSEnrico Granata     bool bit7 = (byte & 128) == 128;
177b9c1b51eSKate Stone     stream.Printf("%c%c%c%c %c%c%c%c ", (bit7 ? '1' : '0'), (bit6 ? '1' : '0'),
178b9c1b51eSKate Stone                   (bit5 ? '1' : '0'), (bit4 ? '1' : '0'), (bit3 ? '1' : '0'),
179b9c1b51eSKate Stone                   (bit2 ? '1' : '0'), (bit1 ? '1' : '0'), (bit0 ? '1' : '0'));
180170c395eSEnrico Granata     count -= 8;
181170c395eSEnrico Granata   }
182170c395eSEnrico Granata   {
183170c395eSEnrico Granata     // print the last byte ensuring we do not print spurious bits
184170c395eSEnrico Granata     uint8_t byte = bytes[num_bytes - 1];
185170c395eSEnrico Granata     bool bit0 = (byte & 1) == 1;
186170c395eSEnrico Granata     bool bit1 = (byte & 2) == 2;
187170c395eSEnrico Granata     bool bit2 = (byte & 4) == 4;
188170c395eSEnrico Granata     bool bit3 = (byte & 8) == 8;
189170c395eSEnrico Granata     bool bit4 = (byte & 16) == 16;
190170c395eSEnrico Granata     bool bit5 = (byte & 32) == 32;
191170c395eSEnrico Granata     bool bit6 = (byte & 64) == 64;
192170c395eSEnrico Granata     bool bit7 = (byte & 128) == 128;
193b9c1b51eSKate Stone     if (count) {
194170c395eSEnrico Granata       stream.Printf("%c", bit7 ? '1' : '0');
195170c395eSEnrico Granata       count -= 1;
196170c395eSEnrico Granata     }
197b9c1b51eSKate Stone     if (count) {
198170c395eSEnrico Granata       stream.Printf("%c", bit6 ? '1' : '0');
199170c395eSEnrico Granata       count -= 1;
200170c395eSEnrico Granata     }
201b9c1b51eSKate Stone     if (count) {
202170c395eSEnrico Granata       stream.Printf("%c", bit5 ? '1' : '0');
203170c395eSEnrico Granata       count -= 1;
204170c395eSEnrico Granata     }
205b9c1b51eSKate Stone     if (count) {
206170c395eSEnrico Granata       stream.Printf("%c", bit4 ? '1' : '0');
207170c395eSEnrico Granata       count -= 1;
208170c395eSEnrico Granata     }
209b9c1b51eSKate Stone     if (count) {
210170c395eSEnrico Granata       stream.Printf("%c", bit3 ? '1' : '0');
211170c395eSEnrico Granata       count -= 1;
212170c395eSEnrico Granata     }
213b9c1b51eSKate Stone     if (count) {
214170c395eSEnrico Granata       stream.Printf("%c", bit2 ? '1' : '0');
215170c395eSEnrico Granata       count -= 1;
216170c395eSEnrico Granata     }
217b9c1b51eSKate Stone     if (count) {
218170c395eSEnrico Granata       stream.Printf("%c", bit1 ? '1' : '0');
219170c395eSEnrico Granata       count -= 1;
220170c395eSEnrico Granata     }
221170c395eSEnrico Granata     if (count)
222170c395eSEnrico Granata       stream.Printf("%c", bit0 ? '1' : '0');
223170c395eSEnrico Granata   }
224170c395eSEnrico Granata   return true;
225170c395eSEnrico Granata }
226170c395eSEnrico Granata 
CFBinaryHeapSummaryProvider(ValueObject & valobj,Stream & stream,const TypeSummaryOptions & options)227b9c1b51eSKate Stone bool lldb_private::formatters::CFBinaryHeapSummaryProvider(
228b9c1b51eSKate Stone     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
229675f49bbSEnrico Granata   static ConstString g_TypeHint("CFBinaryHeap");
230675f49bbSEnrico Granata 
231170c395eSEnrico Granata   ProcessSP process_sp = valobj.GetProcessSP();
232170c395eSEnrico Granata   if (!process_sp)
233170c395eSEnrico Granata     return false;
234170c395eSEnrico Granata 
235e823bbe8SAlex Langford   ObjCLanguageRuntime *runtime = ObjCLanguageRuntime::Get(*process_sp);
236170c395eSEnrico Granata 
237170c395eSEnrico Granata   if (!runtime)
238170c395eSEnrico Granata     return false;
239170c395eSEnrico Granata 
240b9c1b51eSKate Stone   ObjCLanguageRuntime::ClassDescriptorSP descriptor(
241b9c1b51eSKate Stone       runtime->GetClassDescriptor(valobj));
242170c395eSEnrico Granata 
243170c395eSEnrico Granata   if (!descriptor.get() || !descriptor->IsValid())
244170c395eSEnrico Granata     return false;
245170c395eSEnrico Granata 
246170c395eSEnrico Granata   uint32_t ptr_size = process_sp->GetAddressByteSize();
247170c395eSEnrico Granata 
248170c395eSEnrico Granata   lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
249170c395eSEnrico Granata 
250170c395eSEnrico Granata   if (!valobj_addr)
251170c395eSEnrico Granata     return false;
252170c395eSEnrico Granata 
253170c395eSEnrico Granata   uint32_t count = 0;
254170c395eSEnrico Granata 
255b9c1b51eSKate Stone   bool is_type_ok =
256b9c1b51eSKate Stone       false; // check to see if this is a CFBinaryHeap we know about
257b9c1b51eSKate Stone   if (descriptor->IsCFType()) {
258170c395eSEnrico Granata     ConstString type_name(valobj.GetTypeName());
259f96fd0ddSEnrico Granata 
26080a11e08SShafik Yaghmour     static ConstString g_CFBinaryHeap("__CFBinaryHeap");
261b9c1b51eSKate Stone     static ConstString g_conststruct__CFBinaryHeap(
262b9c1b51eSKate Stone         "const struct __CFBinaryHeap");
263f96fd0ddSEnrico Granata     static ConstString g_CFBinaryHeapRef("CFBinaryHeapRef");
264f96fd0ddSEnrico Granata 
26580a11e08SShafik Yaghmour     if (type_name == g_CFBinaryHeap ||
266f96fd0ddSEnrico Granata         type_name == g_conststruct__CFBinaryHeap ||
267b9c1b51eSKate Stone         type_name == g_CFBinaryHeapRef) {
268170c395eSEnrico Granata       if (valobj.IsPointerType())
269170c395eSEnrico Granata         is_type_ok = true;
270170c395eSEnrico Granata     }
271170c395eSEnrico Granata   }
272170c395eSEnrico Granata 
273b9c1b51eSKate Stone   if (is_type_ok) {
274f96fd0ddSEnrico Granata     lldb::addr_t offset = 2 * ptr_size + valobj_addr;
27597206d57SZachary Turner     Status error;
276170c395eSEnrico Granata     count = process_sp->ReadUnsignedIntegerFromMemory(offset, 4, 0, error);
277170c395eSEnrico Granata     if (error.Fail())
278170c395eSEnrico Granata       return false;
279b9c1b51eSKate Stone   } else
280f96fd0ddSEnrico Granata     return false;
281675f49bbSEnrico Granata 
282675f49bbSEnrico Granata   std::string prefix, suffix;
283b9c1b51eSKate Stone   if (Language *language = Language::FindPlugin(options.GetLanguage())) {
284b9c1b51eSKate Stone     if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
285b9c1b51eSKate Stone                                             suffix)) {
286675f49bbSEnrico Granata       prefix.clear();
287675f49bbSEnrico Granata       suffix.clear();
288675f49bbSEnrico Granata     }
289675f49bbSEnrico Granata   }
290675f49bbSEnrico Granata 
291b9c1b51eSKate Stone   stream.Printf("%s\"%u item%s\"%s", prefix.c_str(), count,
292b9c1b51eSKate Stone                 (count == 1 ? "" : "s"), suffix.c_str());
293170c395eSEnrico Granata   return true;
294170c395eSEnrico Granata }
295