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 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 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 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 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 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 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& 273 SetConversionFunction (ConvertFunctionType f) 274 { 275 m_conversion_function = f; 276 return *this; 277 } 278 279 ConvertFunctionType 280 GetConversionFunction () const 281 { 282 return m_conversion_function; 283 } 284 285 ReadUTFBufferAndDumpToStreamOptions& 286 SetLocation (uint64_t l) 287 { 288 m_location = l; 289 return *this; 290 } 291 292 uint64_t 293 GetLocation () const 294 { 295 return m_location; 296 } 297 298 ReadUTFBufferAndDumpToStreamOptions& 299 SetProcessSP (ProcessSP p) 300 { 301 m_process_sp = p; 302 return *this; 303 } 304 305 ProcessSP 306 GetProcessSP () const 307 { 308 return m_process_sp; 309 } 310 311 ReadUTFBufferAndDumpToStreamOptions& 312 SetStream (Stream* s) 313 { 314 m_stream = s; 315 return *this; 316 } 317 318 Stream* 319 GetStream () const 320 { 321 return m_stream; 322 } 323 324 ReadUTFBufferAndDumpToStreamOptions& 325 SetPrefixToken (char p) 326 { 327 m_prefix_token = p; 328 return *this; 329 } 330 331 char 332 GetPrefixToken () const 333 { 334 return m_prefix_token; 335 } 336 337 ReadUTFBufferAndDumpToStreamOptions& 338 SetQuote (char q) 339 { 340 m_quote = q; 341 return *this; 342 } 343 344 char 345 GetQuote () const 346 { 347 return m_quote; 348 } 349 350 ReadUTFBufferAndDumpToStreamOptions& 351 SetSourceSize (uint32_t s) 352 { 353 m_source_size = s; 354 return *this; 355 } 356 357 uint32_t 358 GetSourceSize () const 359 { 360 return m_source_size; 361 } 362 363 ReadUTFBufferAndDumpToStreamOptions& 364 SetNeedsZeroTermination (bool z) 365 { 366 m_needs_zero_termination = z; 367 return *this; 368 } 369 370 bool 371 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 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 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 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 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 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 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 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 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 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 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 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: 811 ObjCClassSyntheticChildrenFrontEnd (lldb::ValueObjectSP valobj_sp) : 812 SyntheticChildrenFrontEnd(*valobj_sp.get()) 813 { 814 } 815 816 virtual size_t 817 CalculateNumChildren () 818 { 819 return 0; 820 } 821 822 virtual lldb::ValueObjectSP 823 GetChildAtIndex (size_t idx) 824 { 825 return lldb::ValueObjectSP(); 826 } 827 828 virtual bool 829 Update() 830 { 831 return false; 832 } 833 834 virtual bool 835 MightHaveChildren () 836 { 837 return false; 838 } 839 840 virtual size_t 841 GetIndexOfChildWithName (const ConstString &name) 842 { 843 return UINT32_MAX; 844 } 845 846 virtual 847 ~ObjCClassSyntheticChildrenFrontEnd () 848 { 849 } 850 }; 851 852 SyntheticChildrenFrontEnd* 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 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 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 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 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 1156 lldb_private::formatters::NSMutableAttributedStringSummaryProvider (ValueObject& valobj, Stream& stream) 1157 { 1158 return NSAttributedStringSummaryProvider(valobj, stream); 1159 } 1160 1161 bool 1162 lldb_private::formatters::RuntimeSpecificDescriptionSummaryProvider (ValueObject& valobj, Stream& stream) 1163 { 1164 stream.Printf("%s",valobj.GetObjectDescription()); 1165 return true; 1166 } 1167 1168 bool 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 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 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 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 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 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 1310 lldb_private::formatters::VectorIteratorSyntheticFrontEnd::CalculateNumChildren () 1311 { 1312 return 1; 1313 } 1314 1315 lldb::ValueObjectSP 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 1324 lldb_private::formatters::VectorIteratorSyntheticFrontEnd::MightHaveChildren () 1325 { 1326 return true; 1327 } 1328 1329 size_t 1330 lldb_private::formatters::VectorIteratorSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name) 1331 { 1332 if (name == ConstString("item")) 1333 return 0; 1334 return UINT32_MAX; 1335 } 1336 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