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