blob: 38ffbc2b0232fa2622da866f4789b2790989572a [file] [log] [blame]
Eugene Zelenko8d15f332015-10-20 01:10:59 +00001//===-- Cocoa.cpp -----------------------------------------------*- C++ -*-===//
Enrico Granata92373532013-03-19 22:58:48 +00002//
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
Eugene Zelenko8d15f332015-10-20 01:10:59 +000010// C Includes
11// C++ Includes
12// Other libraries and framework includes
13// Project includes
Enrico Granata170c3952015-09-14 22:18:32 +000014#include "Cocoa.h"
Enrico Granata92373532013-03-19 22:58:48 +000015
16#include "lldb/Core/DataBufferHeap.h"
17#include "lldb/Core/Error.h"
Enrico Granata7de855c2015-10-02 20:59:58 +000018#include "lldb/Core/Mangled.h"
Enrico Granata92373532013-03-19 22:58:48 +000019#include "lldb/Core/Stream.h"
20#include "lldb/Core/ValueObject.h"
21#include "lldb/Core/ValueObjectConstResult.h"
Enrico Granata419d7912015-09-04 00:33:51 +000022#include "lldb/DataFormatters/FormattersHelpers.h"
23#include "lldb/DataFormatters/StringPrinter.h"
24#include "lldb/DataFormatters/TypeSummary.h"
Enrico Granata92373532013-03-19 22:58:48 +000025#include "lldb/Host/Endian.h"
26#include "lldb/Symbol/ClangASTContext.h"
Enrico Granata675f49b2015-10-07 18:36:53 +000027#include "lldb/Target/Language.h"
Enrico Granata92373532013-03-19 22:58:48 +000028#include "lldb/Target/ObjCLanguageRuntime.h"
29#include "lldb/Target/Target.h"
Enrico Granata419d7912015-09-04 00:33:51 +000030#include "lldb/Target/Process.h"
Enrico Granatad87cc312015-09-03 01:29:42 +000031#include "lldb/Utility/ProcessStructReader.h"
32
Enrico Granata7de855c2015-10-02 20:59:58 +000033#include "NSString.h"
34
Enrico Granata92373532013-03-19 22:58:48 +000035using namespace lldb;
36using namespace lldb_private;
37using namespace lldb_private::formatters;
38
39bool
Enrico Granataf35bc632014-11-06 21:55:30 +000040lldb_private::formatters::NSBundleSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
Enrico Granata92373532013-03-19 22:58:48 +000041{
42 ProcessSP process_sp = valobj.GetProcessSP();
43 if (!process_sp)
44 return false;
45
46 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
47
48 if (!runtime)
49 return false;
50
51 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
52
53 if (!descriptor.get() || !descriptor->IsValid())
54 return false;
55
56 uint32_t ptr_size = process_sp->GetAddressByteSize();
57
58 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
59
60 if (!valobj_addr)
61 return false;
62
63 const char* class_name = descriptor->GetClassName().GetCString();
64
65 if (!class_name || !*class_name)
66 return false;
67
68 if (!strcmp(class_name,"NSBundle"))
69 {
70 uint64_t offset = 5 * ptr_size;
Greg Clayton99558cc42015-08-24 23:46:31 +000071 ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset, valobj.GetCompilerType().GetBasicTypeFromAST(lldb::eBasicTypeObjCID), true));
Enrico Granata675f49b2015-10-07 18:36:53 +000072
Enrico Granata92373532013-03-19 22:58:48 +000073 StreamString summary_stream;
Enrico Granataf35bc632014-11-06 21:55:30 +000074 bool was_nsstring_ok = NSStringSummaryProvider(*text.get(), summary_stream, options);
Enrico Granata92373532013-03-19 22:58:48 +000075 if (was_nsstring_ok && summary_stream.GetSize() > 0)
76 {
77 stream.Printf("%s",summary_stream.GetData());
78 return true;
79 }
80 }
81 // this is either an unknown subclass or an NSBundle that comes from [NSBundle mainBundle]
82 // which is encoded differently and needs to be handled by running code
Enrico Granata31fda932015-10-07 01:41:23 +000083 return ExtractSummaryFromObjCExpression(valobj, "NSString*", "bundlePath", stream, options.GetLanguage());
Enrico Granata92373532013-03-19 22:58:48 +000084}
85
86bool
Enrico Granataf35bc632014-11-06 21:55:30 +000087lldb_private::formatters::NSTimeZoneSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
Enrico Granata92373532013-03-19 22:58:48 +000088{
89 ProcessSP process_sp = valobj.GetProcessSP();
90 if (!process_sp)
91 return false;
92
93 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
94
95 if (!runtime)
96 return false;
97
98 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
99
100 if (!descriptor.get() || !descriptor->IsValid())
101 return false;
102
103 uint32_t ptr_size = process_sp->GetAddressByteSize();
104
105 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
106
107 if (!valobj_addr)
108 return false;
109
110 const char* class_name = descriptor->GetClassName().GetCString();
111
112 if (!class_name || !*class_name)
113 return false;
114
115 if (!strcmp(class_name,"__NSTimeZone"))
116 {
117 uint64_t offset = ptr_size;
Greg Clayton99558cc42015-08-24 23:46:31 +0000118 ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset, valobj.GetCompilerType(), true));
Enrico Granata92373532013-03-19 22:58:48 +0000119 StreamString summary_stream;
Enrico Granataf35bc632014-11-06 21:55:30 +0000120 bool was_nsstring_ok = NSStringSummaryProvider(*text.get(), summary_stream, options);
Enrico Granata92373532013-03-19 22:58:48 +0000121 if (was_nsstring_ok && summary_stream.GetSize() > 0)
122 {
123 stream.Printf("%s",summary_stream.GetData());
124 return true;
125 }
126 }
Enrico Granata31fda932015-10-07 01:41:23 +0000127 return ExtractSummaryFromObjCExpression(valobj, "NSString*", "name", stream, options.GetLanguage());
Enrico Granata92373532013-03-19 22:58:48 +0000128}
129
130bool
Enrico Granataf35bc632014-11-06 21:55:30 +0000131lldb_private::formatters::NSNotificationSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
Enrico Granata92373532013-03-19 22:58:48 +0000132{
133 ProcessSP process_sp = valobj.GetProcessSP();
134 if (!process_sp)
135 return false;
136
137 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
138
139 if (!runtime)
140 return false;
141
142 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
143
144 if (!descriptor.get() || !descriptor->IsValid())
145 return false;
146
147 uint32_t ptr_size = process_sp->GetAddressByteSize();
148
149 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
150
151 if (!valobj_addr)
152 return false;
153
154 const char* class_name = descriptor->GetClassName().GetCString();
155
156 if (!class_name || !*class_name)
157 return false;
158
159 if (!strcmp(class_name,"NSConcreteNotification"))
160 {
161 uint64_t offset = ptr_size;
Greg Clayton99558cc42015-08-24 23:46:31 +0000162 ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset, valobj.GetCompilerType(), true));
Enrico Granata92373532013-03-19 22:58:48 +0000163 StreamString summary_stream;
Enrico Granataf35bc632014-11-06 21:55:30 +0000164 bool was_nsstring_ok = NSStringSummaryProvider(*text.get(), summary_stream, options);
Enrico Granata92373532013-03-19 22:58:48 +0000165 if (was_nsstring_ok && summary_stream.GetSize() > 0)
166 {
167 stream.Printf("%s",summary_stream.GetData());
168 return true;
169 }
170 }
171 // this is either an unknown subclass or an NSBundle that comes from [NSBundle mainBundle]
172 // which is encoded differently and needs to be handled by running code
Enrico Granata31fda932015-10-07 01:41:23 +0000173 return ExtractSummaryFromObjCExpression(valobj, "NSString*", "name", stream, options.GetLanguage());
Enrico Granata92373532013-03-19 22:58:48 +0000174}
175
176bool
Enrico Granataf35bc632014-11-06 21:55:30 +0000177lldb_private::formatters::NSMachPortSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
Enrico Granata92373532013-03-19 22:58:48 +0000178{
179 ProcessSP process_sp = valobj.GetProcessSP();
180 if (!process_sp)
181 return false;
182
183 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
184
185 if (!runtime)
186 return false;
187
188 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
189
190 if (!descriptor.get() || !descriptor->IsValid())
191 return false;
192
193 uint32_t ptr_size = process_sp->GetAddressByteSize();
194
195 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
196
197 if (!valobj_addr)
198 return false;
199
200 const char* class_name = descriptor->GetClassName().GetCString();
201
202 if (!class_name || !*class_name)
203 return false;
204
205 uint64_t port_number = 0;
206
207 do
208 {
209 if (!strcmp(class_name,"NSMachPort"))
210 {
211 uint64_t offset = (ptr_size == 4 ? 12 : 20);
212 Error error;
213 port_number = process_sp->ReadUnsignedIntegerFromMemory(offset+valobj_addr, 4, 0, error);
214 if (error.Success())
215 break;
216 }
217 if (!ExtractValueFromObjCExpression(valobj, "int", "machPort", port_number))
218 return false;
219 } while (false);
220
221 stream.Printf("mach port: %u",(uint32_t)(port_number & 0x00000000FFFFFFFF));
222 return true;
223}
224
225bool
Enrico Granataf35bc632014-11-06 21:55:30 +0000226lldb_private::formatters::NSIndexSetSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
Enrico Granata92373532013-03-19 22:58:48 +0000227{
228 ProcessSP process_sp = valobj.GetProcessSP();
229 if (!process_sp)
230 return false;
231
232 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
233
234 if (!runtime)
235 return false;
236
237 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
238
239 if (!descriptor.get() || !descriptor->IsValid())
240 return false;
241
242 uint32_t ptr_size = process_sp->GetAddressByteSize();
243
244 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
245
246 if (!valobj_addr)
247 return false;
248
249 const char* class_name = descriptor->GetClassName().GetCString();
250
251 if (!class_name || !*class_name)
252 return false;
253
254 uint64_t count = 0;
255
256 do {
257 if (!strcmp(class_name,"NSIndexSet") || !strcmp(class_name,"NSMutableIndexSet"))
258 {
259 Error error;
260 uint32_t mode = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+ptr_size, 4, 0, error);
261 if (error.Fail())
262 return false;
263 // this means the set is empty - count = 0
264 if ((mode & 1) == 1)
265 {
266 count = 0;
267 break;
268 }
269 if ((mode & 2) == 2)
270 mode = 1; // this means the set only has one range
271 else
272 mode = 2; // this means the set has multiple ranges
273 if (mode == 1)
274 {
275 count = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+3*ptr_size, ptr_size, 0, error);
276 if (error.Fail())
277 return false;
278 }
279 else
280 {
281 // read a pointer to the data at 2*ptr_size
282 count = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+2*ptr_size, ptr_size, 0, error);
283 if (error.Fail())
284 return false;
285 // read the data at 2*ptr_size from the first location
286 count = process_sp->ReadUnsignedIntegerFromMemory(count+2*ptr_size, ptr_size, 0, error);
287 if (error.Fail())
288 return false;
289 }
290 }
291 else
292 {
293 if (!ExtractValueFromObjCExpression(valobj, "unsigned long long int", "count", count))
294 return false;
295 }
296 } while (false);
Matt Kopecef143712013-06-03 18:00:07 +0000297 stream.Printf("%" PRIu64 " index%s",
Enrico Granata92373532013-03-19 22:58:48 +0000298 count,
299 (count == 1 ? "" : "es"));
300 return true;
301}
302
Enrico Granata675f49b2015-10-07 18:36:53 +0000303static void
304NSNumber_FormatChar (ValueObject& valobj,
305 Stream& stream,
306 char value,
307 lldb::LanguageType lang)
308{
309 static ConstString g_TypeHint("NSNumber:char");
310
311 std::string prefix,suffix;
312 if (Language* language = Language::FindPlugin(lang))
313 {
314 if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix, suffix))
315 {
316 prefix.clear();
317 suffix.clear();
318 }
319 }
320
321 stream.Printf("%s%hhd%s",
322 prefix.c_str(),
323 value,
324 suffix.c_str());
325}
Eugene Zelenko8d15f332015-10-20 01:10:59 +0000326
Enrico Granata675f49b2015-10-07 18:36:53 +0000327static void
328NSNumber_FormatShort (ValueObject& valobj,
329 Stream& stream,
330 short value,
331 lldb::LanguageType lang)
332{
333 static ConstString g_TypeHint("NSNumber:short");
334
335 std::string prefix,suffix;
336 if (Language* language = Language::FindPlugin(lang))
337 {
338 if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix, suffix))
339 {
340 prefix.clear();
341 suffix.clear();
342 }
343 }
344
345 stream.Printf("%s%hd%s",
346 prefix.c_str(),
347 value,
348 suffix.c_str());
349}
Eugene Zelenko8d15f332015-10-20 01:10:59 +0000350
Enrico Granata675f49b2015-10-07 18:36:53 +0000351static void
352NSNumber_FormatInt (ValueObject& valobj,
353 Stream& stream,
354 int value,
355 lldb::LanguageType lang)
356{
357 static ConstString g_TypeHint("NSNumber:int");
358
359 std::string prefix,suffix;
360 if (Language* language = Language::FindPlugin(lang))
361 {
362 if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix, suffix))
363 {
364 prefix.clear();
365 suffix.clear();
366 }
367 }
368
369 stream.Printf("%s%d%s",
370 prefix.c_str(),
371 value,
372 suffix.c_str());
373}
Eugene Zelenko8d15f332015-10-20 01:10:59 +0000374
Enrico Granata675f49b2015-10-07 18:36:53 +0000375static void
376NSNumber_FormatLong (ValueObject& valobj,
377 Stream& stream,
378 uint64_t value,
379 lldb::LanguageType lang)
380{
381 static ConstString g_TypeHint("NSNumber:long");
382
383 std::string prefix,suffix;
384 if (Language* language = Language::FindPlugin(lang))
385 {
386 if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix, suffix))
387 {
388 prefix.clear();
389 suffix.clear();
390 }
391 }
392
393 stream.Printf("%s%" PRId64 "%s",
394 prefix.c_str(),
395 value,
396 suffix.c_str());
397}
Eugene Zelenko8d15f332015-10-20 01:10:59 +0000398
Enrico Granata675f49b2015-10-07 18:36:53 +0000399static void
400NSNumber_FormatFloat (ValueObject& valobj,
401 Stream& stream,
402 float value,
403 lldb::LanguageType lang)
404{
405 static ConstString g_TypeHint("NSNumber:float");
406
407 std::string prefix,suffix;
408 if (Language* language = Language::FindPlugin(lang))
409 {
410 if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix, suffix))
411 {
412 prefix.clear();
413 suffix.clear();
414 }
415 }
416
417 stream.Printf("%s%f%s",
418 prefix.c_str(),
419 value,
420 suffix.c_str());
421}
Eugene Zelenko8d15f332015-10-20 01:10:59 +0000422
Enrico Granata675f49b2015-10-07 18:36:53 +0000423static void
424NSNumber_FormatDouble (ValueObject& valobj,
425 Stream& stream,
426 double value,
427 lldb::LanguageType lang)
428{
429 static ConstString g_TypeHint("NSNumber:double");
430
431 std::string prefix,suffix;
432 if (Language* language = Language::FindPlugin(lang))
433 {
434 if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix, suffix))
435 {
436 prefix.clear();
437 suffix.clear();
438 }
439 }
440
441 stream.Printf("%s%g%s",
442 prefix.c_str(),
443 value,
444 suffix.c_str());
445}
446
Enrico Granata92373532013-03-19 22:58:48 +0000447bool
Enrico Granataf35bc632014-11-06 21:55:30 +0000448lldb_private::formatters::NSNumberSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
Enrico Granata92373532013-03-19 22:58:48 +0000449{
450 ProcessSP process_sp = valobj.GetProcessSP();
451 if (!process_sp)
452 return false;
453
454 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
455
456 if (!runtime)
457 return false;
458
459 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
460
461 if (!descriptor.get() || !descriptor->IsValid())
462 return false;
463
464 uint32_t ptr_size = process_sp->GetAddressByteSize();
465
466 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
467
468 if (!valobj_addr)
469 return false;
470
471 const char* class_name = descriptor->GetClassName().GetCString();
472
473 if (!class_name || !*class_name)
474 return false;
475
476 if (!strcmp(class_name,"NSNumber") || !strcmp(class_name,"__NSCFNumber"))
477 {
Enrico Granataf15ee4e2013-04-05 18:49:06 +0000478 uint64_t value = 0;
479 uint64_t i_bits = 0;
480 if (descriptor->GetTaggedPointerInfo(&i_bits,&value))
Enrico Granata92373532013-03-19 22:58:48 +0000481 {
Enrico Granata92373532013-03-19 22:58:48 +0000482 switch (i_bits)
483 {
484 case 0:
Enrico Granata675f49b2015-10-07 18:36:53 +0000485 NSNumber_FormatChar(valobj, stream, (char)value, options.GetLanguage());
Enrico Granata92373532013-03-19 22:58:48 +0000486 break;
Enrico Granatab636be72013-04-24 17:49:08 +0000487 case 1:
Enrico Granata92373532013-03-19 22:58:48 +0000488 case 4:
Enrico Granata675f49b2015-10-07 18:36:53 +0000489 NSNumber_FormatShort(valobj, stream, (short)value, options.GetLanguage());
Enrico Granata92373532013-03-19 22:58:48 +0000490 break;
Enrico Granatab636be72013-04-24 17:49:08 +0000491 case 2:
Enrico Granata92373532013-03-19 22:58:48 +0000492 case 8:
Enrico Granata675f49b2015-10-07 18:36:53 +0000493 NSNumber_FormatInt(valobj, stream, (int)value, options.GetLanguage());
Enrico Granata92373532013-03-19 22:58:48 +0000494 break;
Enrico Granatab636be72013-04-24 17:49:08 +0000495 case 3:
Enrico Granata92373532013-03-19 22:58:48 +0000496 case 12:
Enrico Granata675f49b2015-10-07 18:36:53 +0000497 NSNumber_FormatLong(valobj, stream, value, options.GetLanguage());
Enrico Granata92373532013-03-19 22:58:48 +0000498 break;
499 default:
Enrico Granatabd4885f2014-04-10 18:17:30 +0000500 return false;
Enrico Granata92373532013-03-19 22:58:48 +0000501 }
502 return true;
503 }
504 else
505 {
506 Error error;
507 uint8_t data_type = (process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, 1, 0, error) & 0x1F);
508 uint64_t data_location = valobj_addr + 2*ptr_size;
509 uint64_t value = 0;
510 if (error.Fail())
511 return false;
512 switch (data_type)
513 {
514 case 1: // 0B00001
515 value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 1, 0, error);
516 if (error.Fail())
517 return false;
Enrico Granata675f49b2015-10-07 18:36:53 +0000518 NSNumber_FormatChar(valobj, stream, (char)value, options.GetLanguage());
Enrico Granata92373532013-03-19 22:58:48 +0000519 break;
520 case 2: // 0B0010
521 value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 2, 0, error);
522 if (error.Fail())
523 return false;
Enrico Granata675f49b2015-10-07 18:36:53 +0000524 NSNumber_FormatShort(valobj, stream, (short)value, options.GetLanguage());
Enrico Granata92373532013-03-19 22:58:48 +0000525 break;
526 case 3: // 0B0011
527 value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 4, 0, error);
528 if (error.Fail())
529 return false;
Enrico Granata675f49b2015-10-07 18:36:53 +0000530 NSNumber_FormatInt(valobj, stream, (int)value, options.GetLanguage());
Enrico Granata92373532013-03-19 22:58:48 +0000531 break;
532 case 17: // 0B10001
533 data_location += 8;
534 case 4: // 0B0100
535 value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 8, 0, error);
536 if (error.Fail())
537 return false;
Enrico Granata675f49b2015-10-07 18:36:53 +0000538 NSNumber_FormatLong(valobj, stream, value, options.GetLanguage());
Enrico Granata92373532013-03-19 22:58:48 +0000539 break;
540 case 5: // 0B0101
541 {
542 uint32_t flt_as_int = process_sp->ReadUnsignedIntegerFromMemory(data_location, 4, 0, error);
543 if (error.Fail())
544 return false;
545 float flt_value = *((float*)&flt_as_int);
Enrico Granata675f49b2015-10-07 18:36:53 +0000546 NSNumber_FormatFloat(valobj, stream, flt_value, options.GetLanguage());
Enrico Granata92373532013-03-19 22:58:48 +0000547 break;
548 }
549 case 6: // 0B0110
550 {
551 uint64_t dbl_as_lng = process_sp->ReadUnsignedIntegerFromMemory(data_location, 8, 0, error);
552 if (error.Fail())
553 return false;
554 double dbl_value = *((double*)&dbl_as_lng);
Enrico Granata675f49b2015-10-07 18:36:53 +0000555 NSNumber_FormatDouble(valobj, stream, dbl_value, options.GetLanguage());
Enrico Granata92373532013-03-19 22:58:48 +0000556 break;
557 }
558 default:
Enrico Granatabd4885f2014-04-10 18:17:30 +0000559 return false;
Enrico Granata92373532013-03-19 22:58:48 +0000560 }
561 return true;
562 }
563 }
564 else
565 {
Enrico Granata31fda932015-10-07 01:41:23 +0000566 return ExtractSummaryFromObjCExpression(valobj, "NSString*", "stringValue", stream, options.GetLanguage());
Enrico Granata92373532013-03-19 22:58:48 +0000567 }
568}
569
570bool
Enrico Granataf35bc632014-11-06 21:55:30 +0000571lldb_private::formatters::NSURLSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
Enrico Granata92373532013-03-19 22:58:48 +0000572{
573 ProcessSP process_sp = valobj.GetProcessSP();
574 if (!process_sp)
575 return false;
576
577 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
578
579 if (!runtime)
580 return false;
581
582 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
583
584 if (!descriptor.get() || !descriptor->IsValid())
585 return false;
586
587 uint32_t ptr_size = process_sp->GetAddressByteSize();
588
589 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
590
591 if (!valobj_addr)
592 return false;
593
594 const char* class_name = descriptor->GetClassName().GetCString();
595
596 if (!class_name || !*class_name)
597 return false;
598
599 if (strcmp(class_name, "NSURL") == 0)
600 {
601 uint64_t offset_text = ptr_size + ptr_size + 8; // ISA + pointer + 8 bytes of data (even on 32bit)
602 uint64_t offset_base = offset_text + ptr_size;
Greg Clayton99558cc42015-08-24 23:46:31 +0000603 CompilerType type(valobj.GetCompilerType());
Enrico Granata92373532013-03-19 22:58:48 +0000604 ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset_text, type, true));
605 ValueObjectSP base(valobj.GetSyntheticChildAtOffset(offset_base, type, true));
606 if (!text)
607 return false;
608 if (text->GetValueAsUnsigned(0) == 0)
609 return false;
610 StreamString summary;
Enrico Granataf35bc632014-11-06 21:55:30 +0000611 if (!NSStringSummaryProvider(*text, summary, options))
Enrico Granata92373532013-03-19 22:58:48 +0000612 return false;
613 if (base && base->GetValueAsUnsigned(0))
614 {
615 if (summary.GetSize() > 0)
616 summary.GetString().resize(summary.GetSize()-1);
617 summary.Printf(" -- ");
618 StreamString base_summary;
Enrico Granataf35bc632014-11-06 21:55:30 +0000619 if (NSURLSummaryProvider(*base, base_summary, options) && base_summary.GetSize() > 0)
Enrico Granata92373532013-03-19 22:58:48 +0000620 summary.Printf("%s",base_summary.GetSize() > 2 ? base_summary.GetData() + 2 : base_summary.GetData());
621 }
622 if (summary.GetSize())
623 {
624 stream.Printf("%s",summary.GetData());
625 return true;
626 }
627 }
628 else
629 {
Enrico Granata31fda932015-10-07 01:41:23 +0000630 return ExtractSummaryFromObjCExpression(valobj, "NSString*", "description", stream, options.GetLanguage());
Enrico Granata92373532013-03-19 22:58:48 +0000631 }
632 return false;
633}
634
635bool
Enrico Granataf35bc632014-11-06 21:55:30 +0000636lldb_private::formatters::NSDateSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
Enrico Granata92373532013-03-19 22:58:48 +0000637{
638 ProcessSP process_sp = valobj.GetProcessSP();
639 if (!process_sp)
640 return false;
641
642 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
643
644 if (!runtime)
645 return false;
646
647 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
648
649 if (!descriptor.get() || !descriptor->IsValid())
650 return false;
651
652 uint32_t ptr_size = process_sp->GetAddressByteSize();
653
654 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
655
656 if (!valobj_addr)
657 return false;
658
659 uint64_t date_value_bits = 0;
660 double date_value = 0.0;
661
662 const char* class_name = descriptor->GetClassName().GetCString();
663
664 if (!class_name || !*class_name)
665 return false;
666
667 if (strcmp(class_name,"NSDate") == 0 ||
668 strcmp(class_name,"__NSDate") == 0 ||
669 strcmp(class_name,"__NSTaggedDate") == 0)
670 {
Enrico Granataf15ee4e2013-04-05 18:49:06 +0000671 uint64_t info_bits=0,value_bits = 0;
672 if (descriptor->GetTaggedPointerInfo(&info_bits,&value_bits))
Enrico Granata92373532013-03-19 22:58:48 +0000673 {
Enrico Granata92373532013-03-19 22:58:48 +0000674 date_value_bits = ((value_bits << 8) | (info_bits << 4));
675 date_value = *((double*)&date_value_bits);
676 }
677 else
678 {
679 Error error;
680 date_value_bits = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+ptr_size, 8, 0, error);
681 date_value = *((double*)&date_value_bits);
682 if (error.Fail())
683 return false;
684 }
685 }
686 else if (!strcmp(class_name,"NSCalendarDate"))
687 {
688 Error error;
689 date_value_bits = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+2*ptr_size, 8, 0, error);
690 date_value = *((double*)&date_value_bits);
691 if (error.Fail())
692 return false;
693 }
694 else
695 {
696 if (ExtractValueFromObjCExpression(valobj, "NSTimeInterval", "ExtractValueFromObjCExpression", date_value_bits) == false)
697 return false;
698 date_value = *((double*)&date_value_bits);
699 }
700 if (date_value == -63114076800)
701 {
702 stream.Printf("0001-12-30 00:00:00 +0000");
703 return true;
704 }
705 // this snippet of code assumes that time_t == seconds since Jan-1-1970
706 // this is generally true and POSIXly happy, but might break if a library
707 // vendor decides to get creative
708 time_t epoch = GetOSXEpoch();
709 epoch = epoch + (time_t)date_value;
Enrico Granatadb2ecad2014-10-15 20:18:58 +0000710 tm *tm_date = gmtime(&epoch);
Enrico Granata92373532013-03-19 22:58:48 +0000711 if (!tm_date)
712 return false;
713 std::string buffer(1024,0);
714 if (strftime (&buffer[0], 1023, "%Z", tm_date) == 0)
715 return false;
716 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());
717 return true;
718}
Enrico Granatad87cc312015-09-03 01:29:42 +0000719
720bool
721lldb_private::formatters::ObjCClassSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
722{
723 ProcessSP process_sp = valobj.GetProcessSP();
724 if (!process_sp)
725 return false;
726
727 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
728
729 if (!runtime)
730 return false;
731
732 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptorFromISA(valobj.GetValueAsUnsigned(0)));
733
734 if (!descriptor.get() || !descriptor->IsValid())
735 return false;
736
Enrico Granata7de855c2015-10-02 20:59:58 +0000737 ConstString class_name = descriptor->GetClassName();
Enrico Granatad87cc312015-09-03 01:29:42 +0000738
Enrico Granata7de855c2015-10-02 20:59:58 +0000739 if (class_name.IsEmpty())
Enrico Granatad87cc312015-09-03 01:29:42 +0000740 return false;
741
Enrico Granata7de855c2015-10-02 20:59:58 +0000742 if (ConstString cs = Mangled(class_name).GetDemangledName(lldb::eLanguageTypeUnknown))
743 class_name = cs;
744
745 stream.Printf("%s",class_name.AsCString("<unknown class>"));
Enrico Granatad87cc312015-09-03 01:29:42 +0000746 return true;
747}
748
749class ObjCClassSyntheticChildrenFrontEnd : public SyntheticChildrenFrontEnd
750{
751public:
752 ObjCClassSyntheticChildrenFrontEnd (lldb::ValueObjectSP valobj_sp) :
753 SyntheticChildrenFrontEnd(*valobj_sp.get())
754 {
755 }
756
Eugene Zelenko8d15f332015-10-20 01:10:59 +0000757 ~ObjCClassSyntheticChildrenFrontEnd() override = default;
758
759 size_t
760 CalculateNumChildren() override
Enrico Granatad87cc312015-09-03 01:29:42 +0000761 {
762 return 0;
763 }
764
Eugene Zelenko8d15f332015-10-20 01:10:59 +0000765 lldb::ValueObjectSP
766 GetChildAtIndex(size_t idx) override
Enrico Granatad87cc312015-09-03 01:29:42 +0000767 {
768 return lldb::ValueObjectSP();
769 }
770
Eugene Zelenko8d15f332015-10-20 01:10:59 +0000771 bool
772 Update() override
Enrico Granatad87cc312015-09-03 01:29:42 +0000773 {
774 return false;
775 }
776
Eugene Zelenko8d15f332015-10-20 01:10:59 +0000777 bool
778 MightHaveChildren() override
Enrico Granatad87cc312015-09-03 01:29:42 +0000779 {
780 return false;
781 }
782
Eugene Zelenko8d15f332015-10-20 01:10:59 +0000783 size_t
784 GetIndexOfChildWithName(const ConstString &name) override
Enrico Granatad87cc312015-09-03 01:29:42 +0000785 {
786 return UINT32_MAX;
787 }
Enrico Granatad87cc312015-09-03 01:29:42 +0000788};
789
790SyntheticChildrenFrontEnd*
791lldb_private::formatters::ObjCClassSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
792{
793 return new ObjCClassSyntheticChildrenFrontEnd(valobj_sp);
794}
795
796template<bool needs_at>
797bool
798lldb_private::formatters::NSDataSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
799{
800 ProcessSP process_sp = valobj.GetProcessSP();
801 if (!process_sp)
802 return false;
803
804 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
805
806 if (!runtime)
807 return false;
808
809 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
810
811 if (!descriptor.get() || !descriptor->IsValid())
812 return false;
813
814 bool is_64bit = (process_sp->GetAddressByteSize() == 8);
815 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
816
817 if (!valobj_addr)
818 return false;
819
820 uint64_t value = 0;
821
822 const char* class_name = descriptor->GetClassName().GetCString();
823
824 if (!class_name || !*class_name)
825 return false;
826
827 if (!strcmp(class_name,"NSConcreteData") ||
828 !strcmp(class_name,"NSConcreteMutableData") ||
829 !strcmp(class_name,"__NSCFData"))
830 {
831 uint32_t offset = (is_64bit ? 16 : 8);
832 Error error;
833 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + offset, is_64bit ? 8 : 4, 0, error);
834 if (error.Fail())
835 return false;
836 }
837 else
838 {
839 if (!ExtractValueFromObjCExpression(valobj, "int", "length", value))
840 return false;
841 }
842
843 stream.Printf("%s%" PRIu64 " byte%s%s",
844 (needs_at ? "@\"" : ""),
845 value,
846 (value != 1 ? "s" : ""),
847 (needs_at ? "\"" : ""));
848
849 return true;
850}
851
852bool
Enrico Granatad87cc312015-09-03 01:29:42 +0000853lldb_private::formatters::ObjCBOOLSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
854{
855 const uint32_t type_info = valobj.GetCompilerType().GetTypeInfo();
856
857 ValueObjectSP real_guy_sp = valobj.GetSP();
858
859 if (type_info & eTypeIsPointer)
860 {
861 Error err;
862 real_guy_sp = valobj.Dereference(err);
863 if (err.Fail() || !real_guy_sp)
864 return false;
865 }
866 else if (type_info & eTypeIsReference)
867 {
868 real_guy_sp = valobj.GetChildAtIndex(0, true);
869 if (!real_guy_sp)
870 return false;
871 }
872 uint64_t value = real_guy_sp->GetValueAsUnsigned(0);
873 if (value == 0)
874 {
875 stream.Printf("NO");
876 return true;
877 }
878 stream.Printf("YES");
879 return true;
880}
881
882template <bool is_sel_ptr>
883bool
884lldb_private::formatters::ObjCSELSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
885{
886 lldb::ValueObjectSP valobj_sp;
887
888 CompilerType charstar (valobj.GetCompilerType().GetBasicTypeFromAST(eBasicTypeChar).GetPointerType());
889
890 if (!charstar)
891 return false;
892
893 ExecutionContext exe_ctx(valobj.GetExecutionContextRef());
894
895 if (is_sel_ptr)
896 {
897 lldb::addr_t data_address = valobj.GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
898 if (data_address == LLDB_INVALID_ADDRESS)
899 return false;
900 valobj_sp = ValueObject::CreateValueObjectFromAddress("text", data_address, exe_ctx, charstar);
901 }
902 else
903 {
904 DataExtractor data;
905 Error error;
906 valobj.GetData(data, error);
907 if (error.Fail())
908 return false;
909 valobj_sp = ValueObject::CreateValueObjectFromData("text", data, exe_ctx, charstar);
910 }
911
912 if (!valobj_sp)
913 return false;
914
915 stream.Printf("%s",valobj_sp->GetSummaryAsCString());
916 return true;
917}
918
919// POSIX has an epoch on Jan-1-1970, but Cocoa prefers Jan-1-2001
920// this call gives the POSIX equivalent of the Cocoa epoch
921time_t
922lldb_private::formatters::GetOSXEpoch ()
923{
924 static time_t epoch = 0;
925 if (!epoch)
926 {
927#ifndef _WIN32
928 tzset();
929 tm tm_epoch;
930 tm_epoch.tm_sec = 0;
931 tm_epoch.tm_hour = 0;
932 tm_epoch.tm_min = 0;
933 tm_epoch.tm_mon = 0;
934 tm_epoch.tm_mday = 1;
935 tm_epoch.tm_year = 2001-1900; // for some reason, we need to subtract 1900 from this field. not sure why.
936 tm_epoch.tm_isdst = -1;
937 tm_epoch.tm_gmtoff = 0;
938 tm_epoch.tm_zone = NULL;
939 epoch = timegm(&tm_epoch);
940#endif
941 }
942 return epoch;
943}
944
Enrico Granata419d7912015-09-04 00:33:51 +0000945bool
946lldb_private::formatters::RuntimeSpecificDescriptionSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
947{
948 stream.Printf("%s",valobj.GetObjectDescription());
949 return true;
950}
951
Enrico Granatad87cc312015-09-03 01:29:42 +0000952template bool
Eugene Zelenko8d15f332015-10-20 01:10:59 +0000953lldb_private::formatters::NSDataSummaryProvider<true> (ValueObject&, Stream&, const TypeSummaryOptions&);
Enrico Granatad87cc312015-09-03 01:29:42 +0000954
955template bool
Eugene Zelenko8d15f332015-10-20 01:10:59 +0000956lldb_private::formatters::NSDataSummaryProvider<false> (ValueObject&, Stream&, const TypeSummaryOptions&);
Enrico Granatad87cc312015-09-03 01:29:42 +0000957
958template bool
Eugene Zelenko8d15f332015-10-20 01:10:59 +0000959lldb_private::formatters::ObjCSELSummaryProvider<true> (ValueObject&, Stream&, const TypeSummaryOptions&);
Enrico Granatad87cc312015-09-03 01:29:42 +0000960
961template bool
Eugene Zelenko8d15f332015-10-20 01:10:59 +0000962lldb_private::formatters::ObjCSELSummaryProvider<false> (ValueObject&, Stream&, const TypeSummaryOptions&);