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