blob: 0dc0c662fe9657350cd870c7985091e0813ce13f [file] [log] [blame]
Enrico Granata92373532013-03-19 22:58:48 +00001//===-- 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
Enrico Granata170c3952015-09-14 22:18:32 +000010#include "CF.h"
Enrico Granata92373532013-03-19 22:58:48 +000011
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"
Enrico Granata419d7912015-09-04 00:33:51 +000017#include "lldb/DataFormatters/FormattersHelpers.h"
Enrico Granata92373532013-03-19 22:58:48 +000018#include "lldb/Host/Endian.h"
19#include "lldb/Symbol/ClangASTContext.h"
Enrico Granata675f49b2015-10-07 18:36:53 +000020#include "lldb/Target/Language.h"
Enrico Granata92373532013-03-19 22:58:48 +000021#include "lldb/Target/ObjCLanguageRuntime.h"
22#include "lldb/Target/Target.h"
23
24using namespace lldb;
25using namespace lldb_private;
26using namespace lldb_private::formatters;
27
28bool
Enrico Granataf35bc632014-11-06 21:55:30 +000029lldb_private::formatters::CFAbsoluteTimeSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
Enrico Granata92373532013-03-19 22:58:48 +000030{
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
43bool
Enrico Granataf35bc632014-11-06 21:55:30 +000044lldb_private::formatters::CFBagSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
Enrico Granata92373532013-03-19 22:58:48 +000045{
Enrico Granata675f49b2015-10-07 18:36:53 +000046 static ConstString g_TypeHint("CFBag");
47
Enrico Granata92373532013-03-19 22:58:48 +000048 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 {
Jason Molendab57e4a12013-11-04 09:33:30 +000084 StackFrameSP frame_sp(valobj.GetFrameSP());
Enrico Granata92373532013-03-19 22:58:48 +000085 if (!frame_sp)
86 return false;
87 ValueObjectSP count_sp;
88 StreamString expr;
89 expr.Printf("(int)CFBagGetCount((void*)0x%" PRIx64 ")",valobj.GetPointerValue());
Enrico Granata675f49b2015-10-07 18:36:53 +000090 EvaluateExpressionOptions options;
91 options.SetResultIsInternal(true);
92 if (process_sp->GetTarget().EvaluateExpression(expr.GetData(), frame_sp.get(), count_sp, options) != eExpressionCompleted)
Enrico Granata92373532013-03-19 22:58:48 +000093 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 }
Enrico Granata675f49b2015-10-07 18:36:53 +0000106
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());
Enrico Granata92373532013-03-19 22:58:48 +0000121 return true;
122}
123
124bool
Enrico Granataf35bc632014-11-06 21:55:30 +0000125lldb_private::formatters::CFBitVectorSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
Enrico Granata92373532013-03-19 22:58:48 +0000126{
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);
Enrico Granata4c648b12013-06-10 22:26:15 +0000177 if (error.Fail() || num_bytes == 0)
Enrico Granata92373532013-03-19 22:58:48 +0000178 return false;
Enrico Granata4c648b12013-06-10 22:26:15 +0000179 uint8_t *bytes = buffer_sp->GetBytes();
Saleem Abdulrasool3985c8c2014-04-02 03:51:35 +0000180 for (uint64_t byte_idx = 0; byte_idx < num_bytes-1; byte_idx++)
Enrico Granata92373532013-03-19 22:58:48 +0000181 {
Enrico Granata4c648b12013-06-10 22:26:15 +0000182 uint8_t byte = bytes[byte_idx];
Enrico Granata92373532013-03-19 22:58:48 +0000183 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
Enrico Granata4c648b12013-06-10 22:26:15 +0000204 uint8_t byte = bytes[num_bytes-1];
Enrico Granata92373532013-03-19 22:58:48 +0000205 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)
Enrico Granata92373532013-03-19 22:58:48 +0000249 stream.Printf("%c",bit0 ? '1' : '0');
Enrico Granata92373532013-03-19 22:58:48 +0000250 }
251 return true;
252}
253
254bool
Enrico Granataf35bc632014-11-06 21:55:30 +0000255lldb_private::formatters::CFBinaryHeapSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
Enrico Granata92373532013-03-19 22:58:48 +0000256{
Enrico Granata675f49b2015-10-07 18:36:53 +0000257 static ConstString g_TypeHint("CFBinaryHeap");
258
Enrico Granata92373532013-03-19 22:58:48 +0000259 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 {
Jason Molendab57e4a12013-11-04 09:33:30 +0000295 StackFrameSP frame_sp(valobj.GetFrameSP());
Enrico Granata92373532013-03-19 22:58:48 +0000296 if (!frame_sp)
297 return false;
298 ValueObjectSP count_sp;
299 StreamString expr;
300 expr.Printf("(int)CFBinaryHeapGetCount((void*)0x%" PRIx64 ")",valobj.GetPointerValue());
Enrico Granata675f49b2015-10-07 18:36:53 +0000301 EvaluateExpressionOptions options;
302 options.SetResultIsInternal(true);
303 if (process_sp->GetTarget().EvaluateExpression(expr.GetData(), frame_sp.get(), count_sp, options) != eExpressionCompleted)
Enrico Granata92373532013-03-19 22:58:48 +0000304 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 }
Enrico Granata675f49b2015-10-07 18:36:53 +0000317
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());
Enrico Granata92373532013-03-19 22:58:48 +0000332 return true;
333}