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