blob: 614eb29a0f7a4435c8a099000bfa75066a838ba6 [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"
Jim Inghama309efe2015-10-28 22:23:17 +000022#include "lldb/Target/StackFrame.h"
Enrico Granata92373532013-03-19 22:58:48 +000023#include "lldb/Target/Target.h"
24
25using namespace lldb;
26using namespace lldb_private;
27using namespace lldb_private::formatters;
28
29bool
Enrico Granataf35bc632014-11-06 21:55:30 +000030lldb_private::formatters::CFAbsoluteTimeSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
Enrico Granata92373532013-03-19 22:58:48 +000031{
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
44bool
Enrico Granataf35bc632014-11-06 21:55:30 +000045lldb_private::formatters::CFBagSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
Enrico Granata92373532013-03-19 22:58:48 +000046{
Enrico Granata675f49b2015-10-07 18:36:53 +000047 static ConstString g_TypeHint("CFBag");
48
Enrico Granata92373532013-03-19 22:58:48 +000049 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 {
Jason Molendab57e4a12013-11-04 09:33:30 +000085 StackFrameSP frame_sp(valobj.GetFrameSP());
Enrico Granata92373532013-03-19 22:58:48 +000086 if (!frame_sp)
87 return false;
88 ValueObjectSP count_sp;
89 StreamString expr;
90 expr.Printf("(int)CFBagGetCount((void*)0x%" PRIx64 ")",valobj.GetPointerValue());
Enrico Granata675f49b2015-10-07 18:36:53 +000091 EvaluateExpressionOptions options;
92 options.SetResultIsInternal(true);
93 if (process_sp->GetTarget().EvaluateExpression(expr.GetData(), frame_sp.get(), count_sp, options) != eExpressionCompleted)
Enrico Granata92373532013-03-19 22:58:48 +000094 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 }
Enrico Granata675f49b2015-10-07 18:36:53 +0000107
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());
Enrico Granata92373532013-03-19 22:58:48 +0000122 return true;
123}
124
125bool
Enrico Granataf35bc632014-11-06 21:55:30 +0000126lldb_private::formatters::CFBitVectorSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
Enrico Granata92373532013-03-19 22:58:48 +0000127{
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);
Enrico Granata4c648b12013-06-10 22:26:15 +0000178 if (error.Fail() || num_bytes == 0)
Enrico Granata92373532013-03-19 22:58:48 +0000179 return false;
Enrico Granata4c648b12013-06-10 22:26:15 +0000180 uint8_t *bytes = buffer_sp->GetBytes();
Saleem Abdulrasool3985c8c2014-04-02 03:51:35 +0000181 for (uint64_t byte_idx = 0; byte_idx < num_bytes-1; byte_idx++)
Enrico Granata92373532013-03-19 22:58:48 +0000182 {
Enrico Granata4c648b12013-06-10 22:26:15 +0000183 uint8_t byte = bytes[byte_idx];
Enrico Granata92373532013-03-19 22:58:48 +0000184 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
Enrico Granata4c648b12013-06-10 22:26:15 +0000205 uint8_t byte = bytes[num_bytes-1];
Enrico Granata92373532013-03-19 22:58:48 +0000206 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)
Enrico Granata92373532013-03-19 22:58:48 +0000250 stream.Printf("%c",bit0 ? '1' : '0');
Enrico Granata92373532013-03-19 22:58:48 +0000251 }
252 return true;
253}
254
255bool
Enrico Granataf35bc632014-11-06 21:55:30 +0000256lldb_private::formatters::CFBinaryHeapSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
Enrico Granata92373532013-03-19 22:58:48 +0000257{
Enrico Granata675f49b2015-10-07 18:36:53 +0000258 static ConstString g_TypeHint("CFBinaryHeap");
259
Enrico Granata92373532013-03-19 22:58:48 +0000260 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 {
Jason Molendab57e4a12013-11-04 09:33:30 +0000296 StackFrameSP frame_sp(valobj.GetFrameSP());
Enrico Granata92373532013-03-19 22:58:48 +0000297 if (!frame_sp)
298 return false;
299 ValueObjectSP count_sp;
300 StreamString expr;
301 expr.Printf("(int)CFBinaryHeapGetCount((void*)0x%" PRIx64 ")",valobj.GetPointerValue());
Enrico Granata675f49b2015-10-07 18:36:53 +0000302 EvaluateExpressionOptions options;
303 options.SetResultIsInternal(true);
304 if (process_sp->GetTarget().EvaluateExpression(expr.GetData(), frame_sp.get(), count_sp, options) != eExpressionCompleted)
Enrico Granata92373532013-03-19 22:58:48 +0000305 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 }
Enrico Granata675f49b2015-10-07 18:36:53 +0000318
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());
Enrico Granata92373532013-03-19 22:58:48 +0000333 return true;
334}