1 //===-- CF.cpp ----------------------------------------------------*- C++
2 //-*-===//
3 //
4 //                     The LLVM Compiler Infrastructure
5 //
6 // This file is distributed under the University of Illinois Open Source
7 // License. See LICENSE.TXT for details.
8 //
9 //===----------------------------------------------------------------------===//
10 
11 #include "CF.h"
12 
13 #include "lldb/Core/DataBufferHeap.h"
14 #include "lldb/Core/Error.h"
15 #include "lldb/Core/Stream.h"
16 #include "lldb/Core/ValueObject.h"
17 #include "lldb/Core/ValueObjectConstResult.h"
18 #include "lldb/DataFormatters/FormattersHelpers.h"
19 #include "lldb/Host/Endian.h"
20 #include "lldb/Symbol/ClangASTContext.h"
21 #include "lldb/Target/Language.h"
22 #include "lldb/Target/ObjCLanguageRuntime.h"
23 #include "lldb/Target/StackFrame.h"
24 #include "lldb/Target/Target.h"
25 
26 using namespace lldb;
27 using namespace lldb_private;
28 using namespace lldb_private::formatters;
29 
30 bool lldb_private::formatters::CFAbsoluteTimeSummaryProvider(
31     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
32   time_t epoch = GetOSXEpoch();
33   epoch = epoch + (time_t)valobj.GetValueAsUnsigned(0);
34   tm *tm_date = localtime(&epoch);
35   if (!tm_date)
36     return false;
37   std::string buffer(1024, 0);
38   if (strftime(&buffer[0], 1023, "%Z", tm_date) == 0)
39     return false;
40   stream.Printf("%04d-%02d-%02d %02d:%02d:%02d %s", tm_date->tm_year + 1900,
41                 tm_date->tm_mon + 1, tm_date->tm_mday, tm_date->tm_hour,
42                 tm_date->tm_min, tm_date->tm_sec, buffer.c_str());
43   return true;
44 }
45 
46 bool lldb_private::formatters::CFBagSummaryProvider(
47     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
48   static ConstString g_TypeHint("CFBag");
49 
50   ProcessSP process_sp = valobj.GetProcessSP();
51   if (!process_sp)
52     return false;
53 
54   ObjCLanguageRuntime *runtime =
55       (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
56           lldb::eLanguageTypeObjC);
57 
58   if (!runtime)
59     return false;
60 
61   ObjCLanguageRuntime::ClassDescriptorSP descriptor(
62       runtime->GetClassDescriptor(valobj));
63 
64   if (!descriptor.get() || !descriptor->IsValid())
65     return false;
66 
67   uint32_t ptr_size = process_sp->GetAddressByteSize();
68 
69   lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
70 
71   if (!valobj_addr)
72     return false;
73 
74   uint32_t count = 0;
75 
76   bool is_type_ok = false; // check to see if this is a CFBag we know about
77   if (descriptor->IsCFType()) {
78     ConstString type_name(valobj.GetTypeName());
79 
80     static ConstString g___CFBag("__CFBag");
81     static ConstString g_conststruct__CFBag("const struct __CFBag");
82 
83     if (type_name == g___CFBag || type_name == g_conststruct__CFBag) {
84       if (valobj.IsPointerType())
85         is_type_ok = true;
86     }
87   }
88 
89   if (is_type_ok) {
90     lldb::addr_t offset = 2 * ptr_size + 4 + valobj_addr;
91     Error error;
92     count = process_sp->ReadUnsignedIntegerFromMemory(offset, 4, 0, error);
93     if (error.Fail())
94       return false;
95   } else
96     return false;
97 
98   std::string prefix, suffix;
99   if (Language *language = Language::FindPlugin(options.GetLanguage())) {
100     if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
101                                             suffix)) {
102       prefix.clear();
103       suffix.clear();
104     }
105   }
106 
107   stream.Printf("%s\"%u value%s\"%s", prefix.c_str(), count,
108                 (count == 1 ? "" : "s"), suffix.c_str());
109   return true;
110 }
111 
112 bool lldb_private::formatters::CFBitVectorSummaryProvider(
113     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
114   ProcessSP process_sp = valobj.GetProcessSP();
115   if (!process_sp)
116     return false;
117 
118   ObjCLanguageRuntime *runtime =
119       (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
120           lldb::eLanguageTypeObjC);
121 
122   if (!runtime)
123     return false;
124 
125   ObjCLanguageRuntime::ClassDescriptorSP descriptor(
126       runtime->GetClassDescriptor(valobj));
127 
128   if (!descriptor.get() || !descriptor->IsValid())
129     return false;
130 
131   uint32_t ptr_size = process_sp->GetAddressByteSize();
132 
133   lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
134 
135   if (!valobj_addr)
136     return false;
137 
138   uint32_t count = 0;
139 
140   bool is_type_ok = false; // check to see if this is a CFBag we know about
141   if (descriptor->IsCFType()) {
142     ConstString type_name(valobj.GetTypeName());
143     if (type_name == ConstString("__CFMutableBitVector") ||
144         type_name == ConstString("__CFBitVector") ||
145         type_name == ConstString("CFMutableBitVectorRef") ||
146         type_name == ConstString("CFBitVectorRef")) {
147       if (valobj.IsPointerType())
148         is_type_ok = true;
149     }
150   }
151 
152   if (is_type_ok == false)
153     return false;
154 
155   Error error;
156   count = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + 2 * ptr_size,
157                                                     ptr_size, 0, error);
158   if (error.Fail())
159     return false;
160   uint64_t num_bytes = count / 8 + ((count & 7) ? 1 : 0);
161   addr_t data_ptr = process_sp->ReadPointerFromMemory(
162       valobj_addr + 2 * ptr_size + 2 * ptr_size, error);
163   if (error.Fail())
164     return false;
165   // make sure we do not try to read huge amounts of data
166   if (num_bytes > 1024)
167     num_bytes = 1024;
168   DataBufferSP buffer_sp(new DataBufferHeap(num_bytes, 0));
169   num_bytes =
170       process_sp->ReadMemory(data_ptr, buffer_sp->GetBytes(), num_bytes, error);
171   if (error.Fail() || num_bytes == 0)
172     return false;
173   uint8_t *bytes = buffer_sp->GetBytes();
174   for (uint64_t byte_idx = 0; byte_idx < num_bytes - 1; byte_idx++) {
175     uint8_t byte = bytes[byte_idx];
176     bool bit0 = (byte & 1) == 1;
177     bool bit1 = (byte & 2) == 2;
178     bool bit2 = (byte & 4) == 4;
179     bool bit3 = (byte & 8) == 8;
180     bool bit4 = (byte & 16) == 16;
181     bool bit5 = (byte & 32) == 32;
182     bool bit6 = (byte & 64) == 64;
183     bool bit7 = (byte & 128) == 128;
184     stream.Printf("%c%c%c%c %c%c%c%c ", (bit7 ? '1' : '0'), (bit6 ? '1' : '0'),
185                   (bit5 ? '1' : '0'), (bit4 ? '1' : '0'), (bit3 ? '1' : '0'),
186                   (bit2 ? '1' : '0'), (bit1 ? '1' : '0'), (bit0 ? '1' : '0'));
187     count -= 8;
188   }
189   {
190     // print the last byte ensuring we do not print spurious bits
191     uint8_t byte = bytes[num_bytes - 1];
192     bool bit0 = (byte & 1) == 1;
193     bool bit1 = (byte & 2) == 2;
194     bool bit2 = (byte & 4) == 4;
195     bool bit3 = (byte & 8) == 8;
196     bool bit4 = (byte & 16) == 16;
197     bool bit5 = (byte & 32) == 32;
198     bool bit6 = (byte & 64) == 64;
199     bool bit7 = (byte & 128) == 128;
200     if (count) {
201       stream.Printf("%c", bit7 ? '1' : '0');
202       count -= 1;
203     }
204     if (count) {
205       stream.Printf("%c", bit6 ? '1' : '0');
206       count -= 1;
207     }
208     if (count) {
209       stream.Printf("%c", bit5 ? '1' : '0');
210       count -= 1;
211     }
212     if (count) {
213       stream.Printf("%c", bit4 ? '1' : '0');
214       count -= 1;
215     }
216     if (count) {
217       stream.Printf("%c", bit3 ? '1' : '0');
218       count -= 1;
219     }
220     if (count) {
221       stream.Printf("%c", bit2 ? '1' : '0');
222       count -= 1;
223     }
224     if (count) {
225       stream.Printf("%c", bit1 ? '1' : '0');
226       count -= 1;
227     }
228     if (count)
229       stream.Printf("%c", bit0 ? '1' : '0');
230   }
231   return true;
232 }
233 
234 bool lldb_private::formatters::CFBinaryHeapSummaryProvider(
235     ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
236   static ConstString g_TypeHint("CFBinaryHeap");
237 
238   ProcessSP process_sp = valobj.GetProcessSP();
239   if (!process_sp)
240     return false;
241 
242   ObjCLanguageRuntime *runtime =
243       (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
244           lldb::eLanguageTypeObjC);
245 
246   if (!runtime)
247     return false;
248 
249   ObjCLanguageRuntime::ClassDescriptorSP descriptor(
250       runtime->GetClassDescriptor(valobj));
251 
252   if (!descriptor.get() || !descriptor->IsValid())
253     return false;
254 
255   uint32_t ptr_size = process_sp->GetAddressByteSize();
256 
257   lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
258 
259   if (!valobj_addr)
260     return false;
261 
262   uint32_t count = 0;
263 
264   bool is_type_ok =
265       false; // check to see if this is a CFBinaryHeap we know about
266   if (descriptor->IsCFType()) {
267     ConstString type_name(valobj.GetTypeName());
268 
269     static ConstString g___CFBinaryHeap("__CFBinaryHeap");
270     static ConstString g_conststruct__CFBinaryHeap(
271         "const struct __CFBinaryHeap");
272     static ConstString g_CFBinaryHeapRef("CFBinaryHeapRef");
273 
274     if (type_name == g___CFBinaryHeap ||
275         type_name == g_conststruct__CFBinaryHeap ||
276         type_name == g_CFBinaryHeapRef) {
277       if (valobj.IsPointerType())
278         is_type_ok = true;
279     }
280   }
281 
282   if (is_type_ok) {
283     lldb::addr_t offset = 2 * ptr_size + valobj_addr;
284     Error error;
285     count = process_sp->ReadUnsignedIntegerFromMemory(offset, 4, 0, error);
286     if (error.Fail())
287       return false;
288   } else
289     return false;
290 
291   std::string prefix, suffix;
292   if (Language *language = Language::FindPlugin(options.GetLanguage())) {
293     if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
294                                             suffix)) {
295       prefix.clear();
296       suffix.clear();
297     }
298   }
299 
300   stream.Printf("%s\"%u item%s\"%s", prefix.c_str(), count,
301                 (count == 1 ? "" : "s"), suffix.c_str());
302   return true;
303 }
304