LLDB  mainline
Cocoa.cpp
Go to the documentation of this file.
1 //===-- Cocoa.cpp -----------------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "Cocoa.h"
10 
11 #include "lldb/Core/Mangled.h"
12 #include "lldb/Core/ValueObject.h"
17 #include "lldb/Host/Time.h"
19 #include "lldb/Target/Language.h"
21 #include "lldb/Target/Process.h"
23 #include "lldb/Target/Target.h"
25 #include "lldb/Utility/Endian.h"
26 #include "lldb/Utility/Status.h"
27 #include "lldb/Utility/Stream.h"
28 
29 #include "llvm/ADT/APInt.h"
30 #include "llvm/ADT/bit.h"
31 
33 
34 #include "NSString.h"
35 
36 using namespace lldb;
37 using namespace lldb_private;
38 using namespace lldb_private::formatters;
39 
41  ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
42  ProcessSP process_sp = valobj.GetProcessSP();
43  if (!process_sp)
44  return false;
45 
46  ObjCLanguageRuntime *runtime =
47  (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
49 
50  if (!runtime)
51  return false;
52 
54  runtime->GetClassDescriptor(valobj));
55 
56  if (!descriptor || !descriptor->IsValid())
57  return false;
58 
59  uint32_t ptr_size = process_sp->GetAddressByteSize();
60 
61  lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
62 
63  if (!valobj_addr)
64  return false;
65 
66  llvm::StringRef class_name(descriptor->GetClassName().GetCString());
67 
68  if (class_name.empty())
69  return false;
70 
71  if (class_name == "NSBundle") {
72  uint64_t offset = 5 * ptr_size;
73  ValueObjectSP text(valobj.GetSyntheticChildAtOffset(
74  offset,
76  true));
77 
78  StreamString summary_stream;
79  bool was_nsstring_ok =
80  NSStringSummaryProvider(*text, summary_stream, options);
81  if (was_nsstring_ok && summary_stream.GetSize() > 0) {
82  stream.Printf("%s", summary_stream.GetData());
83  return true;
84  }
85  }
86 
87  return false;
88 }
89 
91  ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
92  ProcessSP process_sp = valobj.GetProcessSP();
93  if (!process_sp)
94  return false;
95 
96  ObjCLanguageRuntime *runtime =
97  (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
99 
100  if (!runtime)
101  return false;
102 
104  runtime->GetClassDescriptor(valobj));
105 
106  if (!descriptor || !descriptor->IsValid())
107  return false;
108 
109  uint32_t ptr_size = process_sp->GetAddressByteSize();
110 
111  lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
112 
113  if (!valobj_addr)
114  return false;
115 
116  llvm::StringRef class_name(descriptor->GetClassName().GetCString());
117 
118  if (class_name.empty())
119  return false;
120 
121  if (class_name == "__NSTimeZone") {
122  uint64_t offset = ptr_size;
123  ValueObjectSP text(valobj.GetSyntheticChildAtOffset(
124  offset, valobj.GetCompilerType(), true));
125  StreamString summary_stream;
126  bool was_nsstring_ok =
127  NSStringSummaryProvider(*text, summary_stream, options);
128  if (was_nsstring_ok && summary_stream.GetSize() > 0) {
129  stream.Printf("%s", summary_stream.GetData());
130  return true;
131  }
132  }
133 
134  return false;
135 }
136 
138  ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
139  ProcessSP process_sp = valobj.GetProcessSP();
140  if (!process_sp)
141  return false;
142 
143  ObjCLanguageRuntime *runtime =
144  (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
146 
147  if (!runtime)
148  return false;
149 
151  runtime->GetClassDescriptor(valobj));
152 
153  if (!descriptor || !descriptor->IsValid())
154  return false;
155 
156  uint32_t ptr_size = process_sp->GetAddressByteSize();
157 
158  lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
159 
160  if (!valobj_addr)
161  return false;
162 
163  llvm::StringRef class_name(descriptor->GetClassName().GetCString());
164 
165  if (class_name.empty())
166  return false;
167 
168  if (class_name == "NSConcreteNotification") {
169  uint64_t offset = ptr_size;
170  ValueObjectSP text(valobj.GetSyntheticChildAtOffset(
171  offset, valobj.GetCompilerType(), true));
172  StreamString summary_stream;
173  bool was_nsstring_ok =
174  NSStringSummaryProvider(*text, summary_stream, options);
175  if (was_nsstring_ok && summary_stream.GetSize() > 0) {
176  stream.Printf("%s", summary_stream.GetData());
177  return true;
178  }
179  }
180 
181  return false;
182 }
183 
185  ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
186  ProcessSP process_sp = valobj.GetProcessSP();
187  if (!process_sp)
188  return false;
189 
190  ObjCLanguageRuntime *runtime =
191  (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
193 
194  if (!runtime)
195  return false;
196 
198  runtime->GetClassDescriptor(valobj));
199 
200  if (!descriptor || !descriptor->IsValid())
201  return false;
202 
203  uint32_t ptr_size = process_sp->GetAddressByteSize();
204 
205  lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
206 
207  if (!valobj_addr)
208  return false;
209 
210  llvm::StringRef class_name(descriptor->GetClassName().GetCString());
211 
212  if (class_name.empty())
213  return false;
214 
215  uint64_t port_number = 0;
216 
217  if (class_name == "NSMachPort") {
218  uint64_t offset = (ptr_size == 4 ? 12 : 20);
219  Status error;
220  port_number = process_sp->ReadUnsignedIntegerFromMemory(
221  offset + valobj_addr, 4, 0, error);
222  if (error.Success()) {
223  stream.Printf("mach port: %u",
224  (uint32_t)(port_number & 0x00000000FFFFFFFF));
225  return true;
226  }
227  }
228 
229  return false;
230 }
231 
233  ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
234  ProcessSP process_sp = valobj.GetProcessSP();
235  if (!process_sp)
236  return false;
237 
238  ObjCLanguageRuntime *runtime =
239  (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
241 
242  if (!runtime)
243  return false;
244 
246  runtime->GetClassDescriptor(valobj));
247 
248  if (!descriptor || !descriptor->IsValid())
249  return false;
250 
251  uint32_t ptr_size = process_sp->GetAddressByteSize();
252 
253  lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
254 
255  if (!valobj_addr)
256  return false;
257 
258  llvm::StringRef class_name(descriptor->GetClassName().GetCString());
259 
260  if (class_name.empty())
261  return false;
262 
263  uint64_t count = 0;
264 
265  do {
266  if (class_name == "NSIndexSet" || class_name == "NSMutableIndexSet") {
267  Status error;
268  uint32_t mode = process_sp->ReadUnsignedIntegerFromMemory(
269  valobj_addr + ptr_size, 4, 0, error);
270  if (error.Fail())
271  return false;
272  // this means the set is empty - count = 0
273  if ((mode & 1) == 1) {
274  count = 0;
275  break;
276  }
277  if ((mode & 2) == 2)
278  mode = 1; // this means the set only has one range
279  else
280  mode = 2; // this means the set has multiple ranges
281  if (mode == 1) {
282  count = process_sp->ReadUnsignedIntegerFromMemory(
283  valobj_addr + 3 * ptr_size, ptr_size, 0, error);
284  if (error.Fail())
285  return false;
286  } else {
287  // read a pointer to the data at 2*ptr_size
288  count = process_sp->ReadUnsignedIntegerFromMemory(
289  valobj_addr + 2 * ptr_size, ptr_size, 0, error);
290  if (error.Fail())
291  return false;
292  // read the data at 2*ptr_size from the first location
293  count = process_sp->ReadUnsignedIntegerFromMemory(count + 2 * ptr_size,
294  ptr_size, 0, error);
295  if (error.Fail())
296  return false;
297  }
298  } else
299  return false;
300  } while (false);
301  stream.Printf("%" PRIu64 " index%s", count, (count == 1 ? "" : "es"));
302  return true;
303 }
304 
305 static void NSNumber_FormatChar(ValueObject &valobj, Stream &stream, char value,
306  lldb::LanguageType lang) {
307  static ConstString g_TypeHint("NSNumber:char");
308 
309  std::string prefix, suffix;
310  if (Language *language = Language::FindPlugin(lang)) {
311  if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
312  suffix)) {
313  prefix.clear();
314  suffix.clear();
315  }
316  }
317 
318  stream.Printf("%s%hhd%s", prefix.c_str(), value, suffix.c_str());
319 }
320 
321 static void NSNumber_FormatShort(ValueObject &valobj, Stream &stream,
322  short value, lldb::LanguageType lang) {
323  static ConstString g_TypeHint("NSNumber:short");
324 
325  std::string prefix, suffix;
326  if (Language *language = Language::FindPlugin(lang)) {
327  if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
328  suffix)) {
329  prefix.clear();
330  suffix.clear();
331  }
332  }
333 
334  stream.Printf("%s%hd%s", prefix.c_str(), value, suffix.c_str());
335 }
336 
337 static void NSNumber_FormatInt(ValueObject &valobj, Stream &stream, int value,
338  lldb::LanguageType lang) {
339  static ConstString g_TypeHint("NSNumber:int");
340 
341  std::string prefix, suffix;
342  if (Language *language = Language::FindPlugin(lang)) {
343  if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
344  suffix)) {
345  prefix.clear();
346  suffix.clear();
347  }
348  }
349 
350  stream.Printf("%s%d%s", prefix.c_str(), value, suffix.c_str());
351 }
352 
353 static void NSNumber_FormatLong(ValueObject &valobj, Stream &stream,
354  uint64_t value, lldb::LanguageType lang) {
355  static ConstString g_TypeHint("NSNumber:long");
356 
357  std::string prefix, suffix;
358  if (Language *language = Language::FindPlugin(lang)) {
359  if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
360  suffix)) {
361  prefix.clear();
362  suffix.clear();
363  }
364  }
365 
366  stream.Printf("%s%" PRId64 "%s", prefix.c_str(), value, suffix.c_str());
367 }
368 
369 static void NSNumber_FormatInt128(ValueObject &valobj, Stream &stream,
370  const llvm::APInt &value,
371  lldb::LanguageType lang) {
372  static ConstString g_TypeHint("NSNumber:int128_t");
373 
374  std::string prefix, suffix;
375  if (Language *language = Language::FindPlugin(lang)) {
376  if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
377  suffix)) {
378  prefix.clear();
379  suffix.clear();
380  }
381  }
382 
383  stream.PutCString(prefix.c_str());
384  const int radix = 10;
385  const bool isSigned = true;
386  std::string str = value.toString(radix, isSigned);
387  stream.PutCString(str.c_str());
388  stream.PutCString(suffix.c_str());
389 }
390 
391 static void NSNumber_FormatFloat(ValueObject &valobj, Stream &stream,
392  float value, lldb::LanguageType lang) {
393  static ConstString g_TypeHint("NSNumber:float");
394 
395  std::string prefix, suffix;
396  if (Language *language = Language::FindPlugin(lang)) {
397  if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
398  suffix)) {
399  prefix.clear();
400  suffix.clear();
401  }
402  }
403 
404  stream.Printf("%s%f%s", prefix.c_str(), value, suffix.c_str());
405 }
406 
407 static void NSNumber_FormatDouble(ValueObject &valobj, Stream &stream,
408  double value, lldb::LanguageType lang) {
409  static ConstString g_TypeHint("NSNumber:double");
410 
411  std::string prefix, suffix;
412  if (Language *language = Language::FindPlugin(lang)) {
413  if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
414  suffix)) {
415  prefix.clear();
416  suffix.clear();
417  }
418  }
419 
420  stream.Printf("%s%g%s", prefix.c_str(), value, suffix.c_str());
421 }
422 
424  ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
425  ProcessSP process_sp = valobj.GetProcessSP();
426  if (!process_sp)
427  return false;
428 
429  ObjCLanguageRuntime *runtime =
430  (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
432 
433  if (!runtime)
434  return false;
435 
437  runtime->GetClassDescriptor(valobj));
438 
439  if (!descriptor || !descriptor->IsValid())
440  return false;
441 
442  uint32_t ptr_size = process_sp->GetAddressByteSize();
443 
444  lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
445 
446  if (!valobj_addr)
447  return false;
448 
449  llvm::StringRef class_name(descriptor->GetClassName().GetCString());
450 
451  if (class_name.empty())
452  return false;
453 
454  if (class_name == "__NSCFBoolean")
455  return ObjCBooleanSummaryProvider(valobj, stream, options);
456 
457  if (class_name == "NSDecimalNumber")
458  return NSDecimalNumberSummaryProvider(valobj, stream, options);
459 
460  if (class_name == "NSNumber" || class_name == "__NSCFNumber") {
461  uint64_t value = 0;
462  uint64_t i_bits = 0;
463  if (descriptor->GetTaggedPointerInfo(&i_bits, &value)) {
464  switch (i_bits) {
465  case 0:
466  NSNumber_FormatChar(valobj, stream, (char)value, options.GetLanguage());
467  break;
468  case 1:
469  case 4:
470  NSNumber_FormatShort(valobj, stream, (short)value,
471  options.GetLanguage());
472  break;
473  case 2:
474  case 8:
475  NSNumber_FormatInt(valobj, stream, (int)value, options.GetLanguage());
476  break;
477  case 3:
478  case 12:
479  NSNumber_FormatLong(valobj, stream, value, options.GetLanguage());
480  break;
481  default:
482  return false;
483  }
484  return true;
485  } else {
486  Status error;
487 
488  AppleObjCRuntime *runtime =
489  llvm::dyn_cast_or_null<AppleObjCRuntime>(
490  process_sp->GetObjCLanguageRuntime());
491 
492  const bool new_format =
493  (runtime && runtime->GetFoundationVersion() >= 1400);
494 
495  enum class TypeCodes : int {
496  sint8 = 0x0,
497  sint16 = 0x1,
498  sint32 = 0x2,
499  sint64 = 0x3,
500  f32 = 0x4,
501  f64 = 0x5,
502  sint128 = 0x6
503  };
504 
505  uint64_t data_location = valobj_addr + 2 * ptr_size;
506  TypeCodes type_code;
507 
508  if (new_format) {
509  uint64_t cfinfoa =
510  process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
511  ptr_size, 0, error);
512 
513  if (error.Fail())
514  return false;
515 
516  bool is_preserved_number = cfinfoa & 0x8;
517  if (is_preserved_number) {
518  lldbassert(!static_cast<bool>("We should handle preserved numbers!"));
519  return false;
520  }
521 
522  type_code = static_cast<TypeCodes>(cfinfoa & 0x7);
523  } else {
524  uint8_t data_type =
525  process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, 1,
526  0, error) & 0x1F;
527 
528  if (error.Fail())
529  return false;
530 
531  switch (data_type) {
532  case 1: type_code = TypeCodes::sint8; break;
533  case 2: type_code = TypeCodes::sint16; break;
534  case 3: type_code = TypeCodes::sint32; break;
535  case 17: data_location += 8; LLVM_FALLTHROUGH;
536  case 4: type_code = TypeCodes::sint64; break;
537  case 5: type_code = TypeCodes::f32; break;
538  case 6: type_code = TypeCodes::f64; break;
539  default: return false;
540  }
541  }
542 
543  uint64_t value = 0;
544  bool success = false;
545  switch (type_code) {
546  case TypeCodes::sint8:
547  value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 1, 0,
548  error);
549  if (error.Fail())
550  return false;
551  NSNumber_FormatChar(valobj, stream, (char)value, options.GetLanguage());
552  success = true;
553  break;
554  case TypeCodes::sint16:
555  value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 2, 0,
556  error);
557  if (error.Fail())
558  return false;
559  NSNumber_FormatShort(valobj, stream, (short)value,
560  options.GetLanguage());
561  success = true;
562  break;
563  case TypeCodes::sint32:
564  value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 4, 0,
565  error);
566  if (error.Fail())
567  return false;
568  NSNumber_FormatInt(valobj, stream, (int)value, options.GetLanguage());
569  success = true;
570  break;
571  case TypeCodes::sint64:
572  value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 8, 0,
573  error);
574  if (error.Fail())
575  return false;
576  NSNumber_FormatLong(valobj, stream, value, options.GetLanguage());
577  success = true;
578  break;
579  case TypeCodes::f32:
580  {
581  uint32_t flt_as_int = process_sp->ReadUnsignedIntegerFromMemory(
582  data_location, 4, 0, error);
583  if (error.Fail())
584  return false;
585  float flt_value = 0.0f;
586  memcpy(&flt_value, &flt_as_int, sizeof(flt_as_int));
587  NSNumber_FormatFloat(valobj, stream, flt_value, options.GetLanguage());
588  success = true;
589  break;
590  }
591  case TypeCodes::f64:
592  {
593  uint64_t dbl_as_lng = process_sp->ReadUnsignedIntegerFromMemory(
594  data_location, 8, 0, error);
595  if (error.Fail())
596  return false;
597  double dbl_value = 0.0;
598  memcpy(&dbl_value, &dbl_as_lng, sizeof(dbl_as_lng));
599  NSNumber_FormatDouble(valobj, stream, dbl_value, options.GetLanguage());
600  success = true;
601  break;
602  }
603  case TypeCodes::sint128: // internally, this is the same
604  {
605  uint64_t words[2];
606  words[1] = process_sp->ReadUnsignedIntegerFromMemory(
607  data_location, 8, 0, error);
608  if (error.Fail())
609  return false;
610  words[0] = process_sp->ReadUnsignedIntegerFromMemory(
611  data_location + 8, 8, 0, error);
612  if (error.Fail())
613  return false;
614  llvm::APInt i128_value(128, words);
615  NSNumber_FormatInt128(valobj, stream, i128_value, options.GetLanguage());
616  success = true;
617  break;
618  }
619  }
620  return success;
621  }
622  }
623 
624  return false;
625 }
626 
628  ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
629  ProcessSP process_sp = valobj.GetProcessSP();
630  if (!process_sp)
631  return false;
632 
633  lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
634  uint32_t ptr_size = process_sp->GetAddressByteSize();
635 
636  Status error;
637  int8_t exponent = process_sp->ReadUnsignedIntegerFromMemory(
638  valobj_addr + ptr_size, 1, 0, error);
639  if (error.Fail())
640  return false;
641 
642  uint8_t length_and_negative = process_sp->ReadUnsignedIntegerFromMemory(
643  valobj_addr + ptr_size + 1, 1, 0, error);
644  if (error.Fail())
645  return false;
646 
647  // Fifth bit marks negativity.
648  const bool is_negative = (length_and_negative >> 4) & 1;
649 
650  // Zero length and negative means NaN.
651  uint8_t length = length_and_negative & 0xf;
652  const bool is_nan = is_negative && (length == 0);
653 
654  if (is_nan) {
655  stream.Printf("NaN");
656  return true;
657  }
658 
659  if (length == 0) {
660  stream.Printf("0");
661  return true;
662  }
663 
664  uint64_t mantissa = process_sp->ReadUnsignedIntegerFromMemory(
665  valobj_addr + ptr_size + 4, 8, 0, error);
666  if (error.Fail())
667  return false;
668 
669  if (is_negative)
670  stream.Printf("-");
671 
672  stream.Printf("%" PRIu64 " x 10^%" PRIi8, mantissa, exponent);
673  return true;
674 }
675 
677  ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
678  ProcessSP process_sp = valobj.GetProcessSP();
679  if (!process_sp)
680  return false;
681 
682  ObjCLanguageRuntime *runtime =
683  (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
685 
686  if (!runtime)
687  return false;
688 
690  runtime->GetClassDescriptor(valobj));
691 
692  if (!descriptor || !descriptor->IsValid())
693  return false;
694 
695  uint32_t ptr_size = process_sp->GetAddressByteSize();
696 
697  lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
698 
699  if (!valobj_addr)
700  return false;
701 
702  llvm::StringRef class_name = descriptor->GetClassName().GetStringRef();
703 
704  if (!class_name.equals("NSURL"))
705  return false;
706 
707  uint64_t offset_text = ptr_size + ptr_size +
708  8; // ISA + pointer + 8 bytes of data (even on 32bit)
709  uint64_t offset_base = offset_text + ptr_size;
710  CompilerType type(valobj.GetCompilerType());
711  ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset_text, type, true));
712  ValueObjectSP base(valobj.GetSyntheticChildAtOffset(offset_base, type, true));
713  if (!text)
714  return false;
715  if (text->GetValueAsUnsigned(0) == 0)
716  return false;
717  StreamString summary;
718  if (!NSStringSummaryProvider(*text, summary, options))
719  return false;
720  if (base && base->GetValueAsUnsigned(0)) {
721  std::string summary_str = summary.GetString();
722 
723  if (!summary_str.empty())
724  summary_str.pop_back();
725  summary_str += " -- ";
726  StreamString base_summary;
727  if (NSURLSummaryProvider(*base, base_summary, options) &&
728  !base_summary.Empty()) {
729  llvm::StringRef base_str = base_summary.GetString();
730  if (base_str.size() > 2)
731  base_str = base_str.drop_front(2);
732  summary_str += base_str;
733  }
734  summary.Clear();
735  summary.PutCString(summary_str);
736  }
737  if (!summary.Empty()) {
738  stream.PutCString(summary.GetString());
739  return true;
740  }
741 
742  return false;
743 }
744 
745 /// Bias value for tagged pointer exponents.
746 /// Recommended values:
747 /// 0x3e3: encodes all dates between distantPast and distantFuture
748 /// except for the range within about 1e-28 second of the reference date.
749 /// 0x3ef: encodes all dates for a few million years beyond distantPast and
750 /// distantFuture, except within about 1e-25 second of the reference date.
751 const int TAGGED_DATE_EXPONENT_BIAS = 0x3ef;
752 
753 struct DoubleBits {
754  uint64_t fraction : 52; // unsigned
755  uint64_t exponent : 11; // signed
756  uint64_t sign : 1;
757 };
758 
760  uint64_t fraction : 52; // unsigned
761  uint64_t exponent : 7; // signed
762  uint64_t sign : 1;
763  uint64_t unused : 4; // placeholder for pointer tag bits
764 };
765 
766 static uint64_t decodeExponent(uint64_t exp) {
767  // Tagged exponent field is 7-bit signed. Sign-extend the value to 64 bits
768  // before performing arithmetic.
769  return llvm::SignExtend64<7>(exp) + TAGGED_DATE_EXPONENT_BIAS;
770 }
771 
772 static double decodeTaggedTimeInterval(uint64_t encodedTimeInterval) {
773  if (encodedTimeInterval == 0)
774  return 0.0;
775  if (encodedTimeInterval == std::numeric_limits<uint64_t>::max())
776  return (uint64_t)-0.0;
777 
778  TaggedDoubleBits encodedBits =
779  llvm::bit_cast<TaggedDoubleBits>(encodedTimeInterval);
780  assert(encodedBits.unused == 0);
781 
782  // Sign and fraction are represented exactly.
783  // Exponent is encoded.
784  DoubleBits decodedBits;
785  decodedBits.sign = encodedBits.sign;
786  decodedBits.fraction = encodedBits.fraction;
787  decodedBits.exponent = decodeExponent(encodedBits.exponent);
788 
789  return llvm::bit_cast<double>(decodedBits);
790 }
791 
793  ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
794  ProcessSP process_sp = valobj.GetProcessSP();
795  if (!process_sp)
796  return false;
797 
798  ObjCLanguageRuntime *runtime =
799  (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
801 
802  if (!runtime)
803  return false;
804 
806  runtime->GetClassDescriptor(valobj));
807 
808  if (!descriptor || !descriptor->IsValid())
809  return false;
810 
811  uint32_t ptr_size = process_sp->GetAddressByteSize();
812 
813  lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
814 
815  if (!valobj_addr)
816  return false;
817 
818  uint64_t date_value_bits = 0;
819  double date_value = 0.0;
820 
821  ConstString class_name = descriptor->GetClassName();
822 
823  static const ConstString g_NSDate("NSDate");
824  static const ConstString g___NSDate("__NSDate");
825  static const ConstString g___NSTaggedDate("__NSTaggedDate");
826  static const ConstString g_NSCalendarDate("NSCalendarDate");
827 
828  if (class_name.IsEmpty())
829  return false;
830 
831  uint64_t info_bits = 0, value_bits = 0;
832  if ((class_name == g_NSDate) || (class_name == g___NSDate) ||
833  (class_name == g___NSTaggedDate)) {
834  if (descriptor->GetTaggedPointerInfo(&info_bits, &value_bits)) {
835  date_value_bits = ((value_bits << 8) | (info_bits << 4));
836  memcpy(&date_value, &date_value_bits, sizeof(date_value_bits));
837  } else {
838  llvm::Triple triple(
839  process_sp->GetTarget().GetArchitecture().GetTriple());
840  uint32_t delta =
841  (triple.isWatchOS() && triple.isWatchABI()) ? 8 : ptr_size;
842  Status error;
843  date_value_bits = process_sp->ReadUnsignedIntegerFromMemory(
844  valobj_addr + delta, 8, 0, error);
845  memcpy(&date_value, &date_value_bits, sizeof(date_value_bits));
846  if (error.Fail())
847  return false;
848  }
849  } else if (class_name == g_NSCalendarDate) {
850  Status error;
851  date_value_bits = process_sp->ReadUnsignedIntegerFromMemory(
852  valobj_addr + 2 * ptr_size, 8, 0, error);
853  memcpy(&date_value, &date_value_bits, sizeof(date_value_bits));
854  if (error.Fail())
855  return false;
856  } else
857  return false;
858 
859  if (date_value == -63114076800) {
860  stream.Printf("0001-12-30 00:00:00 +0000");
861  return true;
862  }
863 
864  // Accomodate for the __NSTaggedDate format introduced in Foundation 1600.
865  if (class_name == g___NSTaggedDate) {
866  auto *runtime = llvm::dyn_cast_or_null<AppleObjCRuntime>(
867  process_sp->GetObjCLanguageRuntime());
868  if (runtime && runtime->GetFoundationVersion() >= 1600)
869  date_value = decodeTaggedTimeInterval(value_bits << 4);
870  }
871 
872  // this snippet of code assumes that time_t == seconds since Jan-1-1970 this
873  // is generally true and POSIXly happy, but might break if a library vendor
874  // decides to get creative
875  time_t epoch = GetOSXEpoch();
876  epoch = epoch + (time_t)date_value;
877  tm *tm_date = gmtime(&epoch);
878  if (!tm_date)
879  return false;
880  std::string buffer(1024, 0);
881  if (strftime(&buffer[0], 1023, "%Z", tm_date) == 0)
882  return false;
883  stream.Printf("%04d-%02d-%02d %02d:%02d:%02d %s", tm_date->tm_year + 1900,
884  tm_date->tm_mon + 1, tm_date->tm_mday, tm_date->tm_hour,
885  tm_date->tm_min, tm_date->tm_sec, buffer.c_str());
886  return true;
887 }
888 
890  ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
891  ProcessSP process_sp = valobj.GetProcessSP();
892  if (!process_sp)
893  return false;
894 
895  ObjCLanguageRuntime *runtime =
896  (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
898 
899  if (!runtime)
900  return false;
901 
903  runtime->GetClassDescriptorFromISA(valobj.GetValueAsUnsigned(0)));
904 
905  if (!descriptor || !descriptor->IsValid())
906  return false;
907 
908  ConstString class_name = descriptor->GetClassName();
909 
910  if (class_name.IsEmpty())
911  return false;
912 
913  if (ConstString cs =
914  Mangled(class_name).GetDemangledName(lldb::eLanguageTypeUnknown))
915  class_name = cs;
916 
917  stream.Printf("%s", class_name.AsCString("<unknown class>"));
918  return true;
919 }
920 
922 public:
923  ObjCClassSyntheticChildrenFrontEnd(lldb::ValueObjectSP valobj_sp)
924  : SyntheticChildrenFrontEnd(*valobj_sp) {}
925 
926  ~ObjCClassSyntheticChildrenFrontEnd() override = default;
927 
928  size_t CalculateNumChildren() override { return 0; }
929 
930  lldb::ValueObjectSP GetChildAtIndex(size_t idx) override {
931  return lldb::ValueObjectSP();
932  }
933 
934  bool Update() override { return false; }
935 
936  bool MightHaveChildren() override { return false; }
937 
938  size_t GetIndexOfChildWithName(ConstString name) override {
939  return UINT32_MAX;
940  }
941 };
942 
945  CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
946  return new ObjCClassSyntheticChildrenFrontEnd(valobj_sp);
947 }
948 
949 template <bool needs_at>
951  ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
952  ProcessSP process_sp = valobj.GetProcessSP();
953  if (!process_sp)
954  return false;
955 
956  ObjCLanguageRuntime *runtime =
957  (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
959 
960  if (!runtime)
961  return false;
962 
964  runtime->GetClassDescriptor(valobj));
965 
966  if (!descriptor || !descriptor->IsValid())
967  return false;
968 
969  bool is_64bit = (process_sp->GetAddressByteSize() == 8);
970  lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
971 
972  if (!valobj_addr)
973  return false;
974 
975  uint64_t value = 0;
976 
977  llvm::StringRef class_name = descriptor->GetClassName().GetCString();
978 
979  if (class_name.empty())
980  return false;
981 
982  bool isNSConcreteData = class_name == "NSConcreteData";
983  bool isNSConcreteMutableData = class_name == "NSConcreteMutableData";
984  bool isNSCFData = class_name == "__NSCFData";
985  if (isNSConcreteData || isNSConcreteMutableData || isNSCFData) {
986  uint32_t offset;
987  if (isNSConcreteData)
988  offset = is_64bit ? 8 : 4;
989  else
990  offset = is_64bit ? 16 : 8;
991 
992  Status error;
993  value = process_sp->ReadUnsignedIntegerFromMemory(
994  valobj_addr + offset, is_64bit ? 8 : 4, 0, error);
995  if (error.Fail())
996  return false;
997  } else if (class_name == "_NSInlineData") {
998  uint32_t offset = (is_64bit ? 8 : 4);
999  Status error;
1000  value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + offset, 2,
1001  0, error);
1002  if (error.Fail())
1003  return false;
1004  } else if (class_name == "_NSZeroData") {
1005  value = 0;
1006  } else
1007  return false;
1008 
1009  stream.Printf("%s%" PRIu64 " byte%s%s", (needs_at ? "@\"" : ""), value,
1010  (value != 1 ? "s" : ""), (needs_at ? "\"" : ""));
1011 
1012  return true;
1013 }
1014 
1016  ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
1017  const uint32_t type_info = valobj.GetCompilerType().GetTypeInfo();
1018 
1019  ValueObjectSP real_guy_sp = valobj.GetSP();
1020 
1021  if (type_info & eTypeIsPointer) {
1022  Status err;
1023  real_guy_sp = valobj.Dereference(err);
1024  if (err.Fail() || !real_guy_sp)
1025  return false;
1026  } else if (type_info & eTypeIsReference) {
1027  real_guy_sp = valobj.GetChildAtIndex(0, true);
1028  if (!real_guy_sp)
1029  return false;
1030  }
1031  uint8_t value = (real_guy_sp->GetValueAsUnsigned(0) & 0xFF);
1032  switch (value) {
1033  case 0:
1034  stream.Printf("NO");
1035  break;
1036  case 1:
1037  stream.Printf("YES");
1038  break;
1039  default:
1040  stream.Printf("%u", value);
1041  break;
1042  }
1043  return true;
1044 }
1045 
1047  ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
1048  lldb::addr_t valobj_ptr_value =
1050  if (valobj_ptr_value == LLDB_INVALID_ADDRESS)
1051  return false;
1052 
1053  ProcessSP process_sp(valobj.GetProcessSP());
1054  if (!process_sp)
1055  return false;
1056 
1057  if (AppleObjCRuntime *objc_runtime =
1058  (AppleObjCRuntime *)process_sp->GetObjCLanguageRuntime()) {
1060  cf_false = LLDB_INVALID_ADDRESS;
1061  objc_runtime->GetValuesForGlobalCFBooleans(cf_true, cf_false);
1062  if (valobj_ptr_value == cf_true) {
1063  stream.PutCString("YES");
1064  return true;
1065  }
1066  if (valobj_ptr_value == cf_false) {
1067  stream.PutCString("NO");
1068  return true;
1069  }
1070  }
1071 
1072  return false;
1073 }
1074 
1075 template <bool is_sel_ptr>
1077  ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
1078  lldb::ValueObjectSP valobj_sp;
1079 
1080  CompilerType charstar(valobj.GetCompilerType()
1082  .GetPointerType());
1083 
1084  if (!charstar)
1085  return false;
1086 
1087  ExecutionContext exe_ctx(valobj.GetExecutionContextRef());
1088 
1089  if (is_sel_ptr) {
1090  lldb::addr_t data_address = valobj.GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
1091  if (data_address == LLDB_INVALID_ADDRESS)
1092  return false;
1093  valobj_sp = ValueObject::CreateValueObjectFromAddress("text", data_address,
1094  exe_ctx, charstar);
1095  } else {
1096  DataExtractor data;
1097  Status error;
1098  valobj.GetData(data, error);
1099  if (error.Fail())
1100  return false;
1101  valobj_sp =
1102  ValueObject::CreateValueObjectFromData("text", data, exe_ctx, charstar);
1103  }
1104 
1105  if (!valobj_sp)
1106  return false;
1107 
1108  stream.Printf("%s", valobj_sp->GetSummaryAsCString());
1109  return true;
1110 }
1111 
1112 // POSIX has an epoch on Jan-1-1970, but Cocoa prefers Jan-1-2001
1113 // this call gives the POSIX equivalent of the Cocoa epoch
1115  static time_t epoch = 0;
1116  if (!epoch) {
1117 #ifndef _WIN32
1118  tzset();
1119  tm tm_epoch;
1120  tm_epoch.tm_sec = 0;
1121  tm_epoch.tm_hour = 0;
1122  tm_epoch.tm_min = 0;
1123  tm_epoch.tm_mon = 0;
1124  tm_epoch.tm_mday = 1;
1125  tm_epoch.tm_year = 2001 - 1900;
1126  tm_epoch.tm_isdst = -1;
1127  tm_epoch.tm_gmtoff = 0;
1128  tm_epoch.tm_zone = nullptr;
1129  epoch = timegm(&tm_epoch);
1130 #endif
1131  }
1132  return epoch;
1133 }
1134 
1136  ValueObject &, Stream &, const TypeSummaryOptions &);
1137 
1139  ValueObject &, Stream &, const TypeSummaryOptions &);
1140 
1142  ValueObject &, Stream &, const TypeSummaryOptions &);
1143 
1145  ValueObject &, Stream &, const TypeSummaryOptions &);
bool NSDecimalNumberSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options)
Definition: Cocoa.cpp:627
size_t PutCString(llvm::StringRef cstr)
Output a C string to the stream.
Definition: Stream.cpp:61
uint64_t unused
Definition: Cocoa.cpp:763
An data extractor class.
Definition: DataExtractor.h:47
CompilerType GetCompilerType()
Enumerations for broadcasting.
Definition: SBLaunchInfo.h:14
const char * AsCString(const char *value_if_empty=nullptr) const
Get the string value as a C string.
Definition: ConstString.h:224
virtual lldb::ValueObjectSP Dereference(Status &error)
A stream class that can stream formatted output to a file.
Definition: Stream.h:28
virtual ClassDescriptorSP GetClassDescriptorFromISA(ObjCISA isa)
bool NSBundleSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options)
Definition: Cocoa.cpp:40
#define lldbassert(x)
Definition: LLDBAssert.h:15
bool NSIndexSetSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options)
Definition: Cocoa.cpp:232
ObjCClassSyntheticChildrenFrontEnd(lldb::ValueObjectSP valobj_sp)
Definition: Cocoa.cpp:923
size_t CalculateNumChildren() override
Definition: Cocoa.cpp:928
bool NSDateSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options)
Definition: Cocoa.cpp:792
size_t GetIndexOfChildWithName(ConstString name) override
Definition: Cocoa.cpp:938
template bool NSDataSummaryProvider< false >(ValueObject &, Stream &, const TypeSummaryOptions &)
static void NSNumber_FormatFloat(ValueObject &valobj, Stream &stream, float value, lldb::LanguageType lang)
Definition: Cocoa.cpp:391
static void NSNumber_FormatShort(ValueObject &valobj, Stream &stream, short value, lldb::LanguageType lang)
Definition: Cocoa.cpp:321
const int TAGGED_DATE_EXPONENT_BIAS
Bias value for tagged pointer exponents.
Definition: Cocoa.cpp:751
lldb::ValueObjectSP GetChildAtIndex(size_t idx) override
Definition: Cocoa.cpp:930
static void NSNumber_FormatDouble(ValueObject &valobj, Stream &stream, double value, lldb::LanguageType lang)
Definition: Cocoa.cpp:407
template bool ObjCSELSummaryProvider< true >(ValueObject &, Stream &, const TypeSummaryOptions &)
uint32_t GetTypeInfo(CompilerType *pointee_or_element_compiler_type=nullptr) const
time_t timegm(struct tm *t)
"lldb/Target/ExecutionContext.h" A class that contains an execution context.
std::shared_ptr< ClassDescriptor > ClassDescriptorSP
bool NSNumberSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options)
Definition: Cocoa.cpp:423
template bool ObjCSELSummaryProvider< false >(ValueObject &, Stream &, const TypeSummaryOptions &)
const char * GetData() const
Definition: StreamString.h:43
CompilerType GetBasicTypeFromAST(lldb::BasicType basic_type) const
template bool NSDataSummaryProvider< true >(ValueObject &, Stream &, const TypeSummaryOptions &)
lldb::LanguageType GetLanguage() const
Definition: TypeSummary.cpp:42
bool NSURLSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options)
Definition: Cocoa.cpp:676
uint64_t exponent
Definition: Cocoa.cpp:755
#define UINT32_MAX
Definition: lldb-defines.h:31
bool NSDataSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options)
Definition: Cocoa.cpp:950
#define LLDB_INVALID_ADDRESS
Invalid value definitions.
Definition: lldb-defines.h:85
LanguageType
Programming language type.
uint64_t exponent
Definition: Cocoa.cpp:761
static uint64_t decodeExponent(uint64_t exp)
Definition: Cocoa.cpp:766
virtual lldb::ValueObjectSP GetSyntheticChildAtOffset(uint32_t offset, const CompilerType &type, bool can_create, ConstString name_const_str=ConstString())
bool NSMachPortSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options)
Definition: Cocoa.cpp:184
bool ObjCBooleanSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options)
Definition: Cocoa.cpp:1046
static void NSNumber_FormatInt128(ValueObject &valobj, Stream &stream, const llvm::APInt &value, lldb::LanguageType lang)
Definition: Cocoa.cpp:369
static void NSNumber_FormatChar(ValueObject &valobj, Stream &stream, char value, lldb::LanguageType lang)
Definition: Cocoa.cpp:305
llvm::StringRef GetString() const
bool NSTimeZoneSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options)
Definition: Cocoa.cpp:90
bool NSStringSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options)
Definition: NSString.cpp:53
uint64_t fraction
Definition: Cocoa.cpp:760
uint64_t fraction
Definition: Cocoa.cpp:754
const ExecutionContextRef & GetExecutionContextRef() const
Definition: ValueObject.h:353
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition: Stream.cpp:106
static void NSNumber_FormatInt(ValueObject &valobj, Stream &stream, int value, lldb::LanguageType lang)
Definition: Cocoa.cpp:337
bool Success() const
Test for success condition.
Definition: Status.cpp:287
uint64_t sign
Definition: Cocoa.cpp:756
CompilerType GetPointerType() const
virtual uint64_t GetData(DataExtractor &data, Status &error)
bool ObjCSELSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options)
Definition: Cocoa.cpp:1076
SyntheticChildrenFrontEnd * ObjCClassSyntheticFrontEndCreator(CXXSyntheticChildren *, lldb::ValueObjectSP)
Definition: Cocoa.cpp:944
uint64_t addr_t
Definition: lldb-types.h:83
static void NSNumber_FormatLong(ValueObject &valobj, Stream &stream, uint64_t value, lldb::LanguageType lang)
Definition: Cocoa.cpp:353
A uniqued constant string class.
Definition: ConstString.h:38
Unknown or invalid language value.
bool Fail() const
Test for error condition.
Definition: Status.cpp:181
lldb::ProcessSP GetProcessSP() const
Definition: ValueObject.h:361
static double decodeTaggedTimeInterval(uint64_t encodedTimeInterval)
Definition: Cocoa.cpp:772
virtual uint64_t GetValueAsUnsigned(uint64_t fail_value, bool *success=nullptr)
Definition: SBAddress.h:15
lldb::ValueObjectSP GetSP()
Definition: ValueObject.h:565
uint64_t sign
Definition: Cocoa.cpp:762
virtual ClassDescriptorSP GetClassDescriptor(ValueObject &in_value)
bool ObjCClassSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options)
Definition: Cocoa.cpp:889
bool IsEmpty() const
Test for empty string.
Definition: ConstString.h:340
bool MightHaveChildren() override
Definition: Cocoa.cpp:936
virtual lldb::ValueObjectSP GetChildAtIndex(size_t idx, bool can_create)
bool NSNotificationSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options)
Definition: Cocoa.cpp:137
An error handling class.
Definition: Status.h:44
bool ObjCBOOLSummaryProvider(ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options)
Definition: Cocoa.cpp:1015