blob: d89c3e354699571bc36aa6b03d5d52cdbac7b8d2 [file] [log] [blame]
Enrico Granata92373532013-03-19 22:58:48 +00001//===-- Cocoa.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 Granata419d7912015-09-04 00:33:51 +000010#include "lldb/DataFormatters/Cocoa.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"
18#include "lldb/DataFormatters/StringPrinter.h"
19#include "lldb/DataFormatters/TypeSummary.h"
Enrico Granata92373532013-03-19 22:58:48 +000020#include "lldb/Host/Endian.h"
21#include "lldb/Symbol/ClangASTContext.h"
22#include "lldb/Target/ObjCLanguageRuntime.h"
23#include "lldb/Target/Target.h"
Enrico Granata419d7912015-09-04 00:33:51 +000024#include "lldb/Target/Process.h"
Enrico Granatad87cc312015-09-03 01:29:42 +000025#include "lldb/Utility/ProcessStructReader.h"
26
Enrico Granata92373532013-03-19 22:58:48 +000027using namespace lldb;
28using namespace lldb_private;
29using namespace lldb_private::formatters;
30
31bool
Enrico Granataf35bc632014-11-06 21:55:30 +000032lldb_private::formatters::NSBundleSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
Enrico Granata92373532013-03-19 22:58:48 +000033{
34 ProcessSP process_sp = valobj.GetProcessSP();
35 if (!process_sp)
36 return false;
37
38 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
39
40 if (!runtime)
41 return false;
42
43 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
44
45 if (!descriptor.get() || !descriptor->IsValid())
46 return false;
47
48 uint32_t ptr_size = process_sp->GetAddressByteSize();
49
50 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
51
52 if (!valobj_addr)
53 return false;
54
55 const char* class_name = descriptor->GetClassName().GetCString();
56
57 if (!class_name || !*class_name)
58 return false;
59
60 if (!strcmp(class_name,"NSBundle"))
61 {
62 uint64_t offset = 5 * ptr_size;
Greg Clayton99558cc42015-08-24 23:46:31 +000063 ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset, valobj.GetCompilerType().GetBasicTypeFromAST(lldb::eBasicTypeObjCID), true));
Jim Ingham5c42d8a2013-05-15 18:27:08 +000064
Enrico Granata92373532013-03-19 22:58:48 +000065 StreamString summary_stream;
Enrico Granataf35bc632014-11-06 21:55:30 +000066 bool was_nsstring_ok = NSStringSummaryProvider(*text.get(), summary_stream, options);
Enrico Granata92373532013-03-19 22:58:48 +000067 if (was_nsstring_ok && summary_stream.GetSize() > 0)
68 {
69 stream.Printf("%s",summary_stream.GetData());
70 return true;
71 }
72 }
73 // this is either an unknown subclass or an NSBundle that comes from [NSBundle mainBundle]
74 // which is encoded differently and needs to be handled by running code
75 return ExtractSummaryFromObjCExpression(valobj, "NSString*", "bundlePath", stream);
76}
77
78bool
Enrico Granataf35bc632014-11-06 21:55:30 +000079lldb_private::formatters::NSTimeZoneSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
Enrico Granata92373532013-03-19 22:58:48 +000080{
81 ProcessSP process_sp = valobj.GetProcessSP();
82 if (!process_sp)
83 return false;
84
85 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
86
87 if (!runtime)
88 return false;
89
90 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
91
92 if (!descriptor.get() || !descriptor->IsValid())
93 return false;
94
95 uint32_t ptr_size = process_sp->GetAddressByteSize();
96
97 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
98
99 if (!valobj_addr)
100 return false;
101
102 const char* class_name = descriptor->GetClassName().GetCString();
103
104 if (!class_name || !*class_name)
105 return false;
106
107 if (!strcmp(class_name,"__NSTimeZone"))
108 {
109 uint64_t offset = ptr_size;
Greg Clayton99558cc42015-08-24 23:46:31 +0000110 ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset, valobj.GetCompilerType(), true));
Enrico Granata92373532013-03-19 22:58:48 +0000111 StreamString summary_stream;
Enrico Granataf35bc632014-11-06 21:55:30 +0000112 bool was_nsstring_ok = NSStringSummaryProvider(*text.get(), summary_stream, options);
Enrico Granata92373532013-03-19 22:58:48 +0000113 if (was_nsstring_ok && summary_stream.GetSize() > 0)
114 {
115 stream.Printf("%s",summary_stream.GetData());
116 return true;
117 }
118 }
119 return ExtractSummaryFromObjCExpression(valobj, "NSString*", "name", stream);
120}
121
122bool
Enrico Granataf35bc632014-11-06 21:55:30 +0000123lldb_private::formatters::NSNotificationSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
Enrico Granata92373532013-03-19 22:58:48 +0000124{
125 ProcessSP process_sp = valobj.GetProcessSP();
126 if (!process_sp)
127 return false;
128
129 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
130
131 if (!runtime)
132 return false;
133
134 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
135
136 if (!descriptor.get() || !descriptor->IsValid())
137 return false;
138
139 uint32_t ptr_size = process_sp->GetAddressByteSize();
140
141 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
142
143 if (!valobj_addr)
144 return false;
145
146 const char* class_name = descriptor->GetClassName().GetCString();
147
148 if (!class_name || !*class_name)
149 return false;
150
151 if (!strcmp(class_name,"NSConcreteNotification"))
152 {
153 uint64_t offset = ptr_size;
Greg Clayton99558cc42015-08-24 23:46:31 +0000154 ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset, valobj.GetCompilerType(), true));
Enrico Granata92373532013-03-19 22:58:48 +0000155 StreamString summary_stream;
Enrico Granataf35bc632014-11-06 21:55:30 +0000156 bool was_nsstring_ok = NSStringSummaryProvider(*text.get(), summary_stream, options);
Enrico Granata92373532013-03-19 22:58:48 +0000157 if (was_nsstring_ok && summary_stream.GetSize() > 0)
158 {
159 stream.Printf("%s",summary_stream.GetData());
160 return true;
161 }
162 }
163 // this is either an unknown subclass or an NSBundle that comes from [NSBundle mainBundle]
164 // which is encoded differently and needs to be handled by running code
165 return ExtractSummaryFromObjCExpression(valobj, "NSString*", "name", stream);
166}
167
168bool
Enrico Granataf35bc632014-11-06 21:55:30 +0000169lldb_private::formatters::NSMachPortSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
Enrico Granata92373532013-03-19 22:58:48 +0000170{
171 ProcessSP process_sp = valobj.GetProcessSP();
172 if (!process_sp)
173 return false;
174
175 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
176
177 if (!runtime)
178 return false;
179
180 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
181
182 if (!descriptor.get() || !descriptor->IsValid())
183 return false;
184
185 uint32_t ptr_size = process_sp->GetAddressByteSize();
186
187 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
188
189 if (!valobj_addr)
190 return false;
191
192 const char* class_name = descriptor->GetClassName().GetCString();
193
194 if (!class_name || !*class_name)
195 return false;
196
197 uint64_t port_number = 0;
198
199 do
200 {
201 if (!strcmp(class_name,"NSMachPort"))
202 {
203 uint64_t offset = (ptr_size == 4 ? 12 : 20);
204 Error error;
205 port_number = process_sp->ReadUnsignedIntegerFromMemory(offset+valobj_addr, 4, 0, error);
206 if (error.Success())
207 break;
208 }
209 if (!ExtractValueFromObjCExpression(valobj, "int", "machPort", port_number))
210 return false;
211 } while (false);
212
213 stream.Printf("mach port: %u",(uint32_t)(port_number & 0x00000000FFFFFFFF));
214 return true;
215}
216
217bool
Enrico Granataf35bc632014-11-06 21:55:30 +0000218lldb_private::formatters::NSIndexSetSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
Enrico Granata92373532013-03-19 22:58:48 +0000219{
220 ProcessSP process_sp = valobj.GetProcessSP();
221 if (!process_sp)
222 return false;
223
224 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
225
226 if (!runtime)
227 return false;
228
229 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
230
231 if (!descriptor.get() || !descriptor->IsValid())
232 return false;
233
234 uint32_t ptr_size = process_sp->GetAddressByteSize();
235
236 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
237
238 if (!valobj_addr)
239 return false;
240
241 const char* class_name = descriptor->GetClassName().GetCString();
242
243 if (!class_name || !*class_name)
244 return false;
245
246 uint64_t count = 0;
247
248 do {
249 if (!strcmp(class_name,"NSIndexSet") || !strcmp(class_name,"NSMutableIndexSet"))
250 {
251 Error error;
252 uint32_t mode = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+ptr_size, 4, 0, error);
253 if (error.Fail())
254 return false;
255 // this means the set is empty - count = 0
256 if ((mode & 1) == 1)
257 {
258 count = 0;
259 break;
260 }
261 if ((mode & 2) == 2)
262 mode = 1; // this means the set only has one range
263 else
264 mode = 2; // this means the set has multiple ranges
265 if (mode == 1)
266 {
267 count = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+3*ptr_size, ptr_size, 0, error);
268 if (error.Fail())
269 return false;
270 }
271 else
272 {
273 // read a pointer to the data at 2*ptr_size
274 count = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+2*ptr_size, ptr_size, 0, error);
275 if (error.Fail())
276 return false;
277 // read the data at 2*ptr_size from the first location
278 count = process_sp->ReadUnsignedIntegerFromMemory(count+2*ptr_size, ptr_size, 0, error);
279 if (error.Fail())
280 return false;
281 }
282 }
283 else
284 {
285 if (!ExtractValueFromObjCExpression(valobj, "unsigned long long int", "count", count))
286 return false;
287 }
288 } while (false);
Matt Kopecef143712013-06-03 18:00:07 +0000289 stream.Printf("%" PRIu64 " index%s",
Enrico Granata92373532013-03-19 22:58:48 +0000290 count,
291 (count == 1 ? "" : "es"));
292 return true;
293}
294
295bool
Enrico Granataf35bc632014-11-06 21:55:30 +0000296lldb_private::formatters::NSNumberSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
Enrico Granata92373532013-03-19 22:58:48 +0000297{
298 ProcessSP process_sp = valobj.GetProcessSP();
299 if (!process_sp)
300 return false;
301
302 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
303
304 if (!runtime)
305 return false;
306
307 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
308
309 if (!descriptor.get() || !descriptor->IsValid())
310 return false;
311
312 uint32_t ptr_size = process_sp->GetAddressByteSize();
313
314 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
315
316 if (!valobj_addr)
317 return false;
318
319 const char* class_name = descriptor->GetClassName().GetCString();
320
321 if (!class_name || !*class_name)
322 return false;
323
324 if (!strcmp(class_name,"NSNumber") || !strcmp(class_name,"__NSCFNumber"))
325 {
Enrico Granataf15ee4e2013-04-05 18:49:06 +0000326 uint64_t value = 0;
327 uint64_t i_bits = 0;
328 if (descriptor->GetTaggedPointerInfo(&i_bits,&value))
Enrico Granata92373532013-03-19 22:58:48 +0000329 {
Enrico Granata92373532013-03-19 22:58:48 +0000330 switch (i_bits)
331 {
332 case 0:
333 stream.Printf("(char)%hhd",(char)value);
334 break;
Enrico Granatab636be72013-04-24 17:49:08 +0000335 case 1:
Enrico Granata92373532013-03-19 22:58:48 +0000336 case 4:
337 stream.Printf("(short)%hd",(short)value);
338 break;
Enrico Granatab636be72013-04-24 17:49:08 +0000339 case 2:
Enrico Granata92373532013-03-19 22:58:48 +0000340 case 8:
341 stream.Printf("(int)%d",(int)value);
342 break;
Enrico Granatab636be72013-04-24 17:49:08 +0000343 case 3:
Enrico Granata92373532013-03-19 22:58:48 +0000344 case 12:
345 stream.Printf("(long)%" PRId64,value);
346 break;
347 default:
Enrico Granatabd4885f2014-04-10 18:17:30 +0000348 return false;
Enrico Granata92373532013-03-19 22:58:48 +0000349 }
350 return true;
351 }
352 else
353 {
354 Error error;
355 uint8_t data_type = (process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, 1, 0, error) & 0x1F);
356 uint64_t data_location = valobj_addr + 2*ptr_size;
357 uint64_t value = 0;
358 if (error.Fail())
359 return false;
360 switch (data_type)
361 {
362 case 1: // 0B00001
363 value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 1, 0, error);
364 if (error.Fail())
365 return false;
366 stream.Printf("(char)%hhd",(char)value);
367 break;
368 case 2: // 0B0010
369 value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 2, 0, error);
370 if (error.Fail())
371 return false;
372 stream.Printf("(short)%hd",(short)value);
373 break;
374 case 3: // 0B0011
375 value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 4, 0, error);
376 if (error.Fail())
377 return false;
378 stream.Printf("(int)%d",(int)value);
379 break;
380 case 17: // 0B10001
381 data_location += 8;
382 case 4: // 0B0100
383 value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 8, 0, error);
384 if (error.Fail())
385 return false;
386 stream.Printf("(long)%" PRId64,value);
387 break;
388 case 5: // 0B0101
389 {
390 uint32_t flt_as_int = process_sp->ReadUnsignedIntegerFromMemory(data_location, 4, 0, error);
391 if (error.Fail())
392 return false;
393 float flt_value = *((float*)&flt_as_int);
394 stream.Printf("(float)%f",flt_value);
395 break;
396 }
397 case 6: // 0B0110
398 {
399 uint64_t dbl_as_lng = process_sp->ReadUnsignedIntegerFromMemory(data_location, 8, 0, error);
400 if (error.Fail())
401 return false;
402 double dbl_value = *((double*)&dbl_as_lng);
403 stream.Printf("(double)%g",dbl_value);
404 break;
405 }
406 default:
Enrico Granatabd4885f2014-04-10 18:17:30 +0000407 return false;
Enrico Granata92373532013-03-19 22:58:48 +0000408 }
409 return true;
410 }
411 }
412 else
413 {
414 return ExtractSummaryFromObjCExpression(valobj, "NSString*", "stringValue", stream);
415 }
416}
417
418bool
Enrico Granataf35bc632014-11-06 21:55:30 +0000419lldb_private::formatters::NSURLSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
Enrico Granata92373532013-03-19 22:58:48 +0000420{
421 ProcessSP process_sp = valobj.GetProcessSP();
422 if (!process_sp)
423 return false;
424
425 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
426
427 if (!runtime)
428 return false;
429
430 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
431
432 if (!descriptor.get() || !descriptor->IsValid())
433 return false;
434
435 uint32_t ptr_size = process_sp->GetAddressByteSize();
436
437 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
438
439 if (!valobj_addr)
440 return false;
441
442 const char* class_name = descriptor->GetClassName().GetCString();
443
444 if (!class_name || !*class_name)
445 return false;
446
447 if (strcmp(class_name, "NSURL") == 0)
448 {
449 uint64_t offset_text = ptr_size + ptr_size + 8; // ISA + pointer + 8 bytes of data (even on 32bit)
450 uint64_t offset_base = offset_text + ptr_size;
Greg Clayton99558cc42015-08-24 23:46:31 +0000451 CompilerType type(valobj.GetCompilerType());
Enrico Granata92373532013-03-19 22:58:48 +0000452 ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset_text, type, true));
453 ValueObjectSP base(valobj.GetSyntheticChildAtOffset(offset_base, type, true));
454 if (!text)
455 return false;
456 if (text->GetValueAsUnsigned(0) == 0)
457 return false;
458 StreamString summary;
Enrico Granataf35bc632014-11-06 21:55:30 +0000459 if (!NSStringSummaryProvider(*text, summary, options))
Enrico Granata92373532013-03-19 22:58:48 +0000460 return false;
461 if (base && base->GetValueAsUnsigned(0))
462 {
463 if (summary.GetSize() > 0)
464 summary.GetString().resize(summary.GetSize()-1);
465 summary.Printf(" -- ");
466 StreamString base_summary;
Enrico Granataf35bc632014-11-06 21:55:30 +0000467 if (NSURLSummaryProvider(*base, base_summary, options) && base_summary.GetSize() > 0)
Enrico Granata92373532013-03-19 22:58:48 +0000468 summary.Printf("%s",base_summary.GetSize() > 2 ? base_summary.GetData() + 2 : base_summary.GetData());
469 }
470 if (summary.GetSize())
471 {
472 stream.Printf("%s",summary.GetData());
473 return true;
474 }
475 }
476 else
477 {
478 return ExtractSummaryFromObjCExpression(valobj, "NSString*", "description", stream);
479 }
480 return false;
481}
482
483bool
Enrico Granataf35bc632014-11-06 21:55:30 +0000484lldb_private::formatters::NSDateSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
Enrico Granata92373532013-03-19 22:58:48 +0000485{
486 ProcessSP process_sp = valobj.GetProcessSP();
487 if (!process_sp)
488 return false;
489
490 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
491
492 if (!runtime)
493 return false;
494
495 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
496
497 if (!descriptor.get() || !descriptor->IsValid())
498 return false;
499
500 uint32_t ptr_size = process_sp->GetAddressByteSize();
501
502 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
503
504 if (!valobj_addr)
505 return false;
506
507 uint64_t date_value_bits = 0;
508 double date_value = 0.0;
509
510 const char* class_name = descriptor->GetClassName().GetCString();
511
512 if (!class_name || !*class_name)
513 return false;
514
515 if (strcmp(class_name,"NSDate") == 0 ||
516 strcmp(class_name,"__NSDate") == 0 ||
517 strcmp(class_name,"__NSTaggedDate") == 0)
518 {
Enrico Granataf15ee4e2013-04-05 18:49:06 +0000519 uint64_t info_bits=0,value_bits = 0;
520 if (descriptor->GetTaggedPointerInfo(&info_bits,&value_bits))
Enrico Granata92373532013-03-19 22:58:48 +0000521 {
Enrico Granata92373532013-03-19 22:58:48 +0000522 date_value_bits = ((value_bits << 8) | (info_bits << 4));
523 date_value = *((double*)&date_value_bits);
524 }
525 else
526 {
527 Error error;
528 date_value_bits = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+ptr_size, 8, 0, error);
529 date_value = *((double*)&date_value_bits);
530 if (error.Fail())
531 return false;
532 }
533 }
534 else if (!strcmp(class_name,"NSCalendarDate"))
535 {
536 Error error;
537 date_value_bits = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+2*ptr_size, 8, 0, error);
538 date_value = *((double*)&date_value_bits);
539 if (error.Fail())
540 return false;
541 }
542 else
543 {
544 if (ExtractValueFromObjCExpression(valobj, "NSTimeInterval", "ExtractValueFromObjCExpression", date_value_bits) == false)
545 return false;
546 date_value = *((double*)&date_value_bits);
547 }
548 if (date_value == -63114076800)
549 {
550 stream.Printf("0001-12-30 00:00:00 +0000");
551 return true;
552 }
553 // this snippet of code assumes that time_t == seconds since Jan-1-1970
554 // this is generally true and POSIXly happy, but might break if a library
555 // vendor decides to get creative
556 time_t epoch = GetOSXEpoch();
557 epoch = epoch + (time_t)date_value;
Enrico Granatadb2ecad2014-10-15 20:18:58 +0000558 tm *tm_date = gmtime(&epoch);
Enrico Granata92373532013-03-19 22:58:48 +0000559 if (!tm_date)
560 return false;
561 std::string buffer(1024,0);
562 if (strftime (&buffer[0], 1023, "%Z", tm_date) == 0)
563 return false;
564 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());
565 return true;
566}
Enrico Granatad87cc312015-09-03 01:29:42 +0000567
568bool
569lldb_private::formatters::ObjCClassSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
570{
571 ProcessSP process_sp = valobj.GetProcessSP();
572 if (!process_sp)
573 return false;
574
575 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
576
577 if (!runtime)
578 return false;
579
580 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptorFromISA(valobj.GetValueAsUnsigned(0)));
581
582 if (!descriptor.get() || !descriptor->IsValid())
583 return false;
584
585 const char* class_name = descriptor->GetClassName().GetCString();
586
587 if (!class_name || !*class_name)
588 return false;
589
590 stream.Printf("%s",class_name);
591 return true;
592}
593
594class ObjCClassSyntheticChildrenFrontEnd : public SyntheticChildrenFrontEnd
595{
596public:
597 ObjCClassSyntheticChildrenFrontEnd (lldb::ValueObjectSP valobj_sp) :
598 SyntheticChildrenFrontEnd(*valobj_sp.get())
599 {
600 }
601
602 virtual size_t
603 CalculateNumChildren ()
604 {
605 return 0;
606 }
607
608 virtual lldb::ValueObjectSP
609 GetChildAtIndex (size_t idx)
610 {
611 return lldb::ValueObjectSP();
612 }
613
614 virtual bool
615 Update()
616 {
617 return false;
618 }
619
620 virtual bool
621 MightHaveChildren ()
622 {
623 return false;
624 }
625
626 virtual size_t
627 GetIndexOfChildWithName (const ConstString &name)
628 {
629 return UINT32_MAX;
630 }
631
632 virtual
633 ~ObjCClassSyntheticChildrenFrontEnd ()
634 {
635 }
636};
637
638SyntheticChildrenFrontEnd*
639lldb_private::formatters::ObjCClassSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
640{
641 return new ObjCClassSyntheticChildrenFrontEnd(valobj_sp);
642}
643
644template<bool needs_at>
645bool
646lldb_private::formatters::NSDataSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
647{
648 ProcessSP process_sp = valobj.GetProcessSP();
649 if (!process_sp)
650 return false;
651
652 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
653
654 if (!runtime)
655 return false;
656
657 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
658
659 if (!descriptor.get() || !descriptor->IsValid())
660 return false;
661
662 bool is_64bit = (process_sp->GetAddressByteSize() == 8);
663 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
664
665 if (!valobj_addr)
666 return false;
667
668 uint64_t value = 0;
669
670 const char* class_name = descriptor->GetClassName().GetCString();
671
672 if (!class_name || !*class_name)
673 return false;
674
675 if (!strcmp(class_name,"NSConcreteData") ||
676 !strcmp(class_name,"NSConcreteMutableData") ||
677 !strcmp(class_name,"__NSCFData"))
678 {
679 uint32_t offset = (is_64bit ? 16 : 8);
680 Error error;
681 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + offset, is_64bit ? 8 : 4, 0, error);
682 if (error.Fail())
683 return false;
684 }
685 else
686 {
687 if (!ExtractValueFromObjCExpression(valobj, "int", "length", value))
688 return false;
689 }
690
691 stream.Printf("%s%" PRIu64 " byte%s%s",
692 (needs_at ? "@\"" : ""),
693 value,
694 (value != 1 ? "s" : ""),
695 (needs_at ? "\"" : ""));
696
697 return true;
698}
699
700bool
701lldb_private::formatters::NSTaggedString_SummaryProvider (ObjCLanguageRuntime::ClassDescriptorSP descriptor, Stream& stream)
702{
703 if (!descriptor)
704 return false;
705 uint64_t len_bits = 0, data_bits = 0;
706 if (!descriptor->GetTaggedPointerInfo(&len_bits,&data_bits,nullptr))
707 return false;
708
709 static const int g_MaxNonBitmaskedLen = 7; //TAGGED_STRING_UNPACKED_MAXLEN
710 static const int g_SixbitMaxLen = 9;
711 static const int g_fiveBitMaxLen = 11;
712
713 static const char *sixBitToCharLookup = "eilotrm.apdnsIc ufkMShjTRxgC4013" "bDNvwyUL2O856P-B79AFKEWV_zGJ/HYX";
714
715 if (len_bits > g_fiveBitMaxLen)
716 return false;
717
718 // this is a fairly ugly trick - pretend that the numeric value is actually a char*
719 // this works under a few assumptions:
720 // little endian architecture
721 // sizeof(uint64_t) > g_MaxNonBitmaskedLen
722 if (len_bits <= g_MaxNonBitmaskedLen)
723 {
724 stream.Printf("@\"%s\"",(const char*)&data_bits);
725 return true;
726 }
727
728 // if the data is bitmasked, we need to actually process the bytes
729 uint8_t bitmask = 0;
730 uint8_t shift_offset = 0;
731
732 if (len_bits <= g_SixbitMaxLen)
733 {
734 bitmask = 0x03f;
735 shift_offset = 6;
736 }
737 else
738 {
739 bitmask = 0x01f;
740 shift_offset = 5;
741 }
742
743 std::vector<uint8_t> bytes;
744 bytes.resize(len_bits);
745 for (; len_bits > 0; data_bits >>= shift_offset, --len_bits)
746 {
747 uint8_t packed = data_bits & bitmask;
748 bytes.insert(bytes.begin(), sixBitToCharLookup[packed]);
749 }
750
751 stream.Printf("@\"%s\"",&bytes[0]);
752 return true;
753}
754
755static CompilerType
756GetNSPathStore2Type (Target &target)
757{
758 static ConstString g_type_name("__lldb_autogen_nspathstore2");
759
760 ClangASTContext *ast_ctx = target.GetScratchClangASTContext();
761
762 if (!ast_ctx)
763 return CompilerType();
764
765 CompilerType voidstar = ast_ctx->GetBasicType(lldb::eBasicTypeVoid).GetPointerType();
766 CompilerType uint32 = ast_ctx->GetIntTypeFromBitSize(32, false);
767
768 return ast_ctx->GetOrCreateStructForIdentifier(g_type_name, {
769 {"isa",voidstar},
770 {"lengthAndRef",uint32},
771 {"buffer",voidstar}
772 });
773}
774
775bool
776lldb_private::formatters::NSStringSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& summary_options)
777{
778 ProcessSP process_sp = valobj.GetProcessSP();
779 if (!process_sp)
780 return false;
781
782 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
783
784 if (!runtime)
785 return false;
786
787 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
788
789 if (!descriptor.get() || !descriptor->IsValid())
790 return false;
791
792 uint32_t ptr_size = process_sp->GetAddressByteSize();
793
794 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
795
796 if (!valobj_addr)
797 return false;
798
799 const char* class_name = descriptor->GetClassName().GetCString();
800
801 if (!class_name || !*class_name)
802 return false;
803
804 bool is_tagged_ptr = (0 == strcmp(class_name,"NSTaggedPointerString")) && descriptor->GetTaggedPointerInfo();
805 // for a tagged pointer, the descriptor has everything we need
806 if (is_tagged_ptr)
807 return NSTaggedString_SummaryProvider(descriptor, stream);
808
809 // if not a tagged pointer that we know about, try the normal route
810 uint64_t info_bits_location = valobj_addr + ptr_size;
811 if (process_sp->GetByteOrder() != lldb::eByteOrderLittle)
812 info_bits_location += 3;
813
814 Error error;
815
816 uint8_t info_bits = process_sp->ReadUnsignedIntegerFromMemory(info_bits_location, 1, 0, error);
817 if (error.Fail())
818 return false;
819
820 bool is_mutable = (info_bits & 1) == 1;
821 bool is_inline = (info_bits & 0x60) == 0;
822 bool has_explicit_length = (info_bits & (1 | 4)) != 4;
823 bool is_unicode = (info_bits & 0x10) == 0x10;
824 bool is_path_store = strcmp(class_name,"NSPathStore2") == 0;
825 bool has_null = (info_bits & 8) == 8;
826
827 size_t explicit_length = 0;
828 if (!has_null && has_explicit_length && !is_path_store)
829 {
830 lldb::addr_t explicit_length_offset = 2*ptr_size;
831 if (is_mutable && !is_inline)
832 explicit_length_offset = explicit_length_offset + ptr_size; // notInlineMutable.length;
833 else if (is_inline)
834 explicit_length = explicit_length + 0; // inline1.length;
835 else if (!is_inline && !is_mutable)
836 explicit_length_offset = explicit_length_offset + ptr_size; // notInlineImmutable1.length;
837 else
838 explicit_length_offset = 0;
839
840 if (explicit_length_offset)
841 {
842 explicit_length_offset = valobj_addr + explicit_length_offset;
843 explicit_length = process_sp->ReadUnsignedIntegerFromMemory(explicit_length_offset, 4, 0, error);
844 }
845 }
846
847 if (strcmp(class_name,"NSString") &&
848 strcmp(class_name,"CFStringRef") &&
849 strcmp(class_name,"CFMutableStringRef") &&
850 strcmp(class_name,"__NSCFConstantString") &&
851 strcmp(class_name,"__NSCFString") &&
852 strcmp(class_name,"NSCFConstantString") &&
853 strcmp(class_name,"NSCFString") &&
854 strcmp(class_name,"NSPathStore2"))
855 {
856 // not one of us - but tell me class name
857 stream.Printf("class name = %s",class_name);
858 return true;
859 }
860
861 if (is_mutable)
862 {
863 uint64_t location = 2 * ptr_size + valobj_addr;
864 location = process_sp->ReadPointerFromMemory(location, error);
865 if (error.Fail())
866 return false;
867 if (has_explicit_length && is_unicode)
868 {
869 ReadStringAndDumpToStreamOptions options(valobj);
870 options.SetLocation(location);
871 options.SetProcessSP(process_sp);
872 options.SetStream(&stream);
873 options.SetPrefixToken('@');
874 options.SetQuote('"');
875 options.SetSourceSize(explicit_length);
876 options.SetNeedsZeroTermination(false);
877 options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped);
878 options.SetBinaryZeroIsTerminator(false);
879 return ReadStringAndDumpToStream<StringElementType::UTF16>(options);
880 }
881 else
882 {
883 ReadStringAndDumpToStreamOptions options(valobj);
884 options.SetLocation(location+1);
885 options.SetProcessSP(process_sp);
886 options.SetStream(&stream);
887 options.SetPrefixToken('@');
888 options.SetSourceSize(explicit_length);
889 options.SetNeedsZeroTermination(false);
890 options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped);
891 options.SetBinaryZeroIsTerminator(false);
892 return ReadStringAndDumpToStream<StringElementType::ASCII>(options);
893 }
894 }
895 else if (is_inline && has_explicit_length && !is_unicode && !is_path_store && !is_mutable)
896 {
897 uint64_t location = 3 * ptr_size + valobj_addr;
898
899 ReadStringAndDumpToStreamOptions options(valobj);
900 options.SetLocation(location);
901 options.SetProcessSP(process_sp);
902 options.SetStream(&stream);
903 options.SetPrefixToken('@');
904 options.SetQuote('"');
905 options.SetSourceSize(explicit_length);
906 options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped);
907 return ReadStringAndDumpToStream<StringElementType::ASCII> (options);
908 }
909 else if (is_unicode)
910 {
911 uint64_t location = valobj_addr + 2*ptr_size;
912 if (is_inline)
913 {
914 if (!has_explicit_length)
915 {
916 stream.Printf("found new combo");
917 return true;
918 }
919 else
920 location += ptr_size;
921 }
922 else
923 {
924 location = process_sp->ReadPointerFromMemory(location, error);
925 if (error.Fail())
926 return false;
927 }
928 ReadStringAndDumpToStreamOptions options(valobj);
929 options.SetLocation(location);
930 options.SetProcessSP(process_sp);
931 options.SetStream(&stream);
932 options.SetPrefixToken('@');
933 options.SetQuote('"');
934 options.SetSourceSize(explicit_length);
935 options.SetNeedsZeroTermination(has_explicit_length == false);
936 options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped);
937 options.SetBinaryZeroIsTerminator(has_explicit_length == false);
938 return ReadStringAndDumpToStream<StringElementType::UTF16> (options);
939 }
940 else if (is_path_store)
941 {
942 ProcessStructReader reader(valobj.GetProcessSP().get(), valobj.GetValueAsUnsigned(0), GetNSPathStore2Type(*valobj.GetTargetSP()));
943 explicit_length = reader.GetField<uint32_t>(ConstString("lengthAndRef")) >> 20;
944 lldb::addr_t location = valobj.GetValueAsUnsigned(0) + ptr_size + 4;
945
946 ReadStringAndDumpToStreamOptions options(valobj);
947 options.SetLocation(location);
948 options.SetProcessSP(process_sp);
949 options.SetStream(&stream);
950 options.SetPrefixToken('@');
951 options.SetQuote('"');
952 options.SetSourceSize(explicit_length);
953 options.SetNeedsZeroTermination(has_explicit_length == false);
954 options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped);
955 options.SetBinaryZeroIsTerminator(has_explicit_length == false);
956 return ReadStringAndDumpToStream<StringElementType::UTF16> (options);
957 }
958 else if (is_inline)
959 {
960 uint64_t location = valobj_addr + 2*ptr_size;
961 if (!has_explicit_length)
962 {
963 // in this kind of string, the byte before the string content is a length byte
964 // so let's try and use it to handle the embedded NUL case
965 Error error;
966 explicit_length = process_sp->ReadUnsignedIntegerFromMemory(location, 1, 0, error);
967 if (error.Fail() || explicit_length == 0)
968 has_explicit_length = false;
969 else
970 has_explicit_length = true;
971 location++;
972 }
973 ReadStringAndDumpToStreamOptions options(valobj);
974 options.SetLocation(location);
975 options.SetProcessSP(process_sp);
976 options.SetStream(&stream);
977 options.SetPrefixToken('@');
978 options.SetSourceSize(explicit_length);
979 options.SetNeedsZeroTermination(!has_explicit_length);
980 options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped);
981 options.SetBinaryZeroIsTerminator(!has_explicit_length);
982 if (has_explicit_length)
983 return ReadStringAndDumpToStream<StringElementType::UTF8>(options);
984 else
985 return ReadStringAndDumpToStream<StringElementType::ASCII>(options);
986 }
987 else
988 {
989 uint64_t location = valobj_addr + 2*ptr_size;
990 location = process_sp->ReadPointerFromMemory(location, error);
991 if (error.Fail())
992 return false;
993 if (has_explicit_length && !has_null)
994 explicit_length++; // account for the fact that there is no NULL and we need to have one added
995 ReadStringAndDumpToStreamOptions options(valobj);
996 options.SetLocation(location);
997 options.SetProcessSP(process_sp);
998 options.SetPrefixToken('@');
999 options.SetStream(&stream);
1000 options.SetSourceSize(explicit_length);
1001 options.SetIgnoreMaxLength(summary_options.GetCapping() == TypeSummaryCapping::eTypeSummaryUncapped);
1002 return ReadStringAndDumpToStream<StringElementType::ASCII>(options);
1003 }
1004}
1005
1006bool
1007lldb_private::formatters::NSAttributedStringSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
1008{
1009 TargetSP target_sp(valobj.GetTargetSP());
1010 if (!target_sp)
1011 return false;
1012 uint32_t addr_size = target_sp->GetArchitecture().GetAddressByteSize();
1013 uint64_t pointer_value = valobj.GetValueAsUnsigned(0);
1014 if (!pointer_value)
1015 return false;
1016 pointer_value += addr_size;
1017 CompilerType type(valobj.GetCompilerType());
1018 ExecutionContext exe_ctx(target_sp,false);
1019 ValueObjectSP child_ptr_sp(valobj.CreateValueObjectFromAddress("string_ptr", pointer_value, exe_ctx, type));
1020 if (!child_ptr_sp)
1021 return false;
1022 DataExtractor data;
1023 Error error;
1024 child_ptr_sp->GetData(data, error);
1025 if (error.Fail())
1026 return false;
1027 ValueObjectSP child_sp(child_ptr_sp->CreateValueObjectFromData("string_data", data, exe_ctx, type));
1028 child_sp->GetValueAsUnsigned(0);
1029 if (child_sp)
1030 return NSStringSummaryProvider(*child_sp, stream, options);
1031 return false;
1032}
1033
1034bool
1035lldb_private::formatters::NSMutableAttributedStringSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
1036{
1037 return NSAttributedStringSummaryProvider(valobj, stream, options);
1038}
1039
1040bool
1041lldb_private::formatters::ObjCBOOLSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
1042{
1043 const uint32_t type_info = valobj.GetCompilerType().GetTypeInfo();
1044
1045 ValueObjectSP real_guy_sp = valobj.GetSP();
1046
1047 if (type_info & eTypeIsPointer)
1048 {
1049 Error err;
1050 real_guy_sp = valobj.Dereference(err);
1051 if (err.Fail() || !real_guy_sp)
1052 return false;
1053 }
1054 else if (type_info & eTypeIsReference)
1055 {
1056 real_guy_sp = valobj.GetChildAtIndex(0, true);
1057 if (!real_guy_sp)
1058 return false;
1059 }
1060 uint64_t value = real_guy_sp->GetValueAsUnsigned(0);
1061 if (value == 0)
1062 {
1063 stream.Printf("NO");
1064 return true;
1065 }
1066 stream.Printf("YES");
1067 return true;
1068}
1069
1070template <bool is_sel_ptr>
1071bool
1072lldb_private::formatters::ObjCSELSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
1073{
1074 lldb::ValueObjectSP valobj_sp;
1075
1076 CompilerType charstar (valobj.GetCompilerType().GetBasicTypeFromAST(eBasicTypeChar).GetPointerType());
1077
1078 if (!charstar)
1079 return false;
1080
1081 ExecutionContext exe_ctx(valobj.GetExecutionContextRef());
1082
1083 if (is_sel_ptr)
1084 {
1085 lldb::addr_t data_address = valobj.GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
1086 if (data_address == LLDB_INVALID_ADDRESS)
1087 return false;
1088 valobj_sp = ValueObject::CreateValueObjectFromAddress("text", data_address, exe_ctx, charstar);
1089 }
1090 else
1091 {
1092 DataExtractor data;
1093 Error error;
1094 valobj.GetData(data, error);
1095 if (error.Fail())
1096 return false;
1097 valobj_sp = ValueObject::CreateValueObjectFromData("text", data, exe_ctx, charstar);
1098 }
1099
1100 if (!valobj_sp)
1101 return false;
1102
1103 stream.Printf("%s",valobj_sp->GetSummaryAsCString());
1104 return true;
1105}
1106
1107// POSIX has an epoch on Jan-1-1970, but Cocoa prefers Jan-1-2001
1108// this call gives the POSIX equivalent of the Cocoa epoch
1109time_t
1110lldb_private::formatters::GetOSXEpoch ()
1111{
1112 static time_t epoch = 0;
1113 if (!epoch)
1114 {
1115#ifndef _WIN32
1116 tzset();
1117 tm tm_epoch;
1118 tm_epoch.tm_sec = 0;
1119 tm_epoch.tm_hour = 0;
1120 tm_epoch.tm_min = 0;
1121 tm_epoch.tm_mon = 0;
1122 tm_epoch.tm_mday = 1;
1123 tm_epoch.tm_year = 2001-1900; // for some reason, we need to subtract 1900 from this field. not sure why.
1124 tm_epoch.tm_isdst = -1;
1125 tm_epoch.tm_gmtoff = 0;
1126 tm_epoch.tm_zone = NULL;
1127 epoch = timegm(&tm_epoch);
1128#endif
1129 }
1130 return epoch;
1131}
1132
Enrico Granata419d7912015-09-04 00:33:51 +00001133bool
1134lldb_private::formatters::RuntimeSpecificDescriptionSummaryProvider (ValueObject& valobj, Stream& stream, const TypeSummaryOptions& options)
1135{
1136 stream.Printf("%s",valobj.GetObjectDescription());
1137 return true;
1138}
1139
Enrico Granatad87cc312015-09-03 01:29:42 +00001140template bool
1141lldb_private::formatters::NSDataSummaryProvider<true> (ValueObject&, Stream&, const TypeSummaryOptions&) ;
1142
1143template bool
1144lldb_private::formatters::NSDataSummaryProvider<false> (ValueObject&, Stream&, const TypeSummaryOptions&) ;
1145
1146template bool
1147lldb_private::formatters::ObjCSELSummaryProvider<true> (ValueObject&, Stream&, const TypeSummaryOptions&) ;
1148
1149template bool
1150lldb_private::formatters::ObjCSELSummaryProvider<false> (ValueObject&, Stream&, const TypeSummaryOptions&) ;