CXXFormatterFunctions.cpp revision d32acdb74c50f6fc3a2aab0619a75f2bc4c05a30
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 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 int 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(bufferSPSize,0)); 220 utf8_data_ptr = (UTF8*)utf8_data_buffer_sp->GetBytes(); 221 utf8_data_end_ptr = utf8_data_ptr + bufferSPSize; 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> 249static bool 250ReadUTFBufferAndDumpToStream (ConversionResult (*ConvertFunction) (const SourceDataType**, 251 const SourceDataType*, 252 UTF8**, 253 UTF8*, 254 ConversionFlags), 255 uint64_t location, 256 const ProcessSP& process_sp, 257 Stream& stream, 258 char prefix_token = '@', 259 char quote = '"', 260 int sourceSize = 0) 261{ 262 if (location == 0 || location == LLDB_INVALID_ADDRESS) 263 return false; 264 if (!process_sp) 265 return false; 266 267 const int origin_encoding = 8*sizeof(SourceDataType); 268 if (origin_encoding != 8 && origin_encoding != 16 && origin_encoding != 32) 269 return false; 270 // if not UTF8, I need a conversion function to return proper UTF8 271 if (origin_encoding != 8 && !ConvertFunction) 272 return false; 273 274 if (sourceSize == 0) 275 sourceSize = process_sp->GetTarget().GetMaximumSizeOfStringSummary(); 276 const int bufferSPSize = sourceSize * (origin_encoding >> 2); 277 278 Error error; 279 lldb::DataBufferSP buffer_sp(new DataBufferHeap(bufferSPSize,0)); 280 281 if (!buffer_sp->GetBytes()) 282 return false; 283 284 size_t data_read = process_sp->ReadMemoryFromInferior(location, (char*)buffer_sp->GetBytes(), bufferSPSize, error); 285 if (error.Fail() || data_read == 0) 286 { 287 stream.Printf("unable to read data"); 288 return true; 289 } 290 291 DataExtractor data(buffer_sp, process_sp->GetByteOrder(), process_sp->GetAddressByteSize()); 292 293 return DumpUTFBufferToStream(ConvertFunction, data, stream, prefix_token, quote, sourceSize); 294} 295 296bool 297lldb_private::formatters::Char16StringSummaryProvider (ValueObject& valobj, Stream& stream) 298{ 299 ProcessSP process_sp = valobj.GetProcessSP(); 300 if (!process_sp) 301 return false; 302 303 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 304 305 if (!valobj_addr) 306 return false; 307 308 if (!ReadUTFBufferAndDumpToStream<UTF16>(ConvertUTF16toUTF8,valobj_addr, 309 process_sp, 310 stream, 311 'u')) 312 { 313 stream.Printf("Summary Unavailable"); 314 return true; 315 } 316 317 return true; 318} 319 320bool 321lldb_private::formatters::Char32StringSummaryProvider (ValueObject& valobj, Stream& stream) 322{ 323 ProcessSP process_sp = valobj.GetProcessSP(); 324 if (!process_sp) 325 return false; 326 327 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 328 329 if (!valobj_addr) 330 return false; 331 332 if (!ReadUTFBufferAndDumpToStream<UTF32>(ConvertUTF32toUTF8,valobj_addr, 333 process_sp, 334 stream, 335 'U')) 336 { 337 stream.Printf("Summary Unavailable"); 338 return true; 339 } 340 341 return true; 342} 343 344bool 345lldb_private::formatters::WCharStringSummaryProvider (ValueObject& valobj, Stream& stream) 346{ 347 ProcessSP process_sp = valobj.GetProcessSP(); 348 if (!process_sp) 349 return false; 350 351 lldb::addr_t data_addr = 0; 352 353 if (valobj.IsPointerType()) 354 data_addr = valobj.GetValueAsUnsigned(0); 355 else if (valobj.IsArrayType()) 356 data_addr = valobj.GetAddressOf(); 357 358 if (data_addr == 0 || data_addr == LLDB_INVALID_ADDRESS) 359 return false; 360 361 clang::ASTContext* ast = valobj.GetClangAST(); 362 363 if (!ast) 364 return false; 365 366 uint32_t wchar_size = ClangASTType::GetClangTypeBitWidth(ast, ClangASTType::GetBasicType(ast, lldb::eBasicTypeWChar).GetOpaqueQualType()); 367 368 switch (wchar_size) 369 { 370 case 8: 371 // utf 8 372 return ReadUTFBufferAndDumpToStream<UTF8>(nullptr, data_addr, 373 process_sp, 374 stream, 375 'L'); 376 case 16: 377 // utf 16 378 return ReadUTFBufferAndDumpToStream<UTF16>(ConvertUTF16toUTF8, data_addr, 379 process_sp, 380 stream, 381 'L'); 382 case 32: 383 // utf 32 384 return ReadUTFBufferAndDumpToStream<UTF32>(ConvertUTF32toUTF8, data_addr, 385 process_sp, 386 stream, 387 'L'); 388 default: 389 stream.Printf("size for wchar_t is not valid"); 390 return true; 391 } 392 return true; 393} 394 395bool 396lldb_private::formatters::Char16SummaryProvider (ValueObject& valobj, Stream& stream) 397{ 398 DataExtractor data; 399 valobj.GetData(data); 400 401 std::string value; 402 valobj.GetValueAsCString(lldb::eFormatUnicode16, value); 403 if (!value.empty()) 404 stream.Printf("%s ", value.c_str()); 405 406 return DumpUTFBufferToStream<UTF16>(ConvertUTF16toUTF8,data,stream, 'u','\'',1); 407} 408 409bool 410lldb_private::formatters::Char32SummaryProvider (ValueObject& valobj, Stream& stream) 411{ 412 DataExtractor data; 413 valobj.GetData(data); 414 415 std::string value; 416 valobj.GetValueAsCString(lldb::eFormatUnicode32, value); 417 if (!value.empty()) 418 stream.Printf("%s ", value.c_str()); 419 420 return DumpUTFBufferToStream<UTF32>(ConvertUTF32toUTF8,data,stream, 'U','\'',1); 421} 422 423bool 424lldb_private::formatters::WCharSummaryProvider (ValueObject& valobj, Stream& stream) 425{ 426 DataExtractor data; 427 valobj.GetData(data); 428 429 clang::ASTContext* ast = valobj.GetClangAST(); 430 431 if (!ast) 432 return false; 433 434 std::string value; 435 436 uint32_t wchar_size = ClangASTType::GetClangTypeBitWidth(ast, ClangASTType::GetBasicType(ast, lldb::eBasicTypeWChar).GetOpaqueQualType()); 437 438 switch (wchar_size) 439 { 440 case 8: 441 // utf 8 442 valobj.GetValueAsCString(lldb::eFormatChar, value); 443 if (!value.empty()) 444 stream.Printf("%s ", value.c_str()); 445 return DumpUTFBufferToStream<UTF8>(nullptr, 446 data, 447 stream, 448 'L', 449 '\'', 450 1); 451 case 16: 452 // utf 16 453 valobj.GetValueAsCString(lldb::eFormatUnicode16, value); 454 if (!value.empty()) 455 stream.Printf("%s ", value.c_str()); 456 return DumpUTFBufferToStream<UTF16>(ConvertUTF16toUTF8, 457 data, 458 stream, 459 'L', 460 '\'', 461 1); 462 case 32: 463 // utf 32 464 valobj.GetValueAsCString(lldb::eFormatUnicode32, value); 465 if (!value.empty()) 466 stream.Printf("%s ", value.c_str()); 467 return DumpUTFBufferToStream<UTF32>(ConvertUTF32toUTF8, 468 data, 469 stream, 470 'L', 471 '\'', 472 1); 473 default: 474 stream.Printf("size for wchar_t is not valid"); 475 return true; 476 } 477 return true; 478} 479 480// this function extracts information from a libcxx std::basic_string<> 481// irregardless of template arguments. it reports the size (in item count not bytes) 482// and the location in memory where the string data can be found 483static bool 484ExtractLibcxxStringInfo (ValueObject& valobj, 485 ValueObjectSP &location_sp, 486 uint64_t& size) 487{ 488 ValueObjectSP D(valobj.GetChildAtIndexPath({0,0,0,0})); 489 if (!D) 490 return false; 491 492 ValueObjectSP size_mode(D->GetChildAtIndexPath({1,0,0})); 493 if (!size_mode) 494 return false; 495 496 uint64_t size_mode_value(size_mode->GetValueAsUnsigned(0)); 497 498 if ((size_mode_value & 1) == 0) // this means the string is in short-mode and the data is stored inline 499 { 500 ValueObjectSP s(D->GetChildAtIndex(1, true)); 501 if (!s) 502 return false; 503 size = ((size_mode_value >> 1) % 256); 504 location_sp = s->GetChildAtIndex(1, true); 505 return (location_sp.get() != nullptr); 506 } 507 else 508 { 509 ValueObjectSP l(D->GetChildAtIndex(0, true)); 510 if (!l) 511 return false; 512 location_sp = l->GetChildAtIndex(2, true); 513 ValueObjectSP size_vo(l->GetChildAtIndex(1, true)); 514 if (!size_vo || !location_sp) 515 return false; 516 size = size_vo->GetValueAsUnsigned(0); 517 return true; 518 } 519} 520 521bool 522lldb_private::formatters::LibcxxWStringSummaryProvider (ValueObject& valobj, Stream& stream) 523{ 524 uint64_t size = 0; 525 ValueObjectSP location_sp((ValueObject*)nullptr); 526 if (!ExtractLibcxxStringInfo(valobj, location_sp, size)) 527 return false; 528 if (size == 0) 529 { 530 stream.Printf("L\"\""); 531 return true; 532 } 533 if (!location_sp) 534 return false; 535 return WCharStringSummaryProvider(*location_sp.get(), stream); 536} 537 538bool 539lldb_private::formatters::LibcxxStringSummaryProvider (ValueObject& valobj, Stream& stream) 540{ 541 uint64_t size = 0; 542 ValueObjectSP location_sp((ValueObject*)nullptr); 543 if (!ExtractLibcxxStringInfo(valobj, location_sp, size)) 544 return false; 545 if (size == 0) 546 { 547 stream.Printf("\"\""); 548 return true; 549 } 550 if (!location_sp) 551 return false; 552 Error error; 553 if (location_sp->ReadPointedString(stream, 554 error, 555 0, // max length is decided by the settings 556 false) == 0) // do not honor array (terminates on first 0 byte even for a char[]) 557 stream.Printf("\"\""); // if nothing was read, print an empty string 558 return error.Success(); 559} 560 561bool 562lldb_private::formatters::ObjCClassSummaryProvider (ValueObject& valobj, Stream& stream) 563{ 564 ProcessSP process_sp = valobj.GetProcessSP(); 565 if (!process_sp) 566 return false; 567 568 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 569 570 if (!runtime) 571 return false; 572 573 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj.GetValueAsUnsigned(0))); 574 575 if (!descriptor.get() || !descriptor->IsValid()) 576 return false; 577 578 const char* class_name = descriptor->GetClassName().GetCString(); 579 580 if (!class_name || !*class_name) 581 return false; 582 583 stream.Printf("%s",class_name); 584 return true; 585} 586 587template<bool needs_at> 588bool 589lldb_private::formatters::NSDataSummaryProvider (ValueObject& valobj, Stream& stream) 590{ 591 ProcessSP process_sp = valobj.GetProcessSP(); 592 if (!process_sp) 593 return false; 594 595 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 596 597 if (!runtime) 598 return false; 599 600 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj)); 601 602 if (!descriptor.get() || !descriptor->IsValid()) 603 return false; 604 605 bool is_64bit = (process_sp->GetAddressByteSize() == 8); 606 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 607 608 if (!valobj_addr) 609 return false; 610 611 uint64_t value = 0; 612 613 const char* class_name = descriptor->GetClassName().GetCString(); 614 615 if (!class_name || !*class_name) 616 return false; 617 618 if (!strcmp(class_name,"NSConcreteData") || 619 !strcmp(class_name,"NSConcreteMutableData") || 620 !strcmp(class_name,"__NSCFData")) 621 { 622 uint32_t offset = (is_64bit ? 16 : 8); 623 Error error; 624 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + offset, is_64bit ? 8 : 4, 0, error); 625 if (error.Fail()) 626 return false; 627 } 628 else 629 { 630 if (!ExtractValueFromObjCExpression(valobj, "int", "length", value)) 631 return false; 632 } 633 634 stream.Printf("%s%" PRIu64 " byte%s%s", 635 (needs_at ? "@\"" : ""), 636 value, 637 (value > 1 ? "s" : ""), 638 (needs_at ? "\"" : "")); 639 640 return true; 641} 642 643static bool 644ReadAsciiBufferAndDumpToStream (lldb::addr_t location, 645 lldb::ProcessSP& process_sp, 646 Stream& dest, 647 size_t size = 0, 648 Error* error = NULL, 649 size_t *data_read = NULL, 650 char prefix_token = '@', 651 char quote = '"') 652{ 653 Error my_error; 654 size_t my_data_read; 655 if (!process_sp || location == 0) 656 return false; 657 658 if (size == 0) 659 size = process_sp->GetTarget().GetMaximumSizeOfStringSummary(); 660 661 lldb::DataBufferSP buffer_sp(new DataBufferHeap(size,0)); 662 663 my_data_read = process_sp->ReadCStringFromMemory(location, (char*)buffer_sp->GetBytes(), size, my_error); 664 665 if (error) 666 *error = my_error; 667 if (data_read) 668 *data_read = my_data_read; 669 670 if (my_error.Fail()) 671 return false; 672 if (my_data_read) 673 dest.Printf("%c%c%s%c",prefix_token,quote,(char*)buffer_sp->GetBytes(),quote); 674 675 return true; 676} 677 678bool 679lldb_private::formatters::NSStringSummaryProvider (ValueObject& valobj, Stream& stream) 680{ 681 ProcessSP process_sp = valobj.GetProcessSP(); 682 if (!process_sp) 683 return false; 684 685 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 686 687 if (!runtime) 688 return false; 689 690 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj)); 691 692 if (!descriptor.get() || !descriptor->IsValid()) 693 return false; 694 695 uint32_t ptr_size = process_sp->GetAddressByteSize(); 696 697 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 698 699 if (!valobj_addr) 700 return false; 701 702 const char* class_name = descriptor->GetClassName().GetCString(); 703 704 if (!class_name || !*class_name) 705 return false; 706 707 uint64_t info_bits_location = valobj_addr + ptr_size; 708 if (process_sp->GetByteOrder() != lldb::eByteOrderLittle) 709 info_bits_location += 3; 710 711 Error error; 712 713 uint8_t info_bits = process_sp->ReadUnsignedIntegerFromMemory(info_bits_location, 1, 0, error); 714 if (error.Fail()) 715 return false; 716 717 bool is_mutable = (info_bits & 1) == 1; 718 bool is_inline = (info_bits & 0x60) == 0; 719 bool has_explicit_length = (info_bits & (1 | 4)) != 4; 720 bool is_unicode = (info_bits & 0x10) == 0x10; 721 bool is_special = strcmp(class_name,"NSPathStore2") == 0; 722 723 if (strcmp(class_name,"NSString") && 724 strcmp(class_name,"CFStringRef") && 725 strcmp(class_name,"CFMutableStringRef") && 726 strcmp(class_name,"__NSCFConstantString") && 727 strcmp(class_name,"__NSCFString") && 728 strcmp(class_name,"NSCFConstantString") && 729 strcmp(class_name,"NSCFString") && 730 strcmp(class_name,"NSPathStore2")) 731 { 732 // not one of us - but tell me class name 733 stream.Printf("class name = %s",class_name); 734 return true; 735 } 736 737 if (is_mutable) 738 { 739 uint64_t location = 2 * ptr_size + valobj_addr; 740 location = process_sp->ReadPointerFromMemory(location, error); 741 if (error.Fail()) 742 return false; 743 if (has_explicit_length and is_unicode) 744 return ReadUTFBufferAndDumpToStream<UTF16> (ConvertUTF16toUTF8,location, process_sp, stream, '@'); 745 else 746 return ReadAsciiBufferAndDumpToStream(location+1,process_sp,stream); 747 } 748 else if (is_inline && has_explicit_length && !is_unicode && !is_special && !is_mutable) 749 { 750 uint64_t location = 3 * ptr_size + valobj_addr; 751 return ReadAsciiBufferAndDumpToStream(location,process_sp,stream); 752 } 753 else if (is_unicode) 754 { 755 uint64_t location = valobj_addr + 2*ptr_size; 756 if (is_inline) 757 { 758 if (!has_explicit_length) 759 { 760 stream.Printf("found new combo"); 761 return true; 762 } 763 else 764 location += ptr_size; 765 } 766 else 767 { 768 location = process_sp->ReadPointerFromMemory(location, error); 769 if (error.Fail()) 770 return false; 771 } 772 return ReadUTFBufferAndDumpToStream<UTF16> (ConvertUTF16toUTF8, location, process_sp, stream, '@'); 773 } 774 else if (is_special) 775 { 776 uint64_t location = valobj_addr + (ptr_size == 8 ? 12 : 8); 777 return ReadUTFBufferAndDumpToStream<UTF16> (ConvertUTF16toUTF8, location, process_sp, stream, '@'); 778 } 779 else if (is_inline) 780 { 781 uint64_t location = valobj_addr + 2*ptr_size; 782 if (!has_explicit_length) 783 location++; 784 return ReadAsciiBufferAndDumpToStream(location,process_sp,stream); 785 } 786 else 787 { 788 uint64_t location = valobj_addr + 2*ptr_size; 789 location = process_sp->ReadPointerFromMemory(location, error); 790 if (error.Fail()) 791 return false; 792 return ReadAsciiBufferAndDumpToStream(location,process_sp,stream); 793 } 794 795 stream.Printf("class name = %s",class_name); 796 return true; 797 798} 799 800bool 801lldb_private::formatters::NSAttributedStringSummaryProvider (ValueObject& valobj, Stream& stream) 802{ 803 TargetSP target_sp(valobj.GetTargetSP()); 804 if (!target_sp) 805 return false; 806 uint32_t addr_size = target_sp->GetArchitecture().GetAddressByteSize(); 807 uint64_t pointee = valobj.GetValueAsUnsigned(0); 808 if (!pointee) 809 return false; 810 pointee += addr_size; 811 ClangASTType type(valobj.GetClangAST(),valobj.GetClangType()); 812 ExecutionContext exe_ctx(target_sp,false); 813 ValueObjectSP child_ptr_sp(valobj.CreateValueObjectFromAddress("string_ptr", pointee, exe_ctx, type)); 814 if (!child_ptr_sp) 815 return false; 816 DataExtractor data; 817 child_ptr_sp->GetData(data); 818 ValueObjectSP child_sp(child_ptr_sp->CreateValueObjectFromData("string_data", data, exe_ctx, type)); 819 child_sp->GetValueAsUnsigned(0); 820 if (child_sp) 821 return NSStringSummaryProvider(*child_sp, stream); 822 return false; 823} 824 825bool 826lldb_private::formatters::NSMutableAttributedStringSummaryProvider (ValueObject& valobj, Stream& stream) 827{ 828 return NSAttributedStringSummaryProvider(valobj, stream); 829} 830 831bool 832lldb_private::formatters::RuntimeSpecificDescriptionSummaryProvider (ValueObject& valobj, Stream& stream) 833{ 834 stream.Printf("%s",valobj.GetObjectDescription()); 835 return true; 836} 837 838bool 839lldb_private::formatters::ObjCBOOLSummaryProvider (ValueObject& valobj, Stream& stream) 840{ 841 const uint32_t type_info = ClangASTContext::GetTypeInfo(valobj.GetClangType(), 842 valobj.GetClangAST(), 843 NULL); 844 845 ValueObjectSP real_guy_sp = valobj.GetSP(); 846 847 if (type_info & ClangASTContext::eTypeIsPointer) 848 { 849 Error err; 850 real_guy_sp = valobj.Dereference(err); 851 if (err.Fail() || !real_guy_sp) 852 return false; 853 } 854 else if (type_info & ClangASTContext::eTypeIsReference) 855 { 856 real_guy_sp = valobj.GetChildAtIndex(0, true); 857 if (!real_guy_sp) 858 return false; 859 } 860 uint64_t value = real_guy_sp->GetValueAsUnsigned(0); 861 if (value == 0) 862 { 863 stream.Printf("NO"); 864 return true; 865 } 866 stream.Printf("YES"); 867 return true; 868} 869 870template <bool is_sel_ptr> 871bool 872lldb_private::formatters::ObjCSELSummaryProvider (ValueObject& valobj, Stream& stream) 873{ 874 lldb::ValueObjectSP valobj_sp; 875 876 if (!valobj.GetClangAST()) 877 return false; 878 void* char_opaque_type = valobj.GetClangAST()->CharTy.getAsOpaquePtr(); 879 if (!char_opaque_type) 880 return false; 881 ClangASTType charstar(valobj.GetClangAST(),ClangASTType::GetPointerType(valobj.GetClangAST(), char_opaque_type)); 882 883 ExecutionContext exe_ctx(valobj.GetExecutionContextRef()); 884 885 if (is_sel_ptr) 886 { 887 lldb::addr_t data_address = valobj.GetValueAsUnsigned(LLDB_INVALID_ADDRESS); 888 if (data_address == LLDB_INVALID_ADDRESS) 889 return false; 890 valobj_sp = ValueObject::CreateValueObjectFromAddress("text", data_address, exe_ctx, charstar); 891 } 892 else 893 { 894 DataExtractor data; 895 valobj.GetData(data); 896 valobj_sp = ValueObject::CreateValueObjectFromData("text", data, exe_ctx, charstar); 897 } 898 899 if (!valobj_sp) 900 return false; 901 902 stream.Printf("%s",valobj_sp->GetSummaryAsCString()); 903 return true; 904} 905 906// POSIX has an epoch on Jan-1-1970, but Cocoa prefers Jan-1-2001 907// this call gives the POSIX equivalent of the Cocoa epoch 908time_t 909lldb_private::formatters::GetOSXEpoch () 910{ 911 static time_t epoch = 0; 912 if (!epoch) 913 { 914 tzset(); 915 tm tm_epoch; 916 tm_epoch.tm_sec = 0; 917 tm_epoch.tm_hour = 0; 918 tm_epoch.tm_min = 0; 919 tm_epoch.tm_mon = 0; 920 tm_epoch.tm_mday = 1; 921 tm_epoch.tm_year = 2001-1900; // for some reason, we need to subtract 1900 from this field. not sure why. 922 tm_epoch.tm_isdst = -1; 923 tm_epoch.tm_gmtoff = 0; 924 tm_epoch.tm_zone = NULL; 925 epoch = timegm(&tm_epoch); 926 } 927 return epoch; 928} 929 930size_t 931lldb_private::formatters::ExtractIndexFromString (const char* item_name) 932{ 933 if (!item_name || !*item_name) 934 return UINT32_MAX; 935 if (*item_name != '[') 936 return UINT32_MAX; 937 item_name++; 938 char* endptr = NULL; 939 unsigned long int idx = ::strtoul(item_name, &endptr, 0); 940 if (idx == 0 && endptr == item_name) 941 return UINT32_MAX; 942 if (idx == ULONG_MAX) 943 return UINT32_MAX; 944 return idx; 945} 946 947lldb_private::formatters::VectorIteratorSyntheticFrontEnd::VectorIteratorSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp, 948 ConstString item_name) : 949SyntheticChildrenFrontEnd(*valobj_sp.get()), 950m_exe_ctx_ref(), 951m_item_name(item_name), 952m_item_sp() 953{ 954 if (valobj_sp) 955 Update(); 956} 957 958bool 959lldb_private::formatters::VectorIteratorSyntheticFrontEnd::Update() 960{ 961 m_item_sp.reset(); 962 963 ValueObjectSP valobj_sp = m_backend.GetSP(); 964 if (!valobj_sp) 965 return false; 966 967 if (!valobj_sp) 968 return false; 969 970 ValueObjectSP item_ptr(valobj_sp->GetChildMemberWithName(m_item_name,true)); 971 if (!item_ptr) 972 return false; 973 if (item_ptr->GetValueAsUnsigned(0) == 0) 974 return false; 975 Error err; 976 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 977 m_item_sp = ValueObject::CreateValueObjectFromAddress("item", item_ptr->GetValueAsUnsigned(0), m_exe_ctx_ref, ClangASTType(item_ptr->GetClangAST(),ClangASTType::GetPointeeType(item_ptr->GetClangType()))); 978 if (err.Fail()) 979 m_item_sp.reset(); 980 return false; 981} 982 983size_t 984lldb_private::formatters::VectorIteratorSyntheticFrontEnd::CalculateNumChildren () 985{ 986 return 1; 987} 988 989lldb::ValueObjectSP 990lldb_private::formatters::VectorIteratorSyntheticFrontEnd::GetChildAtIndex (size_t idx) 991{ 992 if (idx == 0) 993 return m_item_sp; 994 return lldb::ValueObjectSP(); 995} 996 997bool 998lldb_private::formatters::VectorIteratorSyntheticFrontEnd::MightHaveChildren () 999{ 1000 return true; 1001} 1002 1003size_t 1004lldb_private::formatters::VectorIteratorSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name) 1005{ 1006 if (name == ConstString("item")) 1007 return 0; 1008 return UINT32_MAX; 1009} 1010 1011lldb_private::formatters::VectorIteratorSyntheticFrontEnd::~VectorIteratorSyntheticFrontEnd () 1012{ 1013} 1014 1015template bool 1016lldb_private::formatters::NSDataSummaryProvider<true> (ValueObject&, Stream&) ; 1017 1018template bool 1019lldb_private::formatters::NSDataSummaryProvider<false> (ValueObject&, Stream&) ; 1020 1021template bool 1022lldb_private::formatters::ObjCSELSummaryProvider<true> (ValueObject&, Stream&) ; 1023 1024template bool 1025lldb_private::formatters::ObjCSELSummaryProvider<false> (ValueObject&, Stream&) ; 1026