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