CXXFormatterFunctions.cpp revision 3818e6ac2211921db522abedd43746c1de3e82b5
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 643bool 644lldb_private::formatters::NSBundleSummaryProvider (ValueObject& valobj, Stream& stream) 645{ 646 ProcessSP process_sp = valobj.GetProcessSP(); 647 if (!process_sp) 648 return false; 649 650 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 651 652 if (!runtime) 653 return false; 654 655 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj)); 656 657 if (!descriptor.get() || !descriptor->IsValid()) 658 return false; 659 660 uint32_t ptr_size = process_sp->GetAddressByteSize(); 661 662 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 663 664 if (!valobj_addr) 665 return false; 666 667 const char* class_name = descriptor->GetClassName().GetCString(); 668 669 if (!class_name || !*class_name) 670 return false; 671 672 if (!strcmp(class_name,"NSBundle")) 673 { 674 uint64_t offset = 5 * ptr_size; 675 ClangASTType type(valobj.GetClangAST(),valobj.GetClangType()); 676 ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset, type, true)); 677 StreamString summary_stream; 678 bool was_nsstring_ok = NSStringSummaryProvider(*text.get(), summary_stream); 679 if (was_nsstring_ok && summary_stream.GetSize() > 0) 680 { 681 stream.Printf("%s",summary_stream.GetData()); 682 return true; 683 } 684 } 685 // this is either an unknown subclass or an NSBundle that comes from [NSBundle mainBundle] 686 // which is encoded differently and needs to be handled by running code 687 return ExtractSummaryFromObjCExpression(valobj, "NSString*", "bundlePath", stream); 688} 689 690bool 691lldb_private::formatters::NSNotificationSummaryProvider (ValueObject& valobj, Stream& stream) 692{ 693 ProcessSP process_sp = valobj.GetProcessSP(); 694 if (!process_sp) 695 return false; 696 697 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 698 699 if (!runtime) 700 return false; 701 702 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj)); 703 704 if (!descriptor.get() || !descriptor->IsValid()) 705 return false; 706 707 uint32_t ptr_size = process_sp->GetAddressByteSize(); 708 709 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 710 711 if (!valobj_addr) 712 return false; 713 714 const char* class_name = descriptor->GetClassName().GetCString(); 715 716 if (!class_name || !*class_name) 717 return false; 718 719 if (!strcmp(class_name,"NSConcreteNotification")) 720 { 721 uint64_t offset = ptr_size; 722 ClangASTType type(valobj.GetClangAST(),valobj.GetClangType()); 723 ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset, type, true)); 724 StreamString summary_stream; 725 bool was_nsstring_ok = NSStringSummaryProvider(*text.get(), summary_stream); 726 if (was_nsstring_ok && summary_stream.GetSize() > 0) 727 { 728 stream.Printf("%s",summary_stream.GetData()); 729 return true; 730 } 731 } 732 // this is either an unknown subclass or an NSBundle that comes from [NSBundle mainBundle] 733 // which is encoded differently and needs to be handled by running code 734 return ExtractSummaryFromObjCExpression(valobj, "NSString*", "name", stream); 735} 736 737bool 738lldb_private::formatters::NSMachPortSummaryProvider (ValueObject& valobj, Stream& stream) 739{ 740 ProcessSP process_sp = valobj.GetProcessSP(); 741 if (!process_sp) 742 return false; 743 744 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 745 746 if (!runtime) 747 return false; 748 749 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj)); 750 751 if (!descriptor.get() || !descriptor->IsValid()) 752 return false; 753 754 uint32_t ptr_size = process_sp->GetAddressByteSize(); 755 756 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 757 758 if (!valobj_addr) 759 return false; 760 761 const char* class_name = descriptor->GetClassName().GetCString(); 762 763 if (!class_name || !*class_name) 764 return false; 765 766 uint64_t port_number = 0; 767 768 do 769 { 770 if (!strcmp(class_name,"NSMachPort")) 771 { 772 uint64_t offset = (ptr_size == 4 ? 12 : 20); 773 Error error; 774 port_number = process_sp->ReadUnsignedIntegerFromMemory(offset+valobj_addr, 4, 0, error); 775 if (error.Success()) 776 break; 777 } 778 if (!ExtractValueFromObjCExpression(valobj, "int", "machPort", port_number)) 779 return false; 780 } while (false); 781 782 stream.Printf("mach port: %u",(uint32_t)(port_number & 0x00000000FFFFFFFF)); 783 return true; 784} 785 786bool 787lldb_private::formatters::CFBagSummaryProvider (ValueObject& valobj, Stream& stream) 788{ 789 ProcessSP process_sp = valobj.GetProcessSP(); 790 if (!process_sp) 791 return false; 792 793 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 794 795 if (!runtime) 796 return false; 797 798 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj)); 799 800 if (!descriptor.get() || !descriptor->IsValid()) 801 return false; 802 803 uint32_t ptr_size = process_sp->GetAddressByteSize(); 804 805 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 806 807 if (!valobj_addr) 808 return false; 809 810 uint32_t count = 0; 811 812 bool is_type_ok = false; // check to see if this is a CFBag we know about 813 if (descriptor->IsCFType()) 814 { 815 ConstString type_name(valobj.GetTypeName()); 816 if (type_name == ConstString("__CFBag") || type_name == ConstString("const struct __CFBag")) 817 { 818 if (valobj.IsPointerType()) 819 is_type_ok = true; 820 } 821 } 822 823 if (is_type_ok == false) 824 { 825 StackFrameSP frame_sp(valobj.GetFrameSP()); 826 if (!frame_sp) 827 return false; 828 ValueObjectSP count_sp; 829 StreamString expr; 830 expr.Printf("(int)CFBagGetCount((void*)0x%" PRIx64 ")",valobj.GetPointerValue()); 831 if (process_sp->GetTarget().EvaluateExpression(expr.GetData(), frame_sp.get(), count_sp) != eExecutionCompleted) 832 return false; 833 if (!count_sp) 834 return false; 835 count = count_sp->GetValueAsUnsigned(0); 836 } 837 else 838 { 839 uint32_t offset = 2*ptr_size+4 + valobj_addr; 840 Error error; 841 count = process_sp->ReadUnsignedIntegerFromMemory(offset, 4, 0, error); 842 if (error.Fail()) 843 return false; 844 } 845 stream.Printf("@\"%u value%s\"", 846 count,(count == 1 ? "" : "s")); 847 return true; 848} 849 850bool 851lldb_private::formatters::CFBinaryHeapSummaryProvider (ValueObject& valobj, Stream& stream) 852{ 853 ProcessSP process_sp = valobj.GetProcessSP(); 854 if (!process_sp) 855 return false; 856 857 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 858 859 if (!runtime) 860 return false; 861 862 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj)); 863 864 if (!descriptor.get() || !descriptor->IsValid()) 865 return false; 866 867 uint32_t ptr_size = process_sp->GetAddressByteSize(); 868 869 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 870 871 if (!valobj_addr) 872 return false; 873 874 uint32_t count = 0; 875 876 bool is_type_ok = false; // check to see if this is a CFBinaryHeap we know about 877 if (descriptor->IsCFType()) 878 { 879 ConstString type_name(valobj.GetTypeName()); 880 if (type_name == ConstString("__CFBinaryHeap") || type_name == ConstString("const struct __CFBinaryHeap")) 881 { 882 if (valobj.IsPointerType()) 883 is_type_ok = true; 884 } 885 } 886 887 if (is_type_ok == false) 888 { 889 StackFrameSP frame_sp(valobj.GetFrameSP()); 890 if (!frame_sp) 891 return false; 892 ValueObjectSP count_sp; 893 StreamString expr; 894 expr.Printf("(int)CFBinaryHeapGetCount((void*)0x%" PRIx64 ")",valobj.GetPointerValue()); 895 if (process_sp->GetTarget().EvaluateExpression(expr.GetData(), frame_sp.get(), count_sp) != eExecutionCompleted) 896 return false; 897 if (!count_sp) 898 return false; 899 count = count_sp->GetValueAsUnsigned(0); 900 } 901 else 902 { 903 uint32_t offset = 2*ptr_size; 904 Error error; 905 count = process_sp->ReadUnsignedIntegerFromMemory(offset, 4, 0, error); 906 if (error.Fail()) 907 return false; 908 } 909 stream.Printf("@\"%u item%s\"", 910 count,(count == 1 ? "" : "s")); 911 return true; 912} 913 914bool 915lldb_private::formatters::NSIndexSetSummaryProvider (ValueObject& valobj, Stream& stream) 916{ 917 ProcessSP process_sp = valobj.GetProcessSP(); 918 if (!process_sp) 919 return false; 920 921 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 922 923 if (!runtime) 924 return false; 925 926 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj)); 927 928 if (!descriptor.get() || !descriptor->IsValid()) 929 return false; 930 931 uint32_t ptr_size = process_sp->GetAddressByteSize(); 932 933 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 934 935 if (!valobj_addr) 936 return false; 937 938 const char* class_name = descriptor->GetClassName().GetCString(); 939 940 if (!class_name || !*class_name) 941 return false; 942 943 uint64_t count = 0; 944 945 do { 946 if (!strcmp(class_name,"NSIndexSet") || !strcmp(class_name,"NSMutableIndexSet")) 947 { 948 Error error; 949 uint32_t mode = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+ptr_size, 4, 0, error); 950 if (error.Fail()) 951 return false; 952 // this means the set is empty - count = 0 953 if ((mode & 1) == 1) 954 { 955 count = 0; 956 break; 957 } 958 if ((mode & 2) == 2) 959 mode = 1; // this means the set only has one range 960 else 961 mode = 2; // this means the set has multiple ranges 962 if (mode == 1) 963 { 964 count = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+3*ptr_size, ptr_size, 0, error); 965 if (error.Fail()) 966 return false; 967 } 968 else 969 { 970 // read a pointer to the data at 2*ptr_size 971 count = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+2*ptr_size, ptr_size, 0, error); 972 if (error.Fail()) 973 return false; 974 // read the data at 2*ptr_size from the first location 975 count = process_sp->ReadUnsignedIntegerFromMemory(count+2*ptr_size, ptr_size, 0, error); 976 if (error.Fail()) 977 return false; 978 } 979 } 980 else 981 { 982 if (!ExtractValueFromObjCExpression(valobj, "unsigned long long int", "count", count)) 983 return false; 984 } 985 } while (false); 986 stream.Printf("%llu index%s", 987 count, 988 (count == 1 ? "" : "es")); 989 return true; 990} 991 992bool 993lldb_private::formatters::NSNumberSummaryProvider (ValueObject& valobj, Stream& stream) 994{ 995 ProcessSP process_sp = valobj.GetProcessSP(); 996 if (!process_sp) 997 return false; 998 999 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 1000 1001 if (!runtime) 1002 return false; 1003 1004 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj)); 1005 1006 if (!descriptor.get() || !descriptor->IsValid()) 1007 return false; 1008 1009 uint32_t ptr_size = process_sp->GetAddressByteSize(); 1010 1011 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 1012 1013 if (!valobj_addr) 1014 return false; 1015 1016 const char* class_name = descriptor->GetClassName().GetCString(); 1017 1018 if (!class_name || !*class_name) 1019 return false; 1020 1021 if (!strcmp(class_name,"NSNumber") || !strcmp(class_name,"__NSCFNumber")) 1022 { 1023 if (descriptor->IsTagged()) 1024 { 1025 // we have a call to get info and value bits in the tagged descriptor. but we prefer not to cast and replicate them 1026 int64_t value = (valobj_addr & ~0x0000000000000000FFL) >> 8; 1027 uint64_t i_bits = (valobj_addr & 0xF0) >> 4; 1028 1029 switch (i_bits) 1030 { 1031 case 0: 1032 stream.Printf("(char)%hhd",(char)value); 1033 break; 1034 case 4: 1035 stream.Printf("(short)%hd",(short)value); 1036 break; 1037 case 8: 1038 stream.Printf("(int)%d",(int)value); 1039 break; 1040 case 12: 1041 stream.Printf("(long)%" PRId64,value); 1042 break; 1043 default: 1044 stream.Printf("unexpected value:(info=%" PRIu64 ", value=%" PRIu64,i_bits,value); 1045 break; 1046 } 1047 return true; 1048 } 1049 else 1050 { 1051 Error error; 1052 uint8_t data_type = (process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, 1, 0, error) & 0x1F); 1053 uint64_t data_location = valobj_addr + 2*ptr_size; 1054 uint64_t value = 0; 1055 if (error.Fail()) 1056 return false; 1057 switch (data_type) 1058 { 1059 case 1: // 0B00001 1060 value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 1, 0, error); 1061 if (error.Fail()) 1062 return false; 1063 stream.Printf("(char)%hhd",(char)value); 1064 break; 1065 case 2: // 0B0010 1066 value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 2, 0, error); 1067 if (error.Fail()) 1068 return false; 1069 stream.Printf("(short)%hd",(short)value); 1070 break; 1071 case 3: // 0B0011 1072 value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 4, 0, error); 1073 if (error.Fail()) 1074 return false; 1075 stream.Printf("(int)%d",(int)value); 1076 break; 1077 case 17: // 0B10001 1078 data_location += 8; 1079 case 4: // 0B0100 1080 value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 8, 0, error); 1081 if (error.Fail()) 1082 return false; 1083 stream.Printf("(long)%" PRId64,value); 1084 break; 1085 case 5: // 0B0101 1086 { 1087 uint32_t flt_as_int = process_sp->ReadUnsignedIntegerFromMemory(data_location, 4, 0, error); 1088 if (error.Fail()) 1089 return false; 1090 float flt_value = *((float*)&flt_as_int); 1091 stream.Printf("(float)%f",flt_value); 1092 break; 1093 } 1094 case 6: // 0B0110 1095 { 1096 uint64_t dbl_as_lng = process_sp->ReadUnsignedIntegerFromMemory(data_location, 8, 0, error); 1097 if (error.Fail()) 1098 return false; 1099 double dbl_value = *((double*)&dbl_as_lng); 1100 stream.Printf("(double)%g",dbl_value); 1101 break; 1102 } 1103 default: 1104 stream.Printf("absurd: dt=%d",data_type); 1105 break; 1106 } 1107 return true; 1108 } 1109 } 1110 else 1111 { 1112 return ExtractSummaryFromObjCExpression(valobj, "NSString*", "stringValue", stream); 1113 } 1114} 1115 1116static bool 1117ReadAsciiBufferAndDumpToStream (lldb::addr_t location, 1118 lldb::ProcessSP& process_sp, 1119 Stream& dest, 1120 size_t size = 0, 1121 Error* error = NULL, 1122 size_t *data_read = NULL, 1123 char prefix_token = '@', 1124 char quote = '"') 1125{ 1126 Error my_error; 1127 size_t my_data_read; 1128 if (!process_sp || location == 0) 1129 return false; 1130 1131 if (size == 0) 1132 size = process_sp->GetTarget().GetMaximumSizeOfStringSummary(); 1133 1134 lldb::DataBufferSP buffer_sp(new DataBufferHeap(size,0)); 1135 1136 my_data_read = process_sp->ReadCStringFromMemory(location, (char*)buffer_sp->GetBytes(), size, my_error); 1137 1138 if (error) 1139 *error = my_error; 1140 if (data_read) 1141 *data_read = my_data_read; 1142 1143 if (my_error.Fail()) 1144 return false; 1145 if (my_data_read) 1146 dest.Printf("%c%c%s%c",prefix_token,quote,(char*)buffer_sp->GetBytes(),quote); 1147 1148 return true; 1149} 1150 1151bool 1152lldb_private::formatters::NSStringSummaryProvider (ValueObject& valobj, Stream& stream) 1153{ 1154 ProcessSP process_sp = valobj.GetProcessSP(); 1155 if (!process_sp) 1156 return false; 1157 1158 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 1159 1160 if (!runtime) 1161 return false; 1162 1163 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj)); 1164 1165 if (!descriptor.get() || !descriptor->IsValid()) 1166 return false; 1167 1168 uint32_t ptr_size = process_sp->GetAddressByteSize(); 1169 1170 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 1171 1172 if (!valobj_addr) 1173 return false; 1174 1175 const char* class_name = descriptor->GetClassName().GetCString(); 1176 1177 if (!class_name || !*class_name) 1178 return false; 1179 1180 uint64_t info_bits_location = valobj_addr + ptr_size; 1181 if (process_sp->GetByteOrder() != lldb::eByteOrderLittle) 1182 info_bits_location += 3; 1183 1184 Error error; 1185 1186 uint8_t info_bits = process_sp->ReadUnsignedIntegerFromMemory(info_bits_location, 1, 0, error); 1187 if (error.Fail()) 1188 return false; 1189 1190 bool is_mutable = (info_bits & 1) == 1; 1191 bool is_inline = (info_bits & 0x60) == 0; 1192 bool has_explicit_length = (info_bits & (1 | 4)) != 4; 1193 bool is_unicode = (info_bits & 0x10) == 0x10; 1194 bool is_special = strcmp(class_name,"NSPathStore2") == 0; 1195 1196 if (strcmp(class_name,"NSString") && 1197 strcmp(class_name,"CFStringRef") && 1198 strcmp(class_name,"CFMutableStringRef") && 1199 strcmp(class_name,"__NSCFConstantString") && 1200 strcmp(class_name,"__NSCFString") && 1201 strcmp(class_name,"NSCFConstantString") && 1202 strcmp(class_name,"NSCFString") && 1203 strcmp(class_name,"NSPathStore2")) 1204 { 1205 // not one of us - but tell me class name 1206 stream.Printf("class name = %s",class_name); 1207 return true; 1208 } 1209 1210 if (is_mutable) 1211 { 1212 uint64_t location = 2 * ptr_size + valobj_addr; 1213 location = process_sp->ReadPointerFromMemory(location, error); 1214 if (error.Fail()) 1215 return false; 1216 if (has_explicit_length and is_unicode) 1217 return ReadUTFBufferAndDumpToStream<UTF16> (ConvertUTF16toUTF8,location, process_sp, stream, '@'); 1218 else 1219 return ReadAsciiBufferAndDumpToStream(location+1,process_sp,stream); 1220 } 1221 else if (is_inline && has_explicit_length && !is_unicode && !is_special && !is_mutable) 1222 { 1223 uint64_t location = 3 * ptr_size + valobj_addr; 1224 return ReadAsciiBufferAndDumpToStream(location,process_sp,stream); 1225 } 1226 else if (is_unicode) 1227 { 1228 uint64_t location = valobj_addr + 2*ptr_size; 1229 if (is_inline) 1230 { 1231 if (!has_explicit_length) 1232 { 1233 stream.Printf("found new combo"); 1234 return true; 1235 } 1236 else 1237 location += ptr_size; 1238 } 1239 else 1240 { 1241 location = process_sp->ReadPointerFromMemory(location, error); 1242 if (error.Fail()) 1243 return false; 1244 } 1245 return ReadUTFBufferAndDumpToStream<UTF16> (ConvertUTF16toUTF8, location, process_sp, stream, '@'); 1246 } 1247 else if (is_special) 1248 { 1249 uint64_t location = valobj_addr + (ptr_size == 8 ? 12 : 8); 1250 return ReadUTFBufferAndDumpToStream<UTF16> (ConvertUTF16toUTF8, location, process_sp, stream, '@'); 1251 } 1252 else if (is_inline) 1253 { 1254 uint64_t location = valobj_addr + 2*ptr_size; 1255 if (!has_explicit_length) 1256 location++; 1257 return ReadAsciiBufferAndDumpToStream(location,process_sp,stream); 1258 } 1259 else 1260 { 1261 uint64_t location = valobj_addr + 2*ptr_size; 1262 location = process_sp->ReadPointerFromMemory(location, error); 1263 if (error.Fail()) 1264 return false; 1265 return ReadAsciiBufferAndDumpToStream(location,process_sp,stream); 1266 } 1267 1268 stream.Printf("class name = %s",class_name); 1269 return true; 1270 1271} 1272 1273bool 1274lldb_private::formatters::NSAttributedStringSummaryProvider (ValueObject& valobj, Stream& stream) 1275{ 1276 TargetSP target_sp(valobj.GetTargetSP()); 1277 if (!target_sp) 1278 return false; 1279 uint32_t addr_size = target_sp->GetArchitecture().GetAddressByteSize(); 1280 uint64_t pointee = valobj.GetValueAsUnsigned(0); 1281 if (!pointee) 1282 return false; 1283 pointee += addr_size; 1284 ClangASTType type(valobj.GetClangAST(),valobj.GetClangType()); 1285 ExecutionContext exe_ctx(target_sp,false); 1286 ValueObjectSP child_ptr_sp(valobj.CreateValueObjectFromAddress("string_ptr", pointee, exe_ctx, type)); 1287 if (!child_ptr_sp) 1288 return false; 1289 DataExtractor data; 1290 child_ptr_sp->GetData(data); 1291 ValueObjectSP child_sp(child_ptr_sp->CreateValueObjectFromData("string_data", data, exe_ctx, type)); 1292 child_sp->GetValueAsUnsigned(0); 1293 if (child_sp) 1294 return NSStringSummaryProvider(*child_sp, stream); 1295 return false; 1296} 1297 1298bool 1299lldb_private::formatters::NSMutableAttributedStringSummaryProvider (ValueObject& valobj, Stream& stream) 1300{ 1301 return NSAttributedStringSummaryProvider(valobj, stream); 1302} 1303 1304bool 1305lldb_private::formatters::RuntimeSpecificDescriptionSummaryProvider (ValueObject& valobj, Stream& stream) 1306{ 1307 stream.Printf("%s",valobj.GetObjectDescription()); 1308 return true; 1309} 1310 1311bool 1312lldb_private::formatters::NSURLSummaryProvider (ValueObject& valobj, Stream& stream) 1313{ 1314 ProcessSP process_sp = valobj.GetProcessSP(); 1315 if (!process_sp) 1316 return false; 1317 1318 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 1319 1320 if (!runtime) 1321 return false; 1322 1323 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj)); 1324 1325 if (!descriptor.get() || !descriptor->IsValid()) 1326 return false; 1327 1328 uint32_t ptr_size = process_sp->GetAddressByteSize(); 1329 1330 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 1331 1332 if (!valobj_addr) 1333 return false; 1334 1335 const char* class_name = descriptor->GetClassName().GetCString(); 1336 1337 if (!class_name || !*class_name) 1338 return false; 1339 1340 if (strcmp(class_name, "NSURL") == 0) 1341 { 1342 uint64_t offset_text = ptr_size + ptr_size + 8; // ISA + pointer + 8 bytes of data (even on 32bit) 1343 uint64_t offset_base = offset_text + ptr_size; 1344 ClangASTType type(valobj.GetClangAST(),valobj.GetClangType()); 1345 ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset_text, type, true)); 1346 ValueObjectSP base(valobj.GetSyntheticChildAtOffset(offset_base, type, true)); 1347 if (!text) 1348 return false; 1349 if (text->GetValueAsUnsigned(0) == 0) 1350 return false; 1351 StreamString summary; 1352 if (!NSStringSummaryProvider(*text, summary)) 1353 return false; 1354 if (base && base->GetValueAsUnsigned(0)) 1355 { 1356 if (summary.GetSize() > 0) 1357 summary.GetString().resize(summary.GetSize()-1); 1358 summary.Printf(" -- "); 1359 StreamString base_summary; 1360 if (NSURLSummaryProvider(*base, base_summary) && base_summary.GetSize() > 0) 1361 summary.Printf("%s",base_summary.GetSize() > 2 ? base_summary.GetData() + 2 : base_summary.GetData()); 1362 } 1363 if (summary.GetSize()) 1364 { 1365 stream.Printf("%s",summary.GetData()); 1366 return true; 1367 } 1368 } 1369 else 1370 { 1371 return ExtractSummaryFromObjCExpression(valobj, "NSString*", "description", stream); 1372 } 1373 return false; 1374} 1375 1376bool 1377lldb_private::formatters::ObjCBOOLSummaryProvider (ValueObject& valobj, Stream& stream) 1378{ 1379 const uint32_t type_info = ClangASTContext::GetTypeInfo(valobj.GetClangType(), 1380 valobj.GetClangAST(), 1381 NULL); 1382 1383 ValueObjectSP real_guy_sp = valobj.GetSP(); 1384 1385 if (type_info & ClangASTContext::eTypeIsPointer) 1386 { 1387 Error err; 1388 real_guy_sp = valobj.Dereference(err); 1389 if (err.Fail() || !real_guy_sp) 1390 return false; 1391 } 1392 else if (type_info & ClangASTContext::eTypeIsReference) 1393 { 1394 real_guy_sp = valobj.GetChildAtIndex(0, true); 1395 if (!real_guy_sp) 1396 return false; 1397 } 1398 uint64_t value = real_guy_sp->GetValueAsUnsigned(0); 1399 if (value == 0) 1400 { 1401 stream.Printf("NO"); 1402 return true; 1403 } 1404 stream.Printf("YES"); 1405 return true; 1406} 1407 1408template <bool is_sel_ptr> 1409bool 1410lldb_private::formatters::ObjCSELSummaryProvider (ValueObject& valobj, Stream& stream) 1411{ 1412 lldb::ValueObjectSP valobj_sp; 1413 1414 if (!valobj.GetClangAST()) 1415 return false; 1416 void* char_opaque_type = valobj.GetClangAST()->CharTy.getAsOpaquePtr(); 1417 if (!char_opaque_type) 1418 return false; 1419 ClangASTType charstar(valobj.GetClangAST(),ClangASTType::GetPointerType(valobj.GetClangAST(), char_opaque_type)); 1420 1421 ExecutionContext exe_ctx(valobj.GetExecutionContextRef()); 1422 1423 if (is_sel_ptr) 1424 { 1425 lldb::addr_t data_address = valobj.GetValueAsUnsigned(LLDB_INVALID_ADDRESS); 1426 if (data_address == LLDB_INVALID_ADDRESS) 1427 return false; 1428 valobj_sp = ValueObject::CreateValueObjectFromAddress("text", data_address, exe_ctx, charstar); 1429 } 1430 else 1431 { 1432 DataExtractor data; 1433 valobj.GetData(data); 1434 valobj_sp = ValueObject::CreateValueObjectFromData("text", data, exe_ctx, charstar); 1435 } 1436 1437 if (!valobj_sp) 1438 return false; 1439 1440 stream.Printf("%s",valobj_sp->GetSummaryAsCString()); 1441 return true; 1442} 1443 1444size_t 1445lldb_private::formatters::ExtractIndexFromString (const char* item_name) 1446{ 1447 if (!item_name || !*item_name) 1448 return UINT32_MAX; 1449 if (*item_name != '[') 1450 return UINT32_MAX; 1451 item_name++; 1452 char* endptr = NULL; 1453 unsigned long int idx = ::strtoul(item_name, &endptr, 0); 1454 if (idx == 0 && endptr == item_name) 1455 return UINT32_MAX; 1456 if (idx == ULONG_MAX) 1457 return UINT32_MAX; 1458 return idx; 1459} 1460 1461lldb_private::formatters::VectorIteratorSyntheticFrontEnd::VectorIteratorSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp, 1462 ConstString item_name) : 1463SyntheticChildrenFrontEnd(*valobj_sp.get()), 1464m_exe_ctx_ref(), 1465m_item_name(item_name), 1466m_item_sp() 1467{ 1468 if (valobj_sp) 1469 Update(); 1470} 1471 1472bool 1473lldb_private::formatters::VectorIteratorSyntheticFrontEnd::Update() 1474{ 1475 ValueObjectSP valobj_sp = m_backend.GetSP(); 1476 if (!valobj_sp) 1477 return false; 1478 1479 if (!valobj_sp) 1480 return false; 1481 1482 ValueObjectSP item_ptr(valobj_sp->GetChildMemberWithName(m_item_name,true)); 1483 if (!item_ptr) 1484 return false; 1485 if (item_ptr->GetValueAsUnsigned(0) == 0) 1486 return false; 1487 Error err; 1488 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 1489 m_item_sp = ValueObject::CreateValueObjectFromAddress("item", item_ptr->GetValueAsUnsigned(0), m_exe_ctx_ref, ClangASTType(item_ptr->GetClangAST(),ClangASTType::GetPointeeType(item_ptr->GetClangType()))); 1490 if (err.Fail()) 1491 m_item_sp.reset(); 1492 return (m_item_sp.get() != NULL); 1493} 1494 1495size_t 1496lldb_private::formatters::VectorIteratorSyntheticFrontEnd::CalculateNumChildren () 1497{ 1498 return 1; 1499} 1500 1501lldb::ValueObjectSP 1502lldb_private::formatters::VectorIteratorSyntheticFrontEnd::GetChildAtIndex (size_t idx) 1503{ 1504 if (idx == 0) 1505 return m_item_sp; 1506 return lldb::ValueObjectSP(); 1507} 1508 1509bool 1510lldb_private::formatters::VectorIteratorSyntheticFrontEnd::MightHaveChildren () 1511{ 1512 return true; 1513} 1514 1515size_t 1516lldb_private::formatters::VectorIteratorSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name) 1517{ 1518 if (name == ConstString("item")) 1519 return 0; 1520 return UINT32_MAX; 1521} 1522 1523lldb_private::formatters::VectorIteratorSyntheticFrontEnd::~VectorIteratorSyntheticFrontEnd () 1524{ 1525} 1526 1527template bool 1528lldb_private::formatters::NSDataSummaryProvider<true> (ValueObject&, Stream&) ; 1529 1530template bool 1531lldb_private::formatters::NSDataSummaryProvider<false> (ValueObject&, Stream&) ; 1532 1533template bool 1534lldb_private::formatters::ObjCSELSummaryProvider<true> (ValueObject&, Stream&) ; 1535 1536template bool 1537lldb_private::formatters::ObjCSELSummaryProvider<false> (ValueObject&, Stream&) ; 1538