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