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