1 //===-- CXXFormatterFunctions.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
10 #include "lldb/lldb-python.h"
11
12 #include "lldb/DataFormatters/CXXFormatterFunctions.h"
13
14 #include "llvm/Support/ConvertUTF.h"
15
16 #include "lldb/Core/DataBufferHeap.h"
17 #include "lldb/Core/Error.h"
18 #include "lldb/Core/Stream.h"
19 #include "lldb/Core/ValueObject.h"
20 #include "lldb/Core/ValueObjectConstResult.h"
21 #include "lldb/Host/Endian.h"
22 #include "lldb/Symbol/ClangASTContext.h"
23 #include "lldb/Target/ObjCLanguageRuntime.h"
24 #include "lldb/Target/Target.h"
25
26 #include <algorithm>
27
28 using namespace lldb;
29 using namespace lldb_private;
30 using namespace lldb_private::formatters;
31
32 bool
ExtractValueFromObjCExpression(ValueObject & valobj,const char * target_type,const char * selector,uint64_t & value)33 lldb_private::formatters::ExtractValueFromObjCExpression (ValueObject &valobj,
34 const char* target_type,
35 const char* selector,
36 uint64_t &value)
37 {
38 if (!target_type || !*target_type)
39 return false;
40 if (!selector || !*selector)
41 return false;
42 StreamString expr;
43 expr.Printf("(%s)[(id)0x%" PRIx64 " %s]",target_type,valobj.GetPointerValue(),selector);
44 ExecutionContext exe_ctx (valobj.GetExecutionContextRef());
45 lldb::ValueObjectSP result_sp;
46 Target* target = exe_ctx.GetTargetPtr();
47 StackFrame* stack_frame = exe_ctx.GetFramePtr();
48 if (!target || !stack_frame)
49 return false;
50
51 EvaluateExpressionOptions options;
52 options.SetCoerceToId(false)
53 .SetUnwindOnError(true)
54 .SetKeepInMemory(true);
55
56 target->EvaluateExpression(expr.GetData(),
57 stack_frame,
58 result_sp,
59 options);
60 if (!result_sp)
61 return false;
62 value = result_sp->GetValueAsUnsigned(0);
63 return true;
64 }
65
66 bool
ExtractSummaryFromObjCExpression(ValueObject & valobj,const char * target_type,const char * selector,Stream & stream)67 lldb_private::formatters::ExtractSummaryFromObjCExpression (ValueObject &valobj,
68 const char* target_type,
69 const char* selector,
70 Stream &stream)
71 {
72 if (!target_type || !*target_type)
73 return false;
74 if (!selector || !*selector)
75 return false;
76 StreamString expr;
77 expr.Printf("(%s)[(id)0x%" PRIx64 " %s]",target_type,valobj.GetPointerValue(),selector);
78 ExecutionContext exe_ctx (valobj.GetExecutionContextRef());
79 lldb::ValueObjectSP result_sp;
80 Target* target = exe_ctx.GetTargetPtr();
81 StackFrame* stack_frame = exe_ctx.GetFramePtr();
82 if (!target || !stack_frame)
83 return false;
84
85 EvaluateExpressionOptions options;
86 options.SetCoerceToId(false)
87 .SetUnwindOnError(true)
88 .SetKeepInMemory(true)
89 .SetUseDynamic(lldb::eDynamicCanRunTarget);
90
91 target->EvaluateExpression(expr.GetData(),
92 stack_frame,
93 result_sp,
94 options);
95 if (!result_sp)
96 return false;
97 stream.Printf("%s",result_sp->GetSummaryAsCString());
98 return true;
99 }
100
101 lldb::ValueObjectSP
CallSelectorOnObject(ValueObject & valobj,const char * return_type,const char * selector,uint64_t index)102 lldb_private::formatters::CallSelectorOnObject (ValueObject &valobj,
103 const char* return_type,
104 const char* selector,
105 uint64_t index)
106 {
107 lldb::ValueObjectSP valobj_sp;
108 if (!return_type || !*return_type)
109 return valobj_sp;
110 if (!selector || !*selector)
111 return valobj_sp;
112 StreamString expr_path_stream;
113 valobj.GetExpressionPath(expr_path_stream, false);
114 StreamString expr;
115 expr.Printf("(%s)[%s %s:%" PRId64 "]",return_type,expr_path_stream.GetData(),selector,index);
116 ExecutionContext exe_ctx (valobj.GetExecutionContextRef());
117 lldb::ValueObjectSP result_sp;
118 Target* target = exe_ctx.GetTargetPtr();
119 StackFrame* stack_frame = exe_ctx.GetFramePtr();
120 if (!target || !stack_frame)
121 return valobj_sp;
122
123 EvaluateExpressionOptions options;
124 options.SetCoerceToId(false)
125 .SetUnwindOnError(true)
126 .SetKeepInMemory(true)
127 .SetUseDynamic(lldb::eDynamicCanRunTarget);
128
129 target->EvaluateExpression(expr.GetData(),
130 stack_frame,
131 valobj_sp,
132 options);
133 return valobj_sp;
134 }
135
136 lldb::ValueObjectSP
CallSelectorOnObject(ValueObject & valobj,const char * return_type,const char * selector,const char * key)137 lldb_private::formatters::CallSelectorOnObject (ValueObject &valobj,
138 const char* return_type,
139 const char* selector,
140 const char* key)
141 {
142 lldb::ValueObjectSP valobj_sp;
143 if (!return_type || !*return_type)
144 return valobj_sp;
145 if (!selector || !*selector)
146 return valobj_sp;
147 if (!key || !*key)
148 return valobj_sp;
149 StreamString expr_path_stream;
150 valobj.GetExpressionPath(expr_path_stream, false);
151 StreamString expr;
152 expr.Printf("(%s)[%s %s:%s]",return_type,expr_path_stream.GetData(),selector,key);
153 ExecutionContext exe_ctx (valobj.GetExecutionContextRef());
154 lldb::ValueObjectSP result_sp;
155 Target* target = exe_ctx.GetTargetPtr();
156 StackFrame* stack_frame = exe_ctx.GetFramePtr();
157 if (!target || !stack_frame)
158 return valobj_sp;
159
160 EvaluateExpressionOptions options;
161 options.SetCoerceToId(false)
162 .SetUnwindOnError(true)
163 .SetKeepInMemory(true)
164 .SetUseDynamic(lldb::eDynamicCanRunTarget);
165
166 target->EvaluateExpression(expr.GetData(),
167 stack_frame,
168 valobj_sp,
169 options);
170 return valobj_sp;
171 }
172
173 // use this call if you already have an LLDB-side buffer for the data
174 template<typename SourceDataType>
175 static bool
DumpUTFBufferToStream(ConversionResult (* ConvertFunction)(const SourceDataType **,const SourceDataType *,UTF8 **,UTF8 *,ConversionFlags),DataExtractor & data,Stream & stream,char prefix_token='@',char quote='"',uint32_t sourceSize=0)176 DumpUTFBufferToStream (ConversionResult (*ConvertFunction) (const SourceDataType**,
177 const SourceDataType*,
178 UTF8**,
179 UTF8*,
180 ConversionFlags),
181 DataExtractor& data,
182 Stream& stream,
183 char prefix_token = '@',
184 char quote = '"',
185 uint32_t sourceSize = 0)
186 {
187 if (prefix_token != 0)
188 stream.Printf("%c",prefix_token);
189 if (quote != 0)
190 stream.Printf("%c",quote);
191 if (data.GetByteSize() && data.GetDataStart() && data.GetDataEnd())
192 {
193 const int bufferSPSize = data.GetByteSize();
194 if (sourceSize == 0)
195 {
196 const int origin_encoding = 8*sizeof(SourceDataType);
197 sourceSize = bufferSPSize/(origin_encoding / 4);
198 }
199
200 SourceDataType *data_ptr = (SourceDataType*)data.GetDataStart();
201 SourceDataType *data_end_ptr = data_ptr + sourceSize;
202
203 while (data_ptr < data_end_ptr)
204 {
205 if (!*data_ptr)
206 {
207 data_end_ptr = data_ptr;
208 break;
209 }
210 data_ptr++;
211 }
212
213 data_ptr = (SourceDataType*)data.GetDataStart();
214
215 lldb::DataBufferSP utf8_data_buffer_sp;
216 UTF8* utf8_data_ptr = nullptr;
217 UTF8* utf8_data_end_ptr = nullptr;
218
219 if (ConvertFunction)
220 {
221 utf8_data_buffer_sp.reset(new DataBufferHeap(4*bufferSPSize,0));
222 utf8_data_ptr = (UTF8*)utf8_data_buffer_sp->GetBytes();
223 utf8_data_end_ptr = utf8_data_ptr + utf8_data_buffer_sp->GetByteSize();
224 ConvertFunction ( (const SourceDataType**)&data_ptr, data_end_ptr, &utf8_data_ptr, utf8_data_end_ptr, lenientConversion );
225 utf8_data_ptr = (UTF8*)utf8_data_buffer_sp->GetBytes(); // needed because the ConvertFunction will change the value of the data_ptr
226 }
227 else
228 {
229 // just copy the pointers - the cast is necessary to make the compiler happy
230 // but this should only happen if we are reading UTF8 data
231 utf8_data_ptr = (UTF8*)data_ptr;
232 utf8_data_end_ptr = (UTF8*)data_end_ptr;
233 }
234
235 // since we tend to accept partial data (and even partially malformed data)
236 // we might end up with no NULL terminator before the end_ptr
237 // hence we need to take a slower route and ensure we stay within boundaries
238 for (;utf8_data_ptr != utf8_data_end_ptr; utf8_data_ptr++)
239 {
240 if (!*utf8_data_ptr)
241 break;
242 stream.Printf("%c",*utf8_data_ptr);
243 }
244 }
245 if (quote != 0)
246 stream.Printf("%c",quote);
247 return true;
248 }
249
250 template<typename SourceDataType>
251 class ReadUTFBufferAndDumpToStreamOptions
252 {
253 public:
254 typedef ConversionResult (*ConvertFunctionType) (const SourceDataType**,
255 const SourceDataType*,
256 UTF8**,
257 UTF8*,
258 ConversionFlags);
259
ReadUTFBufferAndDumpToStreamOptions()260 ReadUTFBufferAndDumpToStreamOptions () :
261 m_conversion_function(NULL),
262 m_location(0),
263 m_process_sp(),
264 m_stream(NULL),
265 m_prefix_token('@'),
266 m_quote('"'),
267 m_source_size(0),
268 m_needs_zero_termination(true)
269 {
270 }
271
272 ReadUTFBufferAndDumpToStreamOptions&
SetConversionFunction(ConvertFunctionType f)273 SetConversionFunction (ConvertFunctionType f)
274 {
275 m_conversion_function = f;
276 return *this;
277 }
278
279 ConvertFunctionType
GetConversionFunction() const280 GetConversionFunction () const
281 {
282 return m_conversion_function;
283 }
284
285 ReadUTFBufferAndDumpToStreamOptions&
SetLocation(uint64_t l)286 SetLocation (uint64_t l)
287 {
288 m_location = l;
289 return *this;
290 }
291
292 uint64_t
GetLocation() const293 GetLocation () const
294 {
295 return m_location;
296 }
297
298 ReadUTFBufferAndDumpToStreamOptions&
SetProcessSP(ProcessSP p)299 SetProcessSP (ProcessSP p)
300 {
301 m_process_sp = p;
302 return *this;
303 }
304
305 ProcessSP
GetProcessSP() const306 GetProcessSP () const
307 {
308 return m_process_sp;
309 }
310
311 ReadUTFBufferAndDumpToStreamOptions&
SetStream(Stream * s)312 SetStream (Stream* s)
313 {
314 m_stream = s;
315 return *this;
316 }
317
318 Stream*
GetStream() const319 GetStream () const
320 {
321 return m_stream;
322 }
323
324 ReadUTFBufferAndDumpToStreamOptions&
SetPrefixToken(char p)325 SetPrefixToken (char p)
326 {
327 m_prefix_token = p;
328 return *this;
329 }
330
331 char
GetPrefixToken() const332 GetPrefixToken () const
333 {
334 return m_prefix_token;
335 }
336
337 ReadUTFBufferAndDumpToStreamOptions&
SetQuote(char q)338 SetQuote (char q)
339 {
340 m_quote = q;
341 return *this;
342 }
343
344 char
GetQuote() const345 GetQuote () const
346 {
347 return m_quote;
348 }
349
350 ReadUTFBufferAndDumpToStreamOptions&
SetSourceSize(uint32_t s)351 SetSourceSize (uint32_t s)
352 {
353 m_source_size = s;
354 return *this;
355 }
356
357 uint32_t
GetSourceSize() const358 GetSourceSize () const
359 {
360 return m_source_size;
361 }
362
363 ReadUTFBufferAndDumpToStreamOptions&
SetNeedsZeroTermination(bool z)364 SetNeedsZeroTermination (bool z)
365 {
366 m_needs_zero_termination = z;
367 return *this;
368 }
369
370 bool
GetNeedsZeroTermination() const371 GetNeedsZeroTermination () const
372 {
373 return m_needs_zero_termination;
374 }
375
376 private:
377 ConvertFunctionType m_conversion_function;
378 uint64_t m_location;
379 ProcessSP m_process_sp;
380 Stream* m_stream;
381 char m_prefix_token;
382 char m_quote;
383 uint32_t m_source_size;
384 bool m_needs_zero_termination;
385 };
386
387 template<typename SourceDataType>
388 static bool
ReadUTFBufferAndDumpToStream(const ReadUTFBufferAndDumpToStreamOptions<SourceDataType> & options)389 ReadUTFBufferAndDumpToStream (const ReadUTFBufferAndDumpToStreamOptions<SourceDataType>& options)
390 {
391 if (options.GetLocation() == 0 || options.GetLocation() == LLDB_INVALID_ADDRESS)
392 return false;
393
394 ProcessSP process_sp(options.GetProcessSP());
395
396 if (!process_sp)
397 return false;
398
399 const int type_width = sizeof(SourceDataType);
400 const int origin_encoding = 8 * type_width ;
401 if (origin_encoding != 8 && origin_encoding != 16 && origin_encoding != 32)
402 return false;
403 // if not UTF8, I need a conversion function to return proper UTF8
404 if (origin_encoding != 8 && !options.GetConversionFunction())
405 return false;
406
407 if (!options.GetStream())
408 return false;
409
410 uint32_t sourceSize = options.GetSourceSize();
411 bool needs_zero_terminator = options.GetNeedsZeroTermination();
412
413 if (!sourceSize)
414 {
415 sourceSize = process_sp->GetTarget().GetMaximumSizeOfStringSummary();
416 needs_zero_terminator = true;
417 }
418 else
419 sourceSize = std::min(sourceSize,process_sp->GetTarget().GetMaximumSizeOfStringSummary());
420
421 const int bufferSPSize = sourceSize * type_width;
422
423 lldb::DataBufferSP buffer_sp(new DataBufferHeap(bufferSPSize,0));
424
425 if (!buffer_sp->GetBytes())
426 return false;
427
428 Error error;
429 char *buffer = reinterpret_cast<char *>(buffer_sp->GetBytes());
430
431 size_t data_read = 0;
432 if (needs_zero_terminator)
433 data_read = process_sp->ReadStringFromMemory(options.GetLocation(), buffer, bufferSPSize, error, type_width);
434 else
435 data_read = process_sp->ReadMemoryFromInferior(options.GetLocation(), (char*)buffer_sp->GetBytes(), bufferSPSize, error);
436
437 if (error.Fail() || data_read == 0)
438 {
439 options.GetStream()->Printf("unable to read data");
440 return true;
441 }
442
443 DataExtractor data(buffer_sp, process_sp->GetByteOrder(), process_sp->GetAddressByteSize());
444
445 return DumpUTFBufferToStream(options.GetConversionFunction(), data, *options.GetStream(), options.GetPrefixToken(), options.GetQuote(), sourceSize);
446 }
447
448 bool
Char16StringSummaryProvider(ValueObject & valobj,Stream & stream)449 lldb_private::formatters::Char16StringSummaryProvider (ValueObject& valobj, Stream& stream)
450 {
451 ProcessSP process_sp = valobj.GetProcessSP();
452 if (!process_sp)
453 return false;
454
455 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
456
457 if (!valobj_addr)
458 return false;
459
460 ReadUTFBufferAndDumpToStreamOptions<UTF16> options;
461 options.SetLocation(valobj_addr);
462 options.SetConversionFunction(ConvertUTF16toUTF8);
463 options.SetProcessSP(process_sp);
464 options.SetStream(&stream);
465 options.SetPrefixToken('u');
466
467 if (!ReadUTFBufferAndDumpToStream(options))
468 {
469 stream.Printf("Summary Unavailable");
470 return true;
471 }
472
473 return true;
474 }
475
476 bool
Char32StringSummaryProvider(ValueObject & valobj,Stream & stream)477 lldb_private::formatters::Char32StringSummaryProvider (ValueObject& valobj, Stream& stream)
478 {
479 ProcessSP process_sp = valobj.GetProcessSP();
480 if (!process_sp)
481 return false;
482
483 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
484
485 if (!valobj_addr)
486 return false;
487
488 ReadUTFBufferAndDumpToStreamOptions<UTF32> options;
489 options.SetLocation(valobj_addr);
490 options.SetConversionFunction(ConvertUTF32toUTF8);
491 options.SetProcessSP(process_sp);
492 options.SetStream(&stream);
493 options.SetPrefixToken('U');
494
495 if (!ReadUTFBufferAndDumpToStream(options))
496 {
497 stream.Printf("Summary Unavailable");
498 return true;
499 }
500
501 return true;
502 }
503
504 bool
WCharStringSummaryProvider(ValueObject & valobj,Stream & stream)505 lldb_private::formatters::WCharStringSummaryProvider (ValueObject& valobj, Stream& stream)
506 {
507 ProcessSP process_sp = valobj.GetProcessSP();
508 if (!process_sp)
509 return false;
510
511 lldb::addr_t data_addr = 0;
512
513 if (valobj.IsPointerType())
514 data_addr = valobj.GetValueAsUnsigned(0);
515 else if (valobj.IsArrayType())
516 data_addr = valobj.GetAddressOf();
517
518 if (data_addr == 0 || data_addr == LLDB_INVALID_ADDRESS)
519 return false;
520
521 clang::ASTContext* ast = valobj.GetClangType().GetASTContext();
522
523 if (!ast)
524 return false;
525
526 ClangASTType wchar_clang_type = ClangASTContext::GetBasicType(ast, lldb::eBasicTypeWChar);
527 const uint32_t wchar_size = wchar_clang_type.GetBitSize();
528
529 switch (wchar_size)
530 {
531 case 8:
532 {
533 // utf 8
534
535 ReadUTFBufferAndDumpToStreamOptions<UTF8> options;
536 options.SetLocation(data_addr);
537 options.SetConversionFunction(nullptr);
538 options.SetProcessSP(process_sp);
539 options.SetStream(&stream);
540 options.SetPrefixToken('L');
541
542 return ReadUTFBufferAndDumpToStream(options);
543 }
544 case 16:
545 {
546 // utf 16
547 ReadUTFBufferAndDumpToStreamOptions<UTF16> options;
548 options.SetLocation(data_addr);
549 options.SetConversionFunction(ConvertUTF16toUTF8);
550 options.SetProcessSP(process_sp);
551 options.SetStream(&stream);
552 options.SetPrefixToken('L');
553
554 return ReadUTFBufferAndDumpToStream(options);
555 }
556 case 32:
557 {
558 // utf 32
559 ReadUTFBufferAndDumpToStreamOptions<UTF32> options;
560 options.SetLocation(data_addr);
561 options.SetConversionFunction(ConvertUTF32toUTF8);
562 options.SetProcessSP(process_sp);
563 options.SetStream(&stream);
564 options.SetPrefixToken('L');
565
566 return ReadUTFBufferAndDumpToStream(options);
567 }
568 default:
569 stream.Printf("size for wchar_t is not valid");
570 return true;
571 }
572 return true;
573 }
574
575 bool
Char16SummaryProvider(ValueObject & valobj,Stream & stream)576 lldb_private::formatters::Char16SummaryProvider (ValueObject& valobj, Stream& stream)
577 {
578 DataExtractor data;
579 valobj.GetData(data);
580
581 std::string value;
582 valobj.GetValueAsCString(lldb::eFormatUnicode16, value);
583 if (!value.empty())
584 stream.Printf("%s ", value.c_str());
585
586 return DumpUTFBufferToStream<UTF16>(ConvertUTF16toUTF8,data,stream, 'u','\'',1);
587 }
588
589 bool
Char32SummaryProvider(ValueObject & valobj,Stream & stream)590 lldb_private::formatters::Char32SummaryProvider (ValueObject& valobj, Stream& stream)
591 {
592 DataExtractor data;
593 valobj.GetData(data);
594
595 std::string value;
596 valobj.GetValueAsCString(lldb::eFormatUnicode32, value);
597 if (!value.empty())
598 stream.Printf("%s ", value.c_str());
599
600 return DumpUTFBufferToStream<UTF32>(ConvertUTF32toUTF8,data,stream, 'U','\'',1);
601 }
602
603 bool
WCharSummaryProvider(ValueObject & valobj,Stream & stream)604 lldb_private::formatters::WCharSummaryProvider (ValueObject& valobj, Stream& stream)
605 {
606 DataExtractor data;
607 valobj.GetData(data);
608
609 clang::ASTContext* ast = valobj.GetClangType().GetASTContext();
610
611 if (!ast)
612 return false;
613
614 ClangASTType wchar_clang_type = ClangASTContext::GetBasicType(ast, lldb::eBasicTypeWChar);
615 const uint32_t wchar_size = wchar_clang_type.GetBitSize();
616 std::string value;
617
618 switch (wchar_size)
619 {
620 case 8:
621 // utf 8
622 valobj.GetValueAsCString(lldb::eFormatChar, value);
623 if (!value.empty())
624 stream.Printf("%s ", value.c_str());
625 return DumpUTFBufferToStream<UTF8>(nullptr,
626 data,
627 stream,
628 'L',
629 '\'',
630 1);
631 case 16:
632 // utf 16
633 valobj.GetValueAsCString(lldb::eFormatUnicode16, value);
634 if (!value.empty())
635 stream.Printf("%s ", value.c_str());
636 return DumpUTFBufferToStream<UTF16>(ConvertUTF16toUTF8,
637 data,
638 stream,
639 'L',
640 '\'',
641 1);
642 case 32:
643 // utf 32
644 valobj.GetValueAsCString(lldb::eFormatUnicode32, value);
645 if (!value.empty())
646 stream.Printf("%s ", value.c_str());
647 return DumpUTFBufferToStream<UTF32>(ConvertUTF32toUTF8,
648 data,
649 stream,
650 'L',
651 '\'',
652 1);
653 default:
654 stream.Printf("size for wchar_t is not valid");
655 return true;
656 }
657 return true;
658 }
659
660 // the field layout in a libc++ string (cap, side, data or data, size, cap)
661 enum LibcxxStringLayoutMode
662 {
663 eLibcxxStringLayoutModeCSD = 0,
664 eLibcxxStringLayoutModeDSC = 1,
665 eLibcxxStringLayoutModeInvalid = 0xffff
666 };
667
668 // this function abstracts away the layout and mode details of a libc++ string
669 // and returns the address of the data and the size ready for callers to consume
670 static bool
ExtractLibcxxStringInfo(ValueObject & valobj,ValueObjectSP & location_sp,uint64_t & size)671 ExtractLibcxxStringInfo (ValueObject& valobj,
672 ValueObjectSP &location_sp,
673 uint64_t& size)
674 {
675 ValueObjectSP D(valobj.GetChildAtIndexPath({0,0,0,0}));
676 if (!D)
677 return false;
678
679 ValueObjectSP layout_decider(D->GetChildAtIndexPath({0,0}));
680
681 // this child should exist
682 if (!layout_decider)
683 return false;
684
685 ConstString g_data_name("__data_");
686 ConstString g_size_name("__size_");
687 bool short_mode = false; // this means the string is in short-mode and the data is stored inline
688 LibcxxStringLayoutMode layout = (layout_decider->GetName() == g_data_name) ? eLibcxxStringLayoutModeDSC : eLibcxxStringLayoutModeCSD;
689 uint64_t size_mode_value = 0;
690
691 if (layout == eLibcxxStringLayoutModeDSC)
692 {
693 ValueObjectSP size_mode(D->GetChildAtIndexPath({1,1,0}));
694 if (!size_mode)
695 return false;
696
697 if (size_mode->GetName() != g_size_name)
698 {
699 // we are hitting the padding structure, move along
700 size_mode = D->GetChildAtIndexPath({1,1,1});
701 if (!size_mode)
702 return false;
703 }
704
705 size_mode_value = (size_mode->GetValueAsUnsigned(0));
706 short_mode = ((size_mode_value & 0x80) == 0);
707 }
708 else
709 {
710 ValueObjectSP size_mode(D->GetChildAtIndexPath({1,0,0}));
711 if (!size_mode)
712 return false;
713
714 size_mode_value = (size_mode->GetValueAsUnsigned(0));
715 short_mode = ((size_mode_value & 1) == 0);
716 }
717
718 if (short_mode)
719 {
720 ValueObjectSP s(D->GetChildAtIndex(1, true));
721 if (!s)
722 return false;
723 location_sp = s->GetChildAtIndex((layout == eLibcxxStringLayoutModeDSC) ? 0 : 1, true);
724 size = (layout == eLibcxxStringLayoutModeDSC) ? size_mode_value : ((size_mode_value >> 1) % 256);
725 return (location_sp.get() != nullptr);
726 }
727 else
728 {
729 ValueObjectSP l(D->GetChildAtIndex(0, true));
730 if (!l)
731 return false;
732 // we can use the layout_decider object as the data pointer
733 location_sp = (layout == eLibcxxStringLayoutModeDSC) ? layout_decider : l->GetChildAtIndex(2, true);
734 ValueObjectSP size_vo(l->GetChildAtIndex(1, true));
735 if (!size_vo || !location_sp)
736 return false;
737 size = size_vo->GetValueAsUnsigned(0);
738 return true;
739 }
740 }
741
742 bool
LibcxxWStringSummaryProvider(ValueObject & valobj,Stream & stream)743 lldb_private::formatters::LibcxxWStringSummaryProvider (ValueObject& valobj, Stream& stream)
744 {
745 uint64_t size = 0;
746 ValueObjectSP location_sp((ValueObject*)nullptr);
747 if (!ExtractLibcxxStringInfo(valobj, location_sp, size))
748 return false;
749 if (size == 0)
750 {
751 stream.Printf("L\"\"");
752 return true;
753 }
754 if (!location_sp)
755 return false;
756 return WCharStringSummaryProvider(*location_sp.get(), stream);
757 }
758
759 bool
LibcxxStringSummaryProvider(ValueObject & valobj,Stream & stream)760 lldb_private::formatters::LibcxxStringSummaryProvider (ValueObject& valobj, Stream& stream)
761 {
762 uint64_t size = 0;
763 ValueObjectSP location_sp((ValueObject*)nullptr);
764 if (!ExtractLibcxxStringInfo(valobj, location_sp, size))
765 return false;
766 if (size == 0)
767 {
768 stream.Printf("\"\"");
769 return true;
770 }
771 if (!location_sp)
772 return false;
773 Error error;
774 if (location_sp->ReadPointedString(stream,
775 error,
776 0, // max length is decided by the settings
777 false) == 0) // do not honor array (terminates on first 0 byte even for a char[])
778 stream.Printf("\"\""); // if nothing was read, print an empty string
779 return error.Success();
780 }
781
782 bool
ObjCClassSummaryProvider(ValueObject & valobj,Stream & stream)783 lldb_private::formatters::ObjCClassSummaryProvider (ValueObject& valobj, Stream& stream)
784 {
785 ProcessSP process_sp = valobj.GetProcessSP();
786 if (!process_sp)
787 return false;
788
789 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
790
791 if (!runtime)
792 return false;
793
794 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptorFromISA(valobj.GetValueAsUnsigned(0)));
795
796 if (!descriptor.get() || !descriptor->IsValid())
797 return false;
798
799 const char* class_name = descriptor->GetClassName().GetCString();
800
801 if (!class_name || !*class_name)
802 return false;
803
804 stream.Printf("%s",class_name);
805 return true;
806 }
807
808 class ObjCClassSyntheticChildrenFrontEnd : public SyntheticChildrenFrontEnd
809 {
810 public:
ObjCClassSyntheticChildrenFrontEnd(lldb::ValueObjectSP valobj_sp)811 ObjCClassSyntheticChildrenFrontEnd (lldb::ValueObjectSP valobj_sp) :
812 SyntheticChildrenFrontEnd(*valobj_sp.get())
813 {
814 }
815
816 virtual size_t
CalculateNumChildren()817 CalculateNumChildren ()
818 {
819 return 0;
820 }
821
822 virtual lldb::ValueObjectSP
GetChildAtIndex(size_t idx)823 GetChildAtIndex (size_t idx)
824 {
825 return lldb::ValueObjectSP();
826 }
827
828 virtual bool
Update()829 Update()
830 {
831 return false;
832 }
833
834 virtual bool
MightHaveChildren()835 MightHaveChildren ()
836 {
837 return false;
838 }
839
840 virtual size_t
GetIndexOfChildWithName(const ConstString & name)841 GetIndexOfChildWithName (const ConstString &name)
842 {
843 return UINT32_MAX;
844 }
845
846 virtual
~ObjCClassSyntheticChildrenFrontEnd()847 ~ObjCClassSyntheticChildrenFrontEnd ()
848 {
849 }
850 };
851
852 SyntheticChildrenFrontEnd*
ObjCClassSyntheticFrontEndCreator(CXXSyntheticChildren *,lldb::ValueObjectSP valobj_sp)853 lldb_private::formatters::ObjCClassSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
854 {
855 return new ObjCClassSyntheticChildrenFrontEnd(valobj_sp);
856 }
857
858 template<bool needs_at>
859 bool
NSDataSummaryProvider(ValueObject & valobj,Stream & stream)860 lldb_private::formatters::NSDataSummaryProvider (ValueObject& valobj, Stream& stream)
861 {
862 ProcessSP process_sp = valobj.GetProcessSP();
863 if (!process_sp)
864 return false;
865
866 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
867
868 if (!runtime)
869 return false;
870
871 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
872
873 if (!descriptor.get() || !descriptor->IsValid())
874 return false;
875
876 bool is_64bit = (process_sp->GetAddressByteSize() == 8);
877 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
878
879 if (!valobj_addr)
880 return false;
881
882 uint64_t value = 0;
883
884 const char* class_name = descriptor->GetClassName().GetCString();
885
886 if (!class_name || !*class_name)
887 return false;
888
889 if (!strcmp(class_name,"NSConcreteData") ||
890 !strcmp(class_name,"NSConcreteMutableData") ||
891 !strcmp(class_name,"__NSCFData"))
892 {
893 uint32_t offset = (is_64bit ? 16 : 8);
894 Error error;
895 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + offset, is_64bit ? 8 : 4, 0, error);
896 if (error.Fail())
897 return false;
898 }
899 else
900 {
901 if (!ExtractValueFromObjCExpression(valobj, "int", "length", value))
902 return false;
903 }
904
905 stream.Printf("%s%" PRIu64 " byte%s%s",
906 (needs_at ? "@\"" : ""),
907 value,
908 (value != 1 ? "s" : ""),
909 (needs_at ? "\"" : ""));
910
911 return true;
912 }
913
914 static bool
ReadAsciiBufferAndDumpToStream(lldb::addr_t location,lldb::ProcessSP & process_sp,Stream & dest,uint32_t size=0,Error * error=NULL,size_t * data_read=NULL,char prefix_token='@',char quote='"')915 ReadAsciiBufferAndDumpToStream (lldb::addr_t location,
916 lldb::ProcessSP& process_sp,
917 Stream& dest,
918 uint32_t size = 0,
919 Error* error = NULL,
920 size_t *data_read = NULL,
921 char prefix_token = '@',
922 char quote = '"')
923 {
924 Error my_error;
925 size_t my_data_read;
926 if (!process_sp || location == 0)
927 return false;
928
929 if (!size)
930 size = process_sp->GetTarget().GetMaximumSizeOfStringSummary();
931 else
932 size = std::min(size,process_sp->GetTarget().GetMaximumSizeOfStringSummary());
933
934 lldb::DataBufferSP buffer_sp(new DataBufferHeap(size,0));
935
936 my_data_read = process_sp->ReadCStringFromMemory(location, (char*)buffer_sp->GetBytes(), size, my_error);
937
938 if (error)
939 *error = my_error;
940 if (data_read)
941 *data_read = my_data_read;
942
943 if (my_error.Fail())
944 return false;
945
946 dest.Printf("%c%c",prefix_token,quote);
947
948 if (my_data_read)
949 dest.Printf("%s",(char*)buffer_sp->GetBytes());
950
951 dest.Printf("%c",quote);
952
953 return true;
954 }
955
956 bool
NSStringSummaryProvider(ValueObject & valobj,Stream & stream)957 lldb_private::formatters::NSStringSummaryProvider (ValueObject& valobj, Stream& stream)
958 {
959 ProcessSP process_sp = valobj.GetProcessSP();
960 if (!process_sp)
961 return false;
962
963 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC);
964
965 if (!runtime)
966 return false;
967
968 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj));
969
970 if (!descriptor.get() || !descriptor->IsValid())
971 return false;
972
973 uint32_t ptr_size = process_sp->GetAddressByteSize();
974
975 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0);
976
977 if (!valobj_addr)
978 return false;
979
980 const char* class_name = descriptor->GetClassName().GetCString();
981
982 if (!class_name || !*class_name)
983 return false;
984
985 uint64_t info_bits_location = valobj_addr + ptr_size;
986 if (process_sp->GetByteOrder() != lldb::eByteOrderLittle)
987 info_bits_location += 3;
988
989 Error error;
990
991 uint8_t info_bits = process_sp->ReadUnsignedIntegerFromMemory(info_bits_location, 1, 0, error);
992 if (error.Fail())
993 return false;
994
995 bool is_mutable = (info_bits & 1) == 1;
996 bool is_inline = (info_bits & 0x60) == 0;
997 bool has_explicit_length = (info_bits & (1 | 4)) != 4;
998 bool is_unicode = (info_bits & 0x10) == 0x10;
999 bool is_special = strcmp(class_name,"NSPathStore2") == 0;
1000 bool has_null = (info_bits & 8) == 8;
1001
1002 size_t explicit_length = 0;
1003 if (!has_null && has_explicit_length && !is_special)
1004 {
1005 lldb::addr_t explicit_length_offset = 2*ptr_size;
1006 if (is_mutable and not is_inline)
1007 explicit_length_offset = explicit_length_offset + ptr_size; // notInlineMutable.length;
1008 else if (is_inline)
1009 explicit_length = explicit_length + 0; // inline1.length;
1010 else if (not is_inline and not is_mutable)
1011 explicit_length_offset = explicit_length_offset + ptr_size; // notInlineImmutable1.length;
1012 else
1013 explicit_length_offset = 0;
1014
1015 if (explicit_length_offset)
1016 {
1017 explicit_length_offset = valobj_addr + explicit_length_offset;
1018 explicit_length = process_sp->ReadUnsignedIntegerFromMemory(explicit_length_offset, 4, 0, error);
1019 }
1020 }
1021
1022 if (strcmp(class_name,"NSString") &&
1023 strcmp(class_name,"CFStringRef") &&
1024 strcmp(class_name,"CFMutableStringRef") &&
1025 strcmp(class_name,"__NSCFConstantString") &&
1026 strcmp(class_name,"__NSCFString") &&
1027 strcmp(class_name,"NSCFConstantString") &&
1028 strcmp(class_name,"NSCFString") &&
1029 strcmp(class_name,"NSPathStore2"))
1030 {
1031 // not one of us - but tell me class name
1032 stream.Printf("class name = %s",class_name);
1033 return true;
1034 }
1035
1036 if (is_mutable)
1037 {
1038 uint64_t location = 2 * ptr_size + valobj_addr;
1039 location = process_sp->ReadPointerFromMemory(location, error);
1040 if (error.Fail())
1041 return false;
1042 if (has_explicit_length and is_unicode)
1043 {
1044 ReadUTFBufferAndDumpToStreamOptions<UTF16> options;
1045 options.SetConversionFunction(ConvertUTF16toUTF8);
1046 options.SetLocation(location);
1047 options.SetProcessSP(process_sp);
1048 options.SetStream(&stream);
1049 options.SetPrefixToken('@');
1050 options.SetQuote('"');
1051 options.SetSourceSize(explicit_length);
1052 options.SetNeedsZeroTermination(false);
1053 return ReadUTFBufferAndDumpToStream (options);
1054 }
1055 else
1056 return ReadAsciiBufferAndDumpToStream(location+1,process_sp,stream, explicit_length);
1057 }
1058 else if (is_inline && has_explicit_length && !is_unicode && !is_special && !is_mutable)
1059 {
1060 uint64_t location = 3 * ptr_size + valobj_addr;
1061 return ReadAsciiBufferAndDumpToStream(location,process_sp,stream,explicit_length);
1062 }
1063 else if (is_unicode)
1064 {
1065 uint64_t location = valobj_addr + 2*ptr_size;
1066 if (is_inline)
1067 {
1068 if (!has_explicit_length)
1069 {
1070 stream.Printf("found new combo");
1071 return true;
1072 }
1073 else
1074 location += ptr_size;
1075 }
1076 else
1077 {
1078 location = process_sp->ReadPointerFromMemory(location, error);
1079 if (error.Fail())
1080 return false;
1081 }
1082 ReadUTFBufferAndDumpToStreamOptions<UTF16> options;
1083 options.SetConversionFunction(ConvertUTF16toUTF8);
1084 options.SetLocation(location);
1085 options.SetProcessSP(process_sp);
1086 options.SetStream(&stream);
1087 options.SetPrefixToken('@');
1088 options.SetQuote('"');
1089 options.SetSourceSize(explicit_length);
1090 options.SetNeedsZeroTermination(has_explicit_length == false);
1091 return ReadUTFBufferAndDumpToStream (options);
1092 }
1093 else if (is_special)
1094 {
1095 uint64_t location = valobj_addr + (ptr_size == 8 ? 12 : 8);
1096 ReadUTFBufferAndDumpToStreamOptions<UTF16> options;
1097 options.SetConversionFunction(ConvertUTF16toUTF8);
1098 options.SetLocation(location);
1099 options.SetProcessSP(process_sp);
1100 options.SetStream(&stream);
1101 options.SetPrefixToken('@');
1102 options.SetQuote('"');
1103 options.SetSourceSize(explicit_length);
1104 options.SetNeedsZeroTermination(has_explicit_length == false);
1105 return ReadUTFBufferAndDumpToStream (options);
1106 }
1107 else if (is_inline)
1108 {
1109 uint64_t location = valobj_addr + 2*ptr_size;
1110 if (!has_explicit_length)
1111 location++;
1112 return ReadAsciiBufferAndDumpToStream(location,process_sp,stream,explicit_length);
1113 }
1114 else
1115 {
1116 uint64_t location = valobj_addr + 2*ptr_size;
1117 location = process_sp->ReadPointerFromMemory(location, error);
1118 if (error.Fail())
1119 return false;
1120 if (has_explicit_length && !has_null)
1121 explicit_length++; // account for the fact that there is no NULL and we need to have one added
1122 return ReadAsciiBufferAndDumpToStream(location,process_sp,stream,explicit_length);
1123 }
1124
1125 stream.Printf("class name = %s",class_name);
1126 return true;
1127
1128 }
1129
1130 bool
NSAttributedStringSummaryProvider(ValueObject & valobj,Stream & stream)1131 lldb_private::formatters::NSAttributedStringSummaryProvider (ValueObject& valobj, Stream& stream)
1132 {
1133 TargetSP target_sp(valobj.GetTargetSP());
1134 if (!target_sp)
1135 return false;
1136 uint32_t addr_size = target_sp->GetArchitecture().GetAddressByteSize();
1137 uint64_t pointer_value = valobj.GetValueAsUnsigned(0);
1138 if (!pointer_value)
1139 return false;
1140 pointer_value += addr_size;
1141 ClangASTType type(valobj.GetClangType());
1142 ExecutionContext exe_ctx(target_sp,false);
1143 ValueObjectSP child_ptr_sp(valobj.CreateValueObjectFromAddress("string_ptr", pointer_value, exe_ctx, type));
1144 if (!child_ptr_sp)
1145 return false;
1146 DataExtractor data;
1147 child_ptr_sp->GetData(data);
1148 ValueObjectSP child_sp(child_ptr_sp->CreateValueObjectFromData("string_data", data, exe_ctx, type));
1149 child_sp->GetValueAsUnsigned(0);
1150 if (child_sp)
1151 return NSStringSummaryProvider(*child_sp, stream);
1152 return false;
1153 }
1154
1155 bool
NSMutableAttributedStringSummaryProvider(ValueObject & valobj,Stream & stream)1156 lldb_private::formatters::NSMutableAttributedStringSummaryProvider (ValueObject& valobj, Stream& stream)
1157 {
1158 return NSAttributedStringSummaryProvider(valobj, stream);
1159 }
1160
1161 bool
RuntimeSpecificDescriptionSummaryProvider(ValueObject & valobj,Stream & stream)1162 lldb_private::formatters::RuntimeSpecificDescriptionSummaryProvider (ValueObject& valobj, Stream& stream)
1163 {
1164 stream.Printf("%s",valobj.GetObjectDescription());
1165 return true;
1166 }
1167
1168 bool
ObjCBOOLSummaryProvider(ValueObject & valobj,Stream & stream)1169 lldb_private::formatters::ObjCBOOLSummaryProvider (ValueObject& valobj, Stream& stream)
1170 {
1171 const uint32_t type_info = valobj.GetClangType().GetTypeInfo();
1172
1173 ValueObjectSP real_guy_sp = valobj.GetSP();
1174
1175 if (type_info & ClangASTType::eTypeIsPointer)
1176 {
1177 Error err;
1178 real_guy_sp = valobj.Dereference(err);
1179 if (err.Fail() || !real_guy_sp)
1180 return false;
1181 }
1182 else if (type_info & ClangASTType::eTypeIsReference)
1183 {
1184 real_guy_sp = valobj.GetChildAtIndex(0, true);
1185 if (!real_guy_sp)
1186 return false;
1187 }
1188 uint64_t value = real_guy_sp->GetValueAsUnsigned(0);
1189 if (value == 0)
1190 {
1191 stream.Printf("NO");
1192 return true;
1193 }
1194 stream.Printf("YES");
1195 return true;
1196 }
1197
1198 template <bool is_sel_ptr>
1199 bool
ObjCSELSummaryProvider(ValueObject & valobj,Stream & stream)1200 lldb_private::formatters::ObjCSELSummaryProvider (ValueObject& valobj, Stream& stream)
1201 {
1202 lldb::ValueObjectSP valobj_sp;
1203
1204 ClangASTType charstar (valobj.GetClangType().GetBasicTypeFromAST(eBasicTypeChar).GetPointerType());
1205
1206 if (!charstar)
1207 return false;
1208
1209 ExecutionContext exe_ctx(valobj.GetExecutionContextRef());
1210
1211 if (is_sel_ptr)
1212 {
1213 lldb::addr_t data_address = valobj.GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
1214 if (data_address == LLDB_INVALID_ADDRESS)
1215 return false;
1216 valobj_sp = ValueObject::CreateValueObjectFromAddress("text", data_address, exe_ctx, charstar);
1217 }
1218 else
1219 {
1220 DataExtractor data;
1221 valobj.GetData(data);
1222 valobj_sp = ValueObject::CreateValueObjectFromData("text", data, exe_ctx, charstar);
1223 }
1224
1225 if (!valobj_sp)
1226 return false;
1227
1228 stream.Printf("%s",valobj_sp->GetSummaryAsCString());
1229 return true;
1230 }
1231
1232 // POSIX has an epoch on Jan-1-1970, but Cocoa prefers Jan-1-2001
1233 // this call gives the POSIX equivalent of the Cocoa epoch
1234 time_t
GetOSXEpoch()1235 lldb_private::formatters::GetOSXEpoch ()
1236 {
1237 static time_t epoch = 0;
1238 if (!epoch)
1239 {
1240 tzset();
1241 tm tm_epoch;
1242 tm_epoch.tm_sec = 0;
1243 tm_epoch.tm_hour = 0;
1244 tm_epoch.tm_min = 0;
1245 tm_epoch.tm_mon = 0;
1246 tm_epoch.tm_mday = 1;
1247 tm_epoch.tm_year = 2001-1900; // for some reason, we need to subtract 1900 from this field. not sure why.
1248 tm_epoch.tm_isdst = -1;
1249 tm_epoch.tm_gmtoff = 0;
1250 tm_epoch.tm_zone = NULL;
1251 epoch = timegm(&tm_epoch);
1252 }
1253 return epoch;
1254 }
1255
1256 size_t
ExtractIndexFromString(const char * item_name)1257 lldb_private::formatters::ExtractIndexFromString (const char* item_name)
1258 {
1259 if (!item_name || !*item_name)
1260 return UINT32_MAX;
1261 if (*item_name != '[')
1262 return UINT32_MAX;
1263 item_name++;
1264 char* endptr = NULL;
1265 unsigned long int idx = ::strtoul(item_name, &endptr, 0);
1266 if (idx == 0 && endptr == item_name)
1267 return UINT32_MAX;
1268 if (idx == ULONG_MAX)
1269 return UINT32_MAX;
1270 return idx;
1271 }
1272
VectorIteratorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp,ConstString item_name)1273 lldb_private::formatters::VectorIteratorSyntheticFrontEnd::VectorIteratorSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp,
1274 ConstString item_name) :
1275 SyntheticChildrenFrontEnd(*valobj_sp.get()),
1276 m_exe_ctx_ref(),
1277 m_item_name(item_name),
1278 m_item_sp()
1279 {
1280 if (valobj_sp)
1281 Update();
1282 }
1283
1284 bool
Update()1285 lldb_private::formatters::VectorIteratorSyntheticFrontEnd::Update()
1286 {
1287 m_item_sp.reset();
1288
1289 ValueObjectSP valobj_sp = m_backend.GetSP();
1290 if (!valobj_sp)
1291 return false;
1292
1293 if (!valobj_sp)
1294 return false;
1295
1296 ValueObjectSP item_ptr(valobj_sp->GetChildMemberWithName(m_item_name,true));
1297 if (!item_ptr)
1298 return false;
1299 if (item_ptr->GetValueAsUnsigned(0) == 0)
1300 return false;
1301 Error err;
1302 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef();
1303 m_item_sp = ValueObject::CreateValueObjectFromAddress("item", item_ptr->GetValueAsUnsigned(0), m_exe_ctx_ref, item_ptr->GetClangType().GetPointeeType());
1304 if (err.Fail())
1305 m_item_sp.reset();
1306 return false;
1307 }
1308
1309 size_t
CalculateNumChildren()1310 lldb_private::formatters::VectorIteratorSyntheticFrontEnd::CalculateNumChildren ()
1311 {
1312 return 1;
1313 }
1314
1315 lldb::ValueObjectSP
GetChildAtIndex(size_t idx)1316 lldb_private::formatters::VectorIteratorSyntheticFrontEnd::GetChildAtIndex (size_t idx)
1317 {
1318 if (idx == 0)
1319 return m_item_sp;
1320 return lldb::ValueObjectSP();
1321 }
1322
1323 bool
MightHaveChildren()1324 lldb_private::formatters::VectorIteratorSyntheticFrontEnd::MightHaveChildren ()
1325 {
1326 return true;
1327 }
1328
1329 size_t
GetIndexOfChildWithName(const ConstString & name)1330 lldb_private::formatters::VectorIteratorSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name)
1331 {
1332 if (name == ConstString("item"))
1333 return 0;
1334 return UINT32_MAX;
1335 }
1336
~VectorIteratorSyntheticFrontEnd()1337 lldb_private::formatters::VectorIteratorSyntheticFrontEnd::~VectorIteratorSyntheticFrontEnd ()
1338 {
1339 }
1340
1341 template bool
1342 lldb_private::formatters::NSDataSummaryProvider<true> (ValueObject&, Stream&) ;
1343
1344 template bool
1345 lldb_private::formatters::NSDataSummaryProvider<false> (ValueObject&, Stream&) ;
1346
1347 template bool
1348 lldb_private::formatters::ObjCSELSummaryProvider<true> (ValueObject&, Stream&) ;
1349
1350 template bool
1351 lldb_private::formatters::ObjCSELSummaryProvider<false> (ValueObject&, Stream&) ;
1352