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