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