blob: 4d77f0259c3d5b316abe4610c2d6de6251149731 [file] [log] [blame]
Eugene Zelenko8d15f332015-10-20 01:10:59 +00001//===-- Cocoa.cpp -----------------------------------------------*- C++ -*-===//
Enrico Granata92373532013-03-19 22:58:48 +00002//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Enrico Granata92373532013-03-19 22:58:48 +00006//
7//===----------------------------------------------------------------------===//
8
Enrico Granata170c3952015-09-14 22:18:32 +00009#include "Cocoa.h"
Enrico Granata92373532013-03-19 22:58:48 +000010
Enrico Granata7de855c2015-10-02 20:59:58 +000011#include "lldb/Core/Mangled.h"
Enrico Granata92373532013-03-19 22:58:48 +000012#include "lldb/Core/ValueObject.h"
13#include "lldb/Core/ValueObjectConstResult.h"
Enrico Granata419d7912015-09-04 00:33:51 +000014#include "lldb/DataFormatters/FormattersHelpers.h"
15#include "lldb/DataFormatters/StringPrinter.h"
16#include "lldb/DataFormatters/TypeSummary.h"
Pavel Labath46897a42017-01-25 11:19:49 +000017#include "lldb/Host/Time.h"
Enrico Granata92373532013-03-19 22:58:48 +000018#include "lldb/Symbol/ClangASTContext.h"
Enrico Granata675f49b2015-10-07 18:36:53 +000019#include "lldb/Target/Language.h"
Enrico Granata92373532013-03-19 22:58:48 +000020#include "lldb/Target/ObjCLanguageRuntime.h"
Enrico Granata419d7912015-09-04 00:33:51 +000021#include "lldb/Target/Process.h"
Zachary Turner01c32432017-02-14 19:06:07 +000022#include "lldb/Target/ProcessStructReader.h"
Kate Stoneb9c1b512016-09-06 20:57:50 +000023#include "lldb/Target/Target.h"
Zachary Turner666cc0b2017-03-04 01:30:05 +000024#include "lldb/Utility/DataBufferHeap.h"
Zachary Turner01c32432017-02-14 19:06:07 +000025#include "lldb/Utility/Endian.h"
Zachary Turner97206d52017-05-12 04:51:55 +000026#include "lldb/Utility/Status.h"
Zachary Turnerbf9a7732017-02-02 21:39:50 +000027#include "lldb/Utility/Stream.h"
Enrico Granatad87cc312015-09-03 01:29:42 +000028
Sean Callanan18b5d922017-06-19 18:32:22 +000029#include "llvm/ADT/APInt.h"
30
Enrico Granata2094e442016-08-22 18:07:52 +000031#include "Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.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
Kate Stoneb9c1b512016-09-06 20:57:50 +000039bool lldb_private::formatters::NSBundleSummaryProvider(
40 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
41 ProcessSP process_sp = valobj.GetProcessSP();
42 if (!process_sp)
Enrico Granataaa05cf92016-04-01 20:33:22 +000043 return false;
Enrico Granata92373532013-03-19 22:58:48 +000044
Kate Stoneb9c1b512016-09-06 20:57:50 +000045 ObjCLanguageRuntime *runtime =
46 (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
47 lldb::eLanguageTypeObjC);
48
49 if (!runtime)
Enrico Granataaa05cf92016-04-01 20:33:22 +000050 return false;
Enrico Granata92373532013-03-19 22:58:48 +000051
Kate Stoneb9c1b512016-09-06 20:57:50 +000052 ObjCLanguageRuntime::ClassDescriptorSP descriptor(
53 runtime->GetClassDescriptor(valobj));
54
55 if (!descriptor || !descriptor->IsValid())
Enrico Granataaa05cf92016-04-01 20:33:22 +000056 return false;
Enrico Granata92373532013-03-19 22:58:48 +000057
Kate Stoneb9c1b512016-09-06 20:57:50 +000058 uint32_t ptr_size = process_sp->GetAddressByteSize();
59
60 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
61
62 if (!valobj_addr)
Enrico Granataaa05cf92016-04-01 20:33:22 +000063 return false;
Enrico Granata92373532013-03-19 22:58:48 +000064
Jonas Devliegherecb38fd62018-06-13 18:15:14 +000065 llvm::StringRef class_name(descriptor->GetClassName().GetCString());
Enrico Granata92373532013-03-19 22:58:48 +000066
Jonas Devliegherecb38fd62018-06-13 18:15:14 +000067 if (class_name.empty())
Enrico Granataaa05cf92016-04-01 20:33:22 +000068 return false;
Kate Stoneb9c1b512016-09-06 20:57:50 +000069
Jonas Devliegherecb38fd62018-06-13 18:15:14 +000070 if (class_name == "NSBundle") {
Kate Stoneb9c1b512016-09-06 20:57:50 +000071 uint64_t offset = 5 * ptr_size;
72 ValueObjectSP text(valobj.GetSyntheticChildAtOffset(
73 offset,
74 valobj.GetCompilerType().GetBasicTypeFromAST(lldb::eBasicTypeObjCID),
75 true));
76
77 StreamString summary_stream;
78 bool was_nsstring_ok =
79 NSStringSummaryProvider(*text, summary_stream, options);
80 if (was_nsstring_ok && summary_stream.GetSize() > 0) {
81 stream.Printf("%s", summary_stream.GetData());
82 return true;
83 }
84 }
85
86 return false;
Enrico Granata92373532013-03-19 22:58:48 +000087}
88
Kate Stoneb9c1b512016-09-06 20:57:50 +000089bool lldb_private::formatters::NSTimeZoneSummaryProvider(
90 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
91 ProcessSP process_sp = valobj.GetProcessSP();
92 if (!process_sp)
Enrico Granata92373532013-03-19 22:58:48 +000093 return false;
Kate Stoneb9c1b512016-09-06 20:57:50 +000094
95 ObjCLanguageRuntime *runtime =
96 (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
97 lldb::eLanguageTypeObjC);
98
99 if (!runtime)
100 return false;
101
102 ObjCLanguageRuntime::ClassDescriptorSP descriptor(
103 runtime->GetClassDescriptor(valobj));
104
105 if (!descriptor || !descriptor->IsValid())
106 return false;
107
108 uint32_t ptr_size = process_sp->GetAddressByteSize();
109
110 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
111
112 if (!valobj_addr)
113 return false;
114
Jonas Devliegherecb38fd62018-06-13 18:15:14 +0000115 llvm::StringRef class_name(descriptor->GetClassName().GetCString());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000116
Jonas Devliegherecb38fd62018-06-13 18:15:14 +0000117 if (class_name.empty())
Kate Stoneb9c1b512016-09-06 20:57:50 +0000118 return false;
119
Jonas Devliegherecb38fd62018-06-13 18:15:14 +0000120 if (class_name == "__NSTimeZone") {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000121 uint64_t offset = ptr_size;
122 ValueObjectSP text(valobj.GetSyntheticChildAtOffset(
123 offset, valobj.GetCompilerType(), true));
124 StreamString summary_stream;
125 bool was_nsstring_ok =
126 NSStringSummaryProvider(*text, summary_stream, options);
127 if (was_nsstring_ok && summary_stream.GetSize() > 0) {
128 stream.Printf("%s", summary_stream.GetData());
129 return true;
130 }
131 }
132
133 return false;
Enrico Granata92373532013-03-19 22:58:48 +0000134}
135
Kate Stoneb9c1b512016-09-06 20:57:50 +0000136bool lldb_private::formatters::NSNotificationSummaryProvider(
137 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
138 ProcessSP process_sp = valobj.GetProcessSP();
139 if (!process_sp)
140 return false;
Enrico Granataaa05cf92016-04-01 20:33:22 +0000141
Kate Stoneb9c1b512016-09-06 20:57:50 +0000142 ObjCLanguageRuntime *runtime =
143 (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
144 lldb::eLanguageTypeObjC);
145
146 if (!runtime)
147 return false;
148
149 ObjCLanguageRuntime::ClassDescriptorSP descriptor(
150 runtime->GetClassDescriptor(valobj));
151
152 if (!descriptor || !descriptor->IsValid())
153 return false;
154
155 uint32_t ptr_size = process_sp->GetAddressByteSize();
156
157 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
158
159 if (!valobj_addr)
160 return false;
161
Jonas Devliegherecb38fd62018-06-13 18:15:14 +0000162 llvm::StringRef class_name(descriptor->GetClassName().GetCString());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000163
Jonas Devliegherecb38fd62018-06-13 18:15:14 +0000164 if (class_name.empty())
Kate Stoneb9c1b512016-09-06 20:57:50 +0000165 return false;
166
Jonas Devliegherecb38fd62018-06-13 18:15:14 +0000167 if (class_name == "NSConcreteNotification") {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000168 uint64_t offset = ptr_size;
169 ValueObjectSP text(valobj.GetSyntheticChildAtOffset(
170 offset, valobj.GetCompilerType(), true));
171 StreamString summary_stream;
172 bool was_nsstring_ok =
173 NSStringSummaryProvider(*text, summary_stream, options);
174 if (was_nsstring_ok && summary_stream.GetSize() > 0) {
175 stream.Printf("%s", summary_stream.GetData());
176 return true;
Enrico Granata92373532013-03-19 22:58:48 +0000177 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000178 }
179
180 return false;
181}
182
183bool lldb_private::formatters::NSMachPortSummaryProvider(
184 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
185 ProcessSP process_sp = valobj.GetProcessSP();
186 if (!process_sp)
187 return false;
188
189 ObjCLanguageRuntime *runtime =
190 (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
191 lldb::eLanguageTypeObjC);
192
193 if (!runtime)
194 return false;
195
196 ObjCLanguageRuntime::ClassDescriptorSP descriptor(
197 runtime->GetClassDescriptor(valobj));
198
199 if (!descriptor || !descriptor->IsValid())
200 return false;
201
202 uint32_t ptr_size = process_sp->GetAddressByteSize();
203
204 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
205
206 if (!valobj_addr)
207 return false;
208
Jonas Devliegherecb38fd62018-06-13 18:15:14 +0000209 llvm::StringRef class_name(descriptor->GetClassName().GetCString());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000210
Jonas Devliegherecb38fd62018-06-13 18:15:14 +0000211 if (class_name.empty())
Kate Stoneb9c1b512016-09-06 20:57:50 +0000212 return false;
213
214 uint64_t port_number = 0;
215
Jonas Devliegherecb38fd62018-06-13 18:15:14 +0000216 if (class_name == "NSMachPort") {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000217 uint64_t offset = (ptr_size == 4 ? 12 : 20);
Zachary Turner97206d52017-05-12 04:51:55 +0000218 Status error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000219 port_number = process_sp->ReadUnsignedIntegerFromMemory(
220 offset + valobj_addr, 4, 0, error);
221 if (error.Success()) {
222 stream.Printf("mach port: %u",
223 (uint32_t)(port_number & 0x00000000FFFFFFFF));
224 return true;
225 }
226 }
227
228 return false;
229}
230
231bool lldb_private::formatters::NSIndexSetSummaryProvider(
232 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
233 ProcessSP process_sp = valobj.GetProcessSP();
234 if (!process_sp)
235 return false;
236
237 ObjCLanguageRuntime *runtime =
238 (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
239 lldb::eLanguageTypeObjC);
240
241 if (!runtime)
242 return false;
243
244 ObjCLanguageRuntime::ClassDescriptorSP descriptor(
245 runtime->GetClassDescriptor(valobj));
246
247 if (!descriptor || !descriptor->IsValid())
248 return false;
249
250 uint32_t ptr_size = process_sp->GetAddressByteSize();
251
252 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
253
254 if (!valobj_addr)
255 return false;
256
Jonas Devliegherecb38fd62018-06-13 18:15:14 +0000257 llvm::StringRef class_name(descriptor->GetClassName().GetCString());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000258
Jonas Devliegherecb38fd62018-06-13 18:15:14 +0000259 if (class_name.empty())
Kate Stoneb9c1b512016-09-06 20:57:50 +0000260 return false;
261
262 uint64_t count = 0;
263
264 do {
Jonas Devliegherecb38fd62018-06-13 18:15:14 +0000265 if (class_name == "NSIndexSet" || class_name == "NSMutableIndexSet") {
Zachary Turner97206d52017-05-12 04:51:55 +0000266 Status error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000267 uint32_t mode = process_sp->ReadUnsignedIntegerFromMemory(
268 valobj_addr + ptr_size, 4, 0, error);
269 if (error.Fail())
270 return false;
271 // this means the set is empty - count = 0
272 if ((mode & 1) == 1) {
273 count = 0;
274 break;
275 }
276 if ((mode & 2) == 2)
277 mode = 1; // this means the set only has one range
278 else
279 mode = 2; // this means the set has multiple ranges
280 if (mode == 1) {
281 count = process_sp->ReadUnsignedIntegerFromMemory(
282 valobj_addr + 3 * ptr_size, ptr_size, 0, error);
Enrico Granata92373532013-03-19 22:58:48 +0000283 if (error.Fail())
Kate Stoneb9c1b512016-09-06 20:57:50 +0000284 return false;
285 } else {
286 // read a pointer to the data at 2*ptr_size
287 count = process_sp->ReadUnsignedIntegerFromMemory(
288 valobj_addr + 2 * ptr_size, ptr_size, 0, error);
289 if (error.Fail())
290 return false;
291 // read the data at 2*ptr_size from the first location
292 count = process_sp->ReadUnsignedIntegerFromMemory(count + 2 * ptr_size,
293 ptr_size, 0, error);
294 if (error.Fail())
295 return false;
296 }
297 } else
298 return false;
299 } while (false);
300 stream.Printf("%" PRIu64 " index%s", count, (count == 1 ? "" : "es"));
301 return true;
Enrico Granata92373532013-03-19 22:58:48 +0000302}
Enrico Granatad87cc312015-09-03 01:29:42 +0000303
Kate Stoneb9c1b512016-09-06 20:57:50 +0000304static void NSNumber_FormatChar(ValueObject &valobj, Stream &stream, char value,
305 lldb::LanguageType lang) {
306 static ConstString g_TypeHint("NSNumber:char");
307
308 std::string prefix, suffix;
309 if (Language *language = Language::FindPlugin(lang)) {
310 if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
311 suffix)) {
312 prefix.clear();
313 suffix.clear();
314 }
315 }
316
317 stream.Printf("%s%hhd%s", prefix.c_str(), value, suffix.c_str());
Enrico Granatad87cc312015-09-03 01:29:42 +0000318}
319
Kate Stoneb9c1b512016-09-06 20:57:50 +0000320static void NSNumber_FormatShort(ValueObject &valobj, Stream &stream,
321 short value, lldb::LanguageType lang) {
322 static ConstString g_TypeHint("NSNumber:short");
323
324 std::string prefix, suffix;
325 if (Language *language = Language::FindPlugin(lang)) {
326 if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
327 suffix)) {
328 prefix.clear();
329 suffix.clear();
330 }
331 }
332
333 stream.Printf("%s%hd%s", prefix.c_str(), value, suffix.c_str());
334}
335
336static void NSNumber_FormatInt(ValueObject &valobj, Stream &stream, int value,
337 lldb::LanguageType lang) {
338 static ConstString g_TypeHint("NSNumber:int");
339
340 std::string prefix, suffix;
341 if (Language *language = Language::FindPlugin(lang)) {
342 if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
343 suffix)) {
344 prefix.clear();
345 suffix.clear();
346 }
347 }
348
349 stream.Printf("%s%d%s", prefix.c_str(), value, suffix.c_str());
350}
351
352static void NSNumber_FormatLong(ValueObject &valobj, Stream &stream,
353 uint64_t value, lldb::LanguageType lang) {
354 static ConstString g_TypeHint("NSNumber:long");
355
356 std::string prefix, suffix;
357 if (Language *language = Language::FindPlugin(lang)) {
358 if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
359 suffix)) {
360 prefix.clear();
361 suffix.clear();
362 }
363 }
364
365 stream.Printf("%s%" PRId64 "%s", prefix.c_str(), value, suffix.c_str());
366}
367
Sean Callanan18b5d922017-06-19 18:32:22 +0000368static void NSNumber_FormatInt128(ValueObject &valobj, Stream &stream,
369 const llvm::APInt &value,
370 lldb::LanguageType lang) {
371 static ConstString g_TypeHint("NSNumber:int128_t");
372
373 std::string prefix, suffix;
374 if (Language *language = Language::FindPlugin(lang)) {
375 if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
376 suffix)) {
377 prefix.clear();
378 suffix.clear();
379 }
380 }
381
382 stream.PutCString(prefix.c_str());
383 const int radix = 10;
384 const bool isSigned = true;
385 std::string str = value.toString(radix, isSigned);
386 stream.PutCString(str.c_str());
387 stream.PutCString(suffix.c_str());
388}
389
Kate Stoneb9c1b512016-09-06 20:57:50 +0000390static void NSNumber_FormatFloat(ValueObject &valobj, Stream &stream,
391 float value, lldb::LanguageType lang) {
392 static ConstString g_TypeHint("NSNumber:float");
393
394 std::string prefix, suffix;
395 if (Language *language = Language::FindPlugin(lang)) {
396 if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
397 suffix)) {
398 prefix.clear();
399 suffix.clear();
400 }
401 }
402
403 stream.Printf("%s%f%s", prefix.c_str(), value, suffix.c_str());
404}
405
406static void NSNumber_FormatDouble(ValueObject &valobj, Stream &stream,
407 double value, lldb::LanguageType lang) {
408 static ConstString g_TypeHint("NSNumber:double");
409
410 std::string prefix, suffix;
411 if (Language *language = Language::FindPlugin(lang)) {
412 if (!language->GetFormatterPrefixSuffix(valobj, g_TypeHint, prefix,
413 suffix)) {
414 prefix.clear();
415 suffix.clear();
416 }
417 }
418
419 stream.Printf("%s%g%s", prefix.c_str(), value, suffix.c_str());
420}
421
422bool lldb_private::formatters::NSNumberSummaryProvider(
423 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
424 ProcessSP process_sp = valobj.GetProcessSP();
425 if (!process_sp)
426 return false;
427
428 ObjCLanguageRuntime *runtime =
429 (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
430 lldb::eLanguageTypeObjC);
431
432 if (!runtime)
433 return false;
434
435 ObjCLanguageRuntime::ClassDescriptorSP descriptor(
436 runtime->GetClassDescriptor(valobj));
437
438 if (!descriptor || !descriptor->IsValid())
439 return false;
440
441 uint32_t ptr_size = process_sp->GetAddressByteSize();
442
443 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
444
445 if (!valobj_addr)
446 return false;
447
Jonas Devliegherecb38fd62018-06-13 18:15:14 +0000448 llvm::StringRef class_name(descriptor->GetClassName().GetCString());
Kate Stoneb9c1b512016-09-06 20:57:50 +0000449
Jonas Devliegherecb38fd62018-06-13 18:15:14 +0000450 if (class_name.empty())
Kate Stoneb9c1b512016-09-06 20:57:50 +0000451 return false;
452
Jonas Devliegherecb38fd62018-06-13 18:15:14 +0000453 if (class_name == "__NSCFBoolean")
Kate Stoneb9c1b512016-09-06 20:57:50 +0000454 return ObjCBooleanSummaryProvider(valobj, stream, options);
455
Jonas Devlieghere20b051b2018-06-13 18:47:04 +0000456 if (class_name == "NSDecimalNumber")
457 return NSDecimalNumberSummaryProvider(valobj, stream, options);
458
Jonas Devliegherecb38fd62018-06-13 18:15:14 +0000459 if (class_name == "NSNumber" || class_name == "__NSCFNumber") {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000460 uint64_t value = 0;
461 uint64_t i_bits = 0;
462 if (descriptor->GetTaggedPointerInfo(&i_bits, &value)) {
463 switch (i_bits) {
464 case 0:
465 NSNumber_FormatChar(valobj, stream, (char)value, options.GetLanguage());
466 break;
467 case 1:
468 case 4:
469 NSNumber_FormatShort(valobj, stream, (short)value,
470 options.GetLanguage());
471 break;
472 case 2:
473 case 8:
474 NSNumber_FormatInt(valobj, stream, (int)value, options.GetLanguage());
475 break;
476 case 3:
477 case 12:
478 NSNumber_FormatLong(valobj, stream, value, options.GetLanguage());
479 break;
480 default:
481 return false;
482 }
483 return true;
484 } else {
Zachary Turner97206d52017-05-12 04:51:55 +0000485 Status error;
Sean Callanan18b5d922017-06-19 18:32:22 +0000486
487 AppleObjCRuntime *runtime =
488 llvm::dyn_cast_or_null<AppleObjCRuntime>(
489 process_sp->GetObjCLanguageRuntime());
490
491 const bool new_format =
492 (runtime && runtime->GetFoundationVersion() >= 1400);
493
494 enum class TypeCodes : int {
495 sint8 = 0x0,
496 sint16 = 0x1,
497 sint32 = 0x2,
498 sint64 = 0x3,
499 f32 = 0x4,
500 f64 = 0x5,
501 sint128 = 0x6
502 };
503
Kate Stoneb9c1b512016-09-06 20:57:50 +0000504 uint64_t data_location = valobj_addr + 2 * ptr_size;
Sean Callanan18b5d922017-06-19 18:32:22 +0000505 TypeCodes type_code;
506
507 if (new_format) {
508 uint64_t cfinfoa =
509 process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size,
510 ptr_size, 0, error);
511
512 if (error.Fail())
513 return false;
514
515 bool is_preserved_number = cfinfoa & 0x8;
516 if (is_preserved_number) {
Tim Hammerquist0a940722017-06-29 23:33:40 +0000517 lldbassert(!static_cast<bool>("We should handle preserved numbers!"));
Sean Callanan18b5d922017-06-19 18:32:22 +0000518 return false;
519 }
520
Tim Hammerquist0a940722017-06-29 23:33:40 +0000521 type_code = static_cast<TypeCodes>(cfinfoa & 0x7);
Sean Callanan18b5d922017-06-19 18:32:22 +0000522 } else {
523 uint8_t data_type =
524 process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, 1,
525 0, error) & 0x1F;
526
527 if (error.Fail())
528 return false;
529
530 switch (data_type) {
531 case 1: type_code = TypeCodes::sint8; break;
532 case 2: type_code = TypeCodes::sint16; break;
533 case 3: type_code = TypeCodes::sint32; break;
534 case 17: data_location += 8; LLVM_FALLTHROUGH;
535 case 4: type_code = TypeCodes::sint64; break;
536 case 5: type_code = TypeCodes::f32; break;
537 case 6: type_code = TypeCodes::f64; break;
538 default: return false;
539 }
540 }
541
Kate Stoneb9c1b512016-09-06 20:57:50 +0000542 uint64_t value = 0;
Tim Hammerquist95c003b2017-07-11 21:06:20 +0000543 bool success = false;
Sean Callanan18b5d922017-06-19 18:32:22 +0000544 switch (type_code) {
545 case TypeCodes::sint8:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000546 value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 1, 0,
547 error);
548 if (error.Fail())
549 return false;
550 NSNumber_FormatChar(valobj, stream, (char)value, options.GetLanguage());
Tim Hammerquist95c003b2017-07-11 21:06:20 +0000551 success = true;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000552 break;
Sean Callanan18b5d922017-06-19 18:32:22 +0000553 case TypeCodes::sint16:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000554 value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 2, 0,
555 error);
556 if (error.Fail())
557 return false;
558 NSNumber_FormatShort(valobj, stream, (short)value,
559 options.GetLanguage());
Tim Hammerquist95c003b2017-07-11 21:06:20 +0000560 success = true;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000561 break;
Sean Callanan18b5d922017-06-19 18:32:22 +0000562 case TypeCodes::sint32:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000563 value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 4, 0,
564 error);
565 if (error.Fail())
566 return false;
567 NSNumber_FormatInt(valobj, stream, (int)value, options.GetLanguage());
Tim Hammerquist95c003b2017-07-11 21:06:20 +0000568 success = true;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000569 break;
Sean Callanan18b5d922017-06-19 18:32:22 +0000570 case TypeCodes::sint64:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000571 value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 8, 0,
572 error);
573 if (error.Fail())
574 return false;
575 NSNumber_FormatLong(valobj, stream, value, options.GetLanguage());
Tim Hammerquist95c003b2017-07-11 21:06:20 +0000576 success = true;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000577 break;
Sean Callanan18b5d922017-06-19 18:32:22 +0000578 case TypeCodes::f32:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000579 {
580 uint32_t flt_as_int = process_sp->ReadUnsignedIntegerFromMemory(
581 data_location, 4, 0, error);
582 if (error.Fail())
583 return false;
584 float flt_value = 0.0f;
585 memcpy(&flt_value, &flt_as_int, sizeof(flt_as_int));
586 NSNumber_FormatFloat(valobj, stream, flt_value, options.GetLanguage());
Tim Hammerquist95c003b2017-07-11 21:06:20 +0000587 success = true;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000588 break;
589 }
Sean Callanan18b5d922017-06-19 18:32:22 +0000590 case TypeCodes::f64:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000591 {
592 uint64_t dbl_as_lng = process_sp->ReadUnsignedIntegerFromMemory(
593 data_location, 8, 0, error);
594 if (error.Fail())
595 return false;
596 double dbl_value = 0.0;
597 memcpy(&dbl_value, &dbl_as_lng, sizeof(dbl_as_lng));
598 NSNumber_FormatDouble(valobj, stream, dbl_value, options.GetLanguage());
Tim Hammerquist95c003b2017-07-11 21:06:20 +0000599 success = true;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000600 break;
601 }
Sean Callanan18b5d922017-06-19 18:32:22 +0000602 case TypeCodes::sint128: // internally, this is the same
603 {
604 uint64_t words[2];
605 words[1] = process_sp->ReadUnsignedIntegerFromMemory(
606 data_location, 8, 0, error);
607 if (error.Fail())
608 return false;
609 words[0] = process_sp->ReadUnsignedIntegerFromMemory(
610 data_location + 8, 8, 0, error);
611 if (error.Fail())
612 return false;
613 llvm::APInt i128_value(128, words);
614 NSNumber_FormatInt128(valobj, stream, i128_value, options.GetLanguage());
Tim Hammerquist95c003b2017-07-11 21:06:20 +0000615 success = true;
Sean Callanan18b5d922017-06-19 18:32:22 +0000616 break;
617 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000618 }
Tim Hammerquist95c003b2017-07-11 21:06:20 +0000619 return success;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000620 }
621 }
622
623 return false;
624}
625
Jonas Devlieghere20b051b2018-06-13 18:47:04 +0000626bool lldb_private::formatters::NSDecimalNumberSummaryProvider(
627 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
628 ProcessSP process_sp = valobj.GetProcessSP();
629 if (!process_sp)
630 return false;
631
632 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
633 uint32_t ptr_size = process_sp->GetAddressByteSize();
634
635 Status error;
636 int8_t exponent = process_sp->ReadUnsignedIntegerFromMemory(
637 valobj_addr + ptr_size, 1, 0, error);
638 if (error.Fail())
639 return false;
640
641 uint8_t length_and_negative = process_sp->ReadUnsignedIntegerFromMemory(
642 valobj_addr + ptr_size + 1, 1, 0, error);
643 if (error.Fail())
644 return false;
645
646 // Fifth bit marks negativity.
647 const bool is_negative = (length_and_negative >> 4) & 1;
648
649 // Zero length and negative means NaN.
650 uint8_t length = length_and_negative & 0xf;
651 const bool is_nan = is_negative && (length == 0);
652
653 if (is_nan) {
654 stream.Printf("NaN");
655 return true;
656 }
657
658 if (length == 0) {
659 stream.Printf("0");
660 return true;
661 }
662
663 uint64_t mantissa = process_sp->ReadUnsignedIntegerFromMemory(
664 valobj_addr + ptr_size + 4, 8, 0, error);
665 if (error.Fail())
666 return false;
667
668 if (is_negative)
669 stream.Printf("-");
670
671 stream.Printf("%" PRIu64 " x 10^%" PRIi8, mantissa, exponent);
672 return true;
673}
674
Kate Stoneb9c1b512016-09-06 20:57:50 +0000675bool lldb_private::formatters::NSURLSummaryProvider(
676 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
677 ProcessSP process_sp = valobj.GetProcessSP();
678 if (!process_sp)
679 return false;
680
681 ObjCLanguageRuntime *runtime =
682 (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
683 lldb::eLanguageTypeObjC);
684
685 if (!runtime)
686 return false;
687
688 ObjCLanguageRuntime::ClassDescriptorSP descriptor(
689 runtime->GetClassDescriptor(valobj));
690
691 if (!descriptor || !descriptor->IsValid())
692 return false;
693
694 uint32_t ptr_size = process_sp->GetAddressByteSize();
695
696 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
697
698 if (!valobj_addr)
699 return false;
700
Zachary Turner2dd214a2016-11-15 20:13:14 +0000701 llvm::StringRef class_name = descriptor->GetClassName().GetStringRef();
Kate Stoneb9c1b512016-09-06 20:57:50 +0000702
Zachary Turner2dd214a2016-11-15 20:13:14 +0000703 if (!class_name.equals("NSURL"))
Kate Stoneb9c1b512016-09-06 20:57:50 +0000704 return false;
705
Zachary Turner2dd214a2016-11-15 20:13:14 +0000706 uint64_t offset_text = ptr_size + ptr_size +
707 8; // ISA + pointer + 8 bytes of data (even on 32bit)
708 uint64_t offset_base = offset_text + ptr_size;
709 CompilerType type(valobj.GetCompilerType());
710 ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset_text, type, true));
711 ValueObjectSP base(valobj.GetSyntheticChildAtOffset(offset_base, type, true));
712 if (!text)
713 return false;
714 if (text->GetValueAsUnsigned(0) == 0)
715 return false;
716 StreamString summary;
717 if (!NSStringSummaryProvider(*text, summary, options))
718 return false;
719 if (base && base->GetValueAsUnsigned(0)) {
720 std::string summary_str = summary.GetString();
721
722 if (!summary_str.empty())
723 summary_str.pop_back();
724 summary_str += " -- ";
725 StreamString base_summary;
726 if (NSURLSummaryProvider(*base, base_summary, options) &&
727 !base_summary.Empty()) {
728 llvm::StringRef base_str = base_summary.GetString();
729 if (base_str.size() > 2)
730 base_str = base_str.drop_front(2);
731 summary_str += base_str;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000732 }
Zachary Turner2dd214a2016-11-15 20:13:14 +0000733 summary.Clear();
734 summary.PutCString(summary_str);
735 }
736 if (!summary.Empty()) {
737 stream.PutCString(summary.GetString());
738 return true;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000739 }
740
741 return false;
742}
743
Davide Italianocdcfa5d2018-11-13 19:43:43 +0000744/// Bias value for tagged pointer exponents.
745/// Recommended values:
746/// 0x3e3: encodes all dates between distantPast and distantFuture
747/// except for the range within about 1e-28 second of the reference date.
748/// 0x3ef: encodes all dates for a few million years beyond distantPast and
749/// distantFuture, except within about 1e-25 second of the reference date.
750const int TAGGED_DATE_EXPONENT_BIAS = 0x3ef;
751
752typedef union {
753 struct {
754 uint64_t fraction:52; // unsigned
755 uint64_t exponent:11; // signed
756 uint64_t sign:1;
757 };
758 uint64_t i;
759 double d;
760} DoubleBits;
761typedef union {
762 struct {
763 uint64_t fraction:52; // unsigned
764 uint64_t exponent:7; // signed
765 uint64_t sign:1;
766 uint64_t unused:4; // placeholder for pointer tag bits
767 };
768 uint64_t i;
769} TaggedDoubleBits;
770
771static uint64_t decodeExponent(uint64_t exp) {
Davide Italianocdcfa5d2018-11-13 19:43:43 +0000772 // Tagged exponent field is 7-bit signed. Sign-extend the value to 64 bits
773 // before performing arithmetic.
Davide Italiano9413be92018-11-16 19:53:00 +0000774 return llvm::SignExtend64<7>(exp) + TAGGED_DATE_EXPONENT_BIAS;
Davide Italianocdcfa5d2018-11-13 19:43:43 +0000775}
776
777static uint64_t decodeTaggedTimeInterval(uint64_t encodedTimeInterval) {
778 if (encodedTimeInterval == 0)
779 return 0.0;
780 if (encodedTimeInterval == std::numeric_limits<uint64_t>::max())
Haojian Wu59fa37d2018-11-14 09:53:45 +0000781 return (uint64_t)-0.0;
Davide Italianocdcfa5d2018-11-13 19:43:43 +0000782
Zachary Turnerfca18e92018-11-14 17:22:09 +0000783 TaggedDoubleBits encodedBits = {};
784 encodedBits.i = encodedTimeInterval;
Davide Italianocdcfa5d2018-11-13 19:43:43 +0000785 DoubleBits decodedBits;
786
787 // Sign and fraction are represented exactly.
788 // Exponent is encoded.
789 assert(encodedBits.unused == 0);
790 decodedBits.sign = encodedBits.sign;
791 decodedBits.fraction = encodedBits.fraction;
792 decodedBits.exponent = decodeExponent(encodedBits.exponent);
793
794 return decodedBits.d;
795}
796
Kate Stoneb9c1b512016-09-06 20:57:50 +0000797bool lldb_private::formatters::NSDateSummaryProvider(
798 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
799 ProcessSP process_sp = valobj.GetProcessSP();
800 if (!process_sp)
801 return false;
802
803 ObjCLanguageRuntime *runtime =
804 (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
805 lldb::eLanguageTypeObjC);
806
807 if (!runtime)
808 return false;
809
810 ObjCLanguageRuntime::ClassDescriptorSP descriptor(
811 runtime->GetClassDescriptor(valobj));
812
813 if (!descriptor || !descriptor->IsValid())
814 return false;
815
816 uint32_t ptr_size = process_sp->GetAddressByteSize();
817
818 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
819
820 if (!valobj_addr)
821 return false;
822
823 uint64_t date_value_bits = 0;
824 double date_value = 0.0;
825
826 ConstString class_name = descriptor->GetClassName();
827
828 static const ConstString g_NSDate("NSDate");
829 static const ConstString g___NSDate("__NSDate");
830 static const ConstString g___NSTaggedDate("__NSTaggedDate");
831 static const ConstString g_NSCalendarDate("NSCalendarDate");
832
833 if (class_name.IsEmpty())
834 return false;
835
Davide Italianocdcfa5d2018-11-13 19:43:43 +0000836 uint64_t info_bits = 0, value_bits = 0;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000837 if ((class_name == g_NSDate) || (class_name == g___NSDate) ||
838 (class_name == g___NSTaggedDate)) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000839 if (descriptor->GetTaggedPointerInfo(&info_bits, &value_bits)) {
840 date_value_bits = ((value_bits << 8) | (info_bits << 4));
841 memcpy(&date_value, &date_value_bits, sizeof(date_value_bits));
842 } else {
843 llvm::Triple triple(
844 process_sp->GetTarget().GetArchitecture().GetTriple());
845 uint32_t delta =
846 (triple.isWatchOS() && triple.isWatchABI()) ? 8 : ptr_size;
Zachary Turner97206d52017-05-12 04:51:55 +0000847 Status error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000848 date_value_bits = process_sp->ReadUnsignedIntegerFromMemory(
849 valobj_addr + delta, 8, 0, error);
850 memcpy(&date_value, &date_value_bits, sizeof(date_value_bits));
851 if (error.Fail())
852 return false;
853 }
854 } else if (class_name == g_NSCalendarDate) {
Zachary Turner97206d52017-05-12 04:51:55 +0000855 Status error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000856 date_value_bits = process_sp->ReadUnsignedIntegerFromMemory(
857 valobj_addr + 2 * ptr_size, 8, 0, error);
858 memcpy(&date_value, &date_value_bits, sizeof(date_value_bits));
859 if (error.Fail())
860 return false;
861 } else
862 return false;
863
864 if (date_value == -63114076800) {
865 stream.Printf("0001-12-30 00:00:00 +0000");
866 return true;
867 }
Davide Italianocdcfa5d2018-11-13 19:43:43 +0000868
869 // Accomodate for the __NSTaggedDate format introduced in Foundation 1600.
870 if (class_name == g___NSTaggedDate) {
871 auto *runtime = llvm::dyn_cast_or_null<AppleObjCRuntime>(process_sp->GetObjCLanguageRuntime());
872 if (runtime && runtime->GetFoundationVersion() >= 1600)
873 date_value = decodeTaggedTimeInterval(value_bits << 4);
874 }
875
Adrian Prantl05097242018-04-30 16:49:04 +0000876 // this snippet of code assumes that time_t == seconds since Jan-1-1970 this
877 // is generally true and POSIXly happy, but might break if a library vendor
878 // decides to get creative
Kate Stoneb9c1b512016-09-06 20:57:50 +0000879 time_t epoch = GetOSXEpoch();
880 epoch = epoch + (time_t)date_value;
881 tm *tm_date = gmtime(&epoch);
882 if (!tm_date)
883 return false;
884 std::string buffer(1024, 0);
885 if (strftime(&buffer[0], 1023, "%Z", tm_date) == 0)
886 return false;
887 stream.Printf("%04d-%02d-%02d %02d:%02d:%02d %s", tm_date->tm_year + 1900,
888 tm_date->tm_mon + 1, tm_date->tm_mday, tm_date->tm_hour,
889 tm_date->tm_min, tm_date->tm_sec, buffer.c_str());
890 return true;
891}
892
893bool lldb_private::formatters::ObjCClassSummaryProvider(
894 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
895 ProcessSP process_sp = valobj.GetProcessSP();
896 if (!process_sp)
897 return false;
898
899 ObjCLanguageRuntime *runtime =
900 (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
901 lldb::eLanguageTypeObjC);
902
903 if (!runtime)
904 return false;
905
906 ObjCLanguageRuntime::ClassDescriptorSP descriptor(
907 runtime->GetClassDescriptorFromISA(valobj.GetValueAsUnsigned(0)));
908
909 if (!descriptor || !descriptor->IsValid())
910 return false;
911
912 ConstString class_name = descriptor->GetClassName();
913
914 if (class_name.IsEmpty())
915 return false;
916
917 if (ConstString cs =
918 Mangled(class_name).GetDemangledName(lldb::eLanguageTypeUnknown))
919 class_name = cs;
920
921 stream.Printf("%s", class_name.AsCString("<unknown class>"));
922 return true;
923}
924
925class ObjCClassSyntheticChildrenFrontEnd : public SyntheticChildrenFrontEnd {
Enrico Granatad87cc312015-09-03 01:29:42 +0000926public:
Kate Stoneb9c1b512016-09-06 20:57:50 +0000927 ObjCClassSyntheticChildrenFrontEnd(lldb::ValueObjectSP valobj_sp)
928 : SyntheticChildrenFrontEnd(*valobj_sp) {}
Eugene Zelenko8d15f332015-10-20 01:10:59 +0000929
Kate Stoneb9c1b512016-09-06 20:57:50 +0000930 ~ObjCClassSyntheticChildrenFrontEnd() override = default;
931
932 size_t CalculateNumChildren() override { return 0; }
933
934 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override {
935 return lldb::ValueObjectSP();
936 }
937
938 bool Update() override { return false; }
939
940 bool MightHaveChildren() override { return false; }
941
942 size_t GetIndexOfChildWithName(const ConstString &name) override {
943 return UINT32_MAX;
944 }
Enrico Granatad87cc312015-09-03 01:29:42 +0000945};
946
Kate Stoneb9c1b512016-09-06 20:57:50 +0000947SyntheticChildrenFrontEnd *
948lldb_private::formatters::ObjCClassSyntheticFrontEndCreator(
949 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) {
950 return new ObjCClassSyntheticChildrenFrontEnd(valobj_sp);
Enrico Granatad87cc312015-09-03 01:29:42 +0000951}
952
Kate Stoneb9c1b512016-09-06 20:57:50 +0000953template <bool needs_at>
954bool lldb_private::formatters::NSDataSummaryProvider(
955 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
956 ProcessSP process_sp = valobj.GetProcessSP();
957 if (!process_sp)
Enrico Granata2094e442016-08-22 18:07:52 +0000958 return false;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000959
960 ObjCLanguageRuntime *runtime =
961 (ObjCLanguageRuntime *)process_sp->GetLanguageRuntime(
962 lldb::eLanguageTypeObjC);
963
964 if (!runtime)
965 return false;
966
967 ObjCLanguageRuntime::ClassDescriptorSP descriptor(
968 runtime->GetClassDescriptor(valobj));
969
970 if (!descriptor || !descriptor->IsValid())
971 return false;
972
973 bool is_64bit = (process_sp->GetAddressByteSize() == 8);
974 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
975
976 if (!valobj_addr)
977 return false;
978
979 uint64_t value = 0;
980
Vedant Kumar6d2b4352018-02-22 23:48:21 +0000981 llvm::StringRef class_name = descriptor->GetClassName().GetCString();
Kate Stoneb9c1b512016-09-06 20:57:50 +0000982
Vedant Kumar6d2b4352018-02-22 23:48:21 +0000983 if (class_name.empty())
Kate Stoneb9c1b512016-09-06 20:57:50 +0000984 return false;
985
Vedant Kumar6d2b4352018-02-22 23:48:21 +0000986 bool isNSConcreteData = class_name == "NSConcreteData";
987 bool isNSConcreteMutableData = class_name == "NSConcreteMutableData";
988 bool isNSCFData = class_name == "__NSCFData";
989 if (isNSConcreteData || isNSConcreteMutableData || isNSCFData) {
990 uint32_t offset;
991 if (isNSConcreteData)
992 offset = is_64bit ? 8 : 4;
993 else
994 offset = is_64bit ? 16 : 8;
995
Zachary Turner97206d52017-05-12 04:51:55 +0000996 Status error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000997 value = process_sp->ReadUnsignedIntegerFromMemory(
998 valobj_addr + offset, is_64bit ? 8 : 4, 0, error);
999 if (error.Fail())
1000 return false;
Vedant Kumar6d2b4352018-02-22 23:48:21 +00001001 } else if (class_name == "_NSInlineData") {
Kate Stoneb9c1b512016-09-06 20:57:50 +00001002 uint32_t offset = (is_64bit ? 8 : 4);
Zachary Turner97206d52017-05-12 04:51:55 +00001003 Status error;
Kate Stoneb9c1b512016-09-06 20:57:50 +00001004 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + offset, 2,
1005 0, error);
1006 if (error.Fail())
1007 return false;
Vedant Kumar6d2b4352018-02-22 23:48:21 +00001008 } else if (class_name == "_NSZeroData") {
Kate Stoneb9c1b512016-09-06 20:57:50 +00001009 value = 0;
1010 } else
1011 return false;
1012
1013 stream.Printf("%s%" PRIu64 " byte%s%s", (needs_at ? "@\"" : ""), value,
1014 (value != 1 ? "s" : ""), (needs_at ? "\"" : ""));
1015
1016 return true;
1017}
1018
1019bool lldb_private::formatters::ObjCBOOLSummaryProvider(
1020 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
1021 const uint32_t type_info = valobj.GetCompilerType().GetTypeInfo();
1022
1023 ValueObjectSP real_guy_sp = valobj.GetSP();
1024
1025 if (type_info & eTypeIsPointer) {
Zachary Turner97206d52017-05-12 04:51:55 +00001026 Status err;
Kate Stoneb9c1b512016-09-06 20:57:50 +00001027 real_guy_sp = valobj.Dereference(err);
1028 if (err.Fail() || !real_guy_sp)
1029 return false;
1030 } else if (type_info & eTypeIsReference) {
1031 real_guy_sp = valobj.GetChildAtIndex(0, true);
1032 if (!real_guy_sp)
1033 return false;
1034 }
1035 uint8_t value = (real_guy_sp->GetValueAsUnsigned(0) & 0xFF);
1036 switch (value) {
1037 case 0:
1038 stream.Printf("NO");
1039 break;
1040 case 1:
1041 stream.Printf("YES");
1042 break;
1043 default:
1044 stream.Printf("%u", value);
1045 break;
1046 }
1047 return true;
1048}
1049
1050bool lldb_private::formatters::ObjCBooleanSummaryProvider(
1051 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
1052 lldb::addr_t valobj_ptr_value =
1053 valobj.GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
1054 if (valobj_ptr_value == LLDB_INVALID_ADDRESS)
1055 return false;
1056
1057 ProcessSP process_sp(valobj.GetProcessSP());
1058 if (!process_sp)
1059 return false;
1060
1061 if (AppleObjCRuntime *objc_runtime =
1062 (AppleObjCRuntime *)process_sp->GetObjCLanguageRuntime()) {
1063 lldb::addr_t cf_true = LLDB_INVALID_ADDRESS,
1064 cf_false = LLDB_INVALID_ADDRESS;
1065 objc_runtime->GetValuesForGlobalCFBooleans(cf_true, cf_false);
1066 if (valobj_ptr_value == cf_true) {
1067 stream.PutCString("YES");
1068 return true;
1069 }
1070 if (valobj_ptr_value == cf_false) {
1071 stream.PutCString("NO");
1072 return true;
1073 }
1074 }
1075
1076 return false;
Enrico Granata2094e442016-08-22 18:07:52 +00001077}
1078
Enrico Granatad87cc312015-09-03 01:29:42 +00001079template <bool is_sel_ptr>
Kate Stoneb9c1b512016-09-06 20:57:50 +00001080bool lldb_private::formatters::ObjCSELSummaryProvider(
1081 ValueObject &valobj, Stream &stream, const TypeSummaryOptions &options) {
1082 lldb::ValueObjectSP valobj_sp;
1083
1084 CompilerType charstar(valobj.GetCompilerType()
1085 .GetBasicTypeFromAST(eBasicTypeChar)
1086 .GetPointerType());
1087
1088 if (!charstar)
1089 return false;
1090
1091 ExecutionContext exe_ctx(valobj.GetExecutionContextRef());
1092
1093 if (is_sel_ptr) {
1094 lldb::addr_t data_address = valobj.GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
1095 if (data_address == LLDB_INVALID_ADDRESS)
1096 return false;
1097 valobj_sp = ValueObject::CreateValueObjectFromAddress("text", data_address,
1098 exe_ctx, charstar);
1099 } else {
1100 DataExtractor data;
Zachary Turner97206d52017-05-12 04:51:55 +00001101 Status error;
Kate Stoneb9c1b512016-09-06 20:57:50 +00001102 valobj.GetData(data, error);
1103 if (error.Fail())
1104 return false;
1105 valobj_sp =
1106 ValueObject::CreateValueObjectFromData("text", data, exe_ctx, charstar);
1107 }
1108
1109 if (!valobj_sp)
1110 return false;
1111
1112 stream.Printf("%s", valobj_sp->GetSummaryAsCString());
1113 return true;
Enrico Granatad87cc312015-09-03 01:29:42 +00001114}
1115
1116// POSIX has an epoch on Jan-1-1970, but Cocoa prefers Jan-1-2001
1117// this call gives the POSIX equivalent of the Cocoa epoch
Kate Stoneb9c1b512016-09-06 20:57:50 +00001118time_t lldb_private::formatters::GetOSXEpoch() {
1119 static time_t epoch = 0;
1120 if (!epoch) {
Enrico Granatad87cc312015-09-03 01:29:42 +00001121#ifndef _WIN32
Kate Stoneb9c1b512016-09-06 20:57:50 +00001122 tzset();
1123 tm tm_epoch;
1124 tm_epoch.tm_sec = 0;
1125 tm_epoch.tm_hour = 0;
1126 tm_epoch.tm_min = 0;
1127 tm_epoch.tm_mon = 0;
1128 tm_epoch.tm_mday = 1;
1129 tm_epoch.tm_year = 2001 - 1900;
1130 tm_epoch.tm_isdst = -1;
1131 tm_epoch.tm_gmtoff = 0;
1132 tm_epoch.tm_zone = nullptr;
1133 epoch = timegm(&tm_epoch);
Enrico Granatad87cc312015-09-03 01:29:42 +00001134#endif
Kate Stoneb9c1b512016-09-06 20:57:50 +00001135 }
1136 return epoch;
Enrico Granatad87cc312015-09-03 01:29:42 +00001137}
1138
Kate Stoneb9c1b512016-09-06 20:57:50 +00001139template bool lldb_private::formatters::NSDataSummaryProvider<true>(
1140 ValueObject &, Stream &, const TypeSummaryOptions &);
Enrico Granatad87cc312015-09-03 01:29:42 +00001141
Kate Stoneb9c1b512016-09-06 20:57:50 +00001142template bool lldb_private::formatters::NSDataSummaryProvider<false>(
1143 ValueObject &, Stream &, const TypeSummaryOptions &);
Enrico Granatad87cc312015-09-03 01:29:42 +00001144
Kate Stoneb9c1b512016-09-06 20:57:50 +00001145template bool lldb_private::formatters::ObjCSELSummaryProvider<true>(
1146 ValueObject &, Stream &, const TypeSummaryOptions &);
Enrico Granatad87cc312015-09-03 01:29:42 +00001147
Kate Stoneb9c1b512016-09-06 20:57:50 +00001148template bool lldb_private::formatters::ObjCSELSummaryProvider<false>(
1149 ValueObject &, Stream &, const TypeSummaryOptions &);