CXXFormatterFunctions.cpp revision cba09f60618744e2155bc97c9049fa9c797698ad
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 <time.h> 13 14#include "lldb/DataFormatters/CXXFormatterFunctions.h" 15 16#include "llvm/Support/ConvertUTF.h" 17 18#include "lldb/Core/DataBufferHeap.h" 19#include "lldb/Core/Error.h" 20#include "lldb/Core/Stream.h" 21#include "lldb/Core/ValueObject.h" 22#include "lldb/Core/ValueObjectConstResult.h" 23#include "lldb/Host/Endian.h" 24#include "lldb/Symbol/ClangASTContext.h" 25#include "lldb/Target/ObjCLanguageRuntime.h" 26#include "lldb/Target/Target.h" 27 28using namespace lldb; 29using namespace lldb_private; 30using namespace lldb_private::formatters; 31 32bool 33lldb_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 66bool 67lldb_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 101lldb::ValueObjectSP 102lldb_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 136lldb::ValueObjectSP 137lldb_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 174template<typename SourceDataType> 175static bool 176DumpUTFBufferToStream (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 int 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(bufferSPSize,0)); 222 utf8_data_ptr = (UTF8*)utf8_data_buffer_sp->GetBytes(); 223 utf8_data_end_ptr = utf8_data_ptr + bufferSPSize; 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 250template<typename SourceDataType> 251static bool 252ReadUTFBufferAndDumpToStream (ConversionResult (*ConvertFunction) (const SourceDataType**, 253 const SourceDataType*, 254 UTF8**, 255 UTF8*, 256 ConversionFlags), 257 uint64_t location, 258 const ProcessSP& process_sp, 259 Stream& stream, 260 char prefix_token = '@', 261 char quote = '"', 262 int sourceSize = 0) 263{ 264 if (location == 0 || location == LLDB_INVALID_ADDRESS) 265 return false; 266 if (!process_sp) 267 return false; 268 269 const int origin_encoding = 8*sizeof(SourceDataType); 270 if (origin_encoding != 8 && origin_encoding != 16 && origin_encoding != 32) 271 return false; 272 // if not UTF8, I need a conversion function to return proper UTF8 273 if (origin_encoding != 8 && !ConvertFunction) 274 return false; 275 276 if (sourceSize == 0) 277 sourceSize = process_sp->GetTarget().GetMaximumSizeOfStringSummary(); 278 const int bufferSPSize = sourceSize * (origin_encoding >> 2); 279 280 Error error; 281 lldb::DataBufferSP buffer_sp(new DataBufferHeap(bufferSPSize,0)); 282 283 if (!buffer_sp->GetBytes()) 284 return false; 285 286 size_t data_read = process_sp->ReadMemoryFromInferior(location, (char*)buffer_sp->GetBytes(), bufferSPSize, error); 287 if (error.Fail() || data_read == 0) 288 { 289 stream.Printf("unable to read data"); 290 return true; 291 } 292 293 DataExtractor data(buffer_sp, process_sp->GetByteOrder(), process_sp->GetAddressByteSize()); 294 295 return DumpUTFBufferToStream(ConvertFunction, data, stream, prefix_token, quote, sourceSize); 296} 297 298bool 299lldb_private::formatters::Char16StringSummaryProvider (ValueObject& valobj, Stream& stream) 300{ 301 ProcessSP process_sp = valobj.GetProcessSP(); 302 if (!process_sp) 303 return false; 304 305 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 306 307 if (!valobj_addr) 308 return false; 309 310 if (!ReadUTFBufferAndDumpToStream<UTF16>(ConvertUTF16toUTF8,valobj_addr, 311 process_sp, 312 stream, 313 'u')) 314 { 315 stream.Printf("Summary Unavailable"); 316 return true; 317 } 318 319 return true; 320} 321 322bool 323lldb_private::formatters::Char32StringSummaryProvider (ValueObject& valobj, Stream& stream) 324{ 325 ProcessSP process_sp = valobj.GetProcessSP(); 326 if (!process_sp) 327 return false; 328 329 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 330 331 if (!valobj_addr) 332 return false; 333 334 if (!ReadUTFBufferAndDumpToStream<UTF32>(ConvertUTF32toUTF8,valobj_addr, 335 process_sp, 336 stream, 337 'U')) 338 { 339 stream.Printf("Summary Unavailable"); 340 return true; 341 } 342 343 return true; 344} 345 346bool 347lldb_private::formatters::WCharStringSummaryProvider (ValueObject& valobj, Stream& stream) 348{ 349 ProcessSP process_sp = valobj.GetProcessSP(); 350 if (!process_sp) 351 return false; 352 353 lldb::addr_t data_addr = 0; 354 355 if (valobj.IsPointerType()) 356 data_addr = valobj.GetValueAsUnsigned(0); 357 else if (valobj.IsArrayType()) 358 data_addr = valobj.GetAddressOf(); 359 360 if (data_addr == 0 || data_addr == LLDB_INVALID_ADDRESS) 361 return false; 362 363 clang::ASTContext* ast = valobj.GetClangAST(); 364 365 if (!ast) 366 return false; 367 368 uint32_t wchar_size = ClangASTType::GetClangTypeBitWidth(ast, ClangASTType::GetBasicType(ast, lldb::eBasicTypeWChar).GetOpaqueQualType()); 369 370 switch (wchar_size) 371 { 372 case 8: 373 // utf 8 374 return ReadUTFBufferAndDumpToStream<UTF8>(nullptr, data_addr, 375 process_sp, 376 stream, 377 'L'); 378 case 16: 379 // utf 16 380 return ReadUTFBufferAndDumpToStream<UTF16>(ConvertUTF16toUTF8, data_addr, 381 process_sp, 382 stream, 383 'L'); 384 case 32: 385 // utf 32 386 return ReadUTFBufferAndDumpToStream<UTF32>(ConvertUTF32toUTF8, data_addr, 387 process_sp, 388 stream, 389 'L'); 390 default: 391 stream.Printf("size for wchar_t is not valid"); 392 return true; 393 } 394 return true; 395} 396 397bool 398lldb_private::formatters::Char16SummaryProvider (ValueObject& valobj, Stream& stream) 399{ 400 DataExtractor data; 401 valobj.GetData(data); 402 403 std::string value; 404 valobj.GetValueAsCString(lldb::eFormatUnicode16, value); 405 if (!value.empty()) 406 stream.Printf("%s ", value.c_str()); 407 408 return DumpUTFBufferToStream<UTF16>(ConvertUTF16toUTF8,data,stream, 'u','\'',1); 409} 410 411bool 412lldb_private::formatters::Char32SummaryProvider (ValueObject& valobj, Stream& stream) 413{ 414 DataExtractor data; 415 valobj.GetData(data); 416 417 std::string value; 418 valobj.GetValueAsCString(lldb::eFormatUnicode32, value); 419 if (!value.empty()) 420 stream.Printf("%s ", value.c_str()); 421 422 return DumpUTFBufferToStream<UTF32>(ConvertUTF32toUTF8,data,stream, 'U','\'',1); 423} 424 425bool 426lldb_private::formatters::WCharSummaryProvider (ValueObject& valobj, Stream& stream) 427{ 428 DataExtractor data; 429 valobj.GetData(data); 430 431 clang::ASTContext* ast = valobj.GetClangAST(); 432 433 if (!ast) 434 return false; 435 436 std::string value; 437 438 uint32_t wchar_size = ClangASTType::GetClangTypeBitWidth(ast, ClangASTType::GetBasicType(ast, lldb::eBasicTypeWChar).GetOpaqueQualType()); 439 440 switch (wchar_size) 441 { 442 case 8: 443 // utf 8 444 valobj.GetValueAsCString(lldb::eFormatChar, value); 445 if (!value.empty()) 446 stream.Printf("%s ", value.c_str()); 447 return DumpUTFBufferToStream<UTF8>(nullptr, 448 data, 449 stream, 450 'L', 451 '\'', 452 1); 453 case 16: 454 // utf 16 455 valobj.GetValueAsCString(lldb::eFormatUnicode16, value); 456 if (!value.empty()) 457 stream.Printf("%s ", value.c_str()); 458 return DumpUTFBufferToStream<UTF16>(ConvertUTF16toUTF8, 459 data, 460 stream, 461 'L', 462 '\'', 463 1); 464 case 32: 465 // utf 32 466 valobj.GetValueAsCString(lldb::eFormatUnicode32, value); 467 if (!value.empty()) 468 stream.Printf("%s ", value.c_str()); 469 return DumpUTFBufferToStream<UTF32>(ConvertUTF32toUTF8, 470 data, 471 stream, 472 'L', 473 '\'', 474 1); 475 default: 476 stream.Printf("size for wchar_t is not valid"); 477 return true; 478 } 479 return true; 480} 481 482// this function extracts information from a libcxx std::basic_string<> 483// irregardless of template arguments. it reports the size (in item count not bytes) 484// and the location in memory where the string data can be found 485static bool 486ExtractLibcxxStringInfo (ValueObject& valobj, 487 ValueObjectSP &location_sp, 488 uint64_t& size) 489{ 490 ValueObjectSP D(valobj.GetChildAtIndexPath({0,0,0,0})); 491 if (!D) 492 return false; 493 494 ValueObjectSP size_mode(D->GetChildAtIndexPath({1,0,0})); 495 if (!size_mode) 496 return false; 497 498 uint64_t size_mode_value(size_mode->GetValueAsUnsigned(0)); 499 500 if ((size_mode_value & 1) == 0) // this means the string is in short-mode and the data is stored inline 501 { 502 ValueObjectSP s(D->GetChildAtIndex(1, true)); 503 if (!s) 504 return false; 505 size = ((size_mode_value >> 1) % 256); 506 location_sp = s->GetChildAtIndex(1, true); 507 return (location_sp.get() != nullptr); 508 } 509 else 510 { 511 ValueObjectSP l(D->GetChildAtIndex(0, true)); 512 if (!l) 513 return false; 514 location_sp = l->GetChildAtIndex(2, true); 515 ValueObjectSP size_vo(l->GetChildAtIndex(1, true)); 516 if (!size_vo || !location_sp) 517 return false; 518 size = size_vo->GetValueAsUnsigned(0); 519 return true; 520 } 521} 522 523bool 524lldb_private::formatters::LibcxxWStringSummaryProvider (ValueObject& valobj, Stream& stream) 525{ 526 uint64_t size = 0; 527 ValueObjectSP location_sp((ValueObject*)nullptr); 528 if (!ExtractLibcxxStringInfo(valobj, location_sp, size)) 529 return false; 530 if (size == 0) 531 { 532 stream.Printf("L\"\""); 533 return true; 534 } 535 if (!location_sp) 536 return false; 537 return WCharStringSummaryProvider(*location_sp.get(), stream); 538} 539 540bool 541lldb_private::formatters::LibcxxStringSummaryProvider (ValueObject& valobj, Stream& stream) 542{ 543 uint64_t size = 0; 544 ValueObjectSP location_sp((ValueObject*)nullptr); 545 if (!ExtractLibcxxStringInfo(valobj, location_sp, size)) 546 return false; 547 if (size == 0) 548 { 549 stream.Printf("\"\""); 550 return true; 551 } 552 if (!location_sp) 553 return false; 554 Error error; 555 if (location_sp->ReadPointedString(stream, 556 error, 557 0, // max length is decided by the settings 558 false) == 0) // do not honor array (terminates on first 0 byte even for a char[]) 559 stream.Printf("\"\""); // if nothing was read, print an empty string 560 return error.Success(); 561} 562 563bool 564lldb_private::formatters::ObjCClassSummaryProvider (ValueObject& valobj, Stream& stream) 565{ 566 ProcessSP process_sp = valobj.GetProcessSP(); 567 if (!process_sp) 568 return false; 569 570 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 571 572 if (!runtime) 573 return false; 574 575 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj.GetValueAsUnsigned(0))); 576 577 if (!descriptor.get() || !descriptor->IsValid()) 578 return false; 579 580 const char* class_name = descriptor->GetClassName().GetCString(); 581 582 if (!class_name || !*class_name) 583 return false; 584 585 stream.Printf("%s",class_name); 586 return true; 587} 588 589template<bool needs_at> 590bool 591lldb_private::formatters::NSDataSummaryProvider (ValueObject& valobj, Stream& stream) 592{ 593 ProcessSP process_sp = valobj.GetProcessSP(); 594 if (!process_sp) 595 return false; 596 597 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 598 599 if (!runtime) 600 return false; 601 602 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj)); 603 604 if (!descriptor.get() || !descriptor->IsValid()) 605 return false; 606 607 bool is_64bit = (process_sp->GetAddressByteSize() == 8); 608 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 609 610 if (!valobj_addr) 611 return false; 612 613 uint64_t value = 0; 614 615 const char* class_name = descriptor->GetClassName().GetCString(); 616 617 if (!class_name || !*class_name) 618 return false; 619 620 if (!strcmp(class_name,"NSConcreteData") || 621 !strcmp(class_name,"NSConcreteMutableData") || 622 !strcmp(class_name,"__NSCFData")) 623 { 624 uint32_t offset = (is_64bit ? 16 : 8); 625 Error error; 626 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + offset, is_64bit ? 8 : 4, 0, error); 627 if (error.Fail()) 628 return false; 629 } 630 else 631 { 632 if (!ExtractValueFromObjCExpression(valobj, "int", "length", value)) 633 return false; 634 } 635 636 stream.Printf("%s%" PRIu64 " byte%s%s", 637 (needs_at ? "@\"" : ""), 638 value, 639 (value > 1 ? "s" : ""), 640 (needs_at ? "\"" : "")); 641 642 return true; 643} 644 645bool 646lldb_private::formatters::NSBundleSummaryProvider (ValueObject& valobj, Stream& stream) 647{ 648 ProcessSP process_sp = valobj.GetProcessSP(); 649 if (!process_sp) 650 return false; 651 652 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 653 654 if (!runtime) 655 return false; 656 657 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj)); 658 659 if (!descriptor.get() || !descriptor->IsValid()) 660 return false; 661 662 uint32_t ptr_size = process_sp->GetAddressByteSize(); 663 664 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 665 666 if (!valobj_addr) 667 return false; 668 669 const char* class_name = descriptor->GetClassName().GetCString(); 670 671 if (!class_name || !*class_name) 672 return false; 673 674 if (!strcmp(class_name,"NSBundle")) 675 { 676 uint64_t offset = 5 * ptr_size; 677 ClangASTType type(valobj.GetClangAST(),valobj.GetClangType()); 678 ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset, type, true)); 679 StreamString summary_stream; 680 bool was_nsstring_ok = NSStringSummaryProvider(*text.get(), summary_stream); 681 if (was_nsstring_ok && summary_stream.GetSize() > 0) 682 { 683 stream.Printf("%s",summary_stream.GetData()); 684 return true; 685 } 686 } 687 // this is either an unknown subclass or an NSBundle that comes from [NSBundle mainBundle] 688 // which is encoded differently and needs to be handled by running code 689 return ExtractSummaryFromObjCExpression(valobj, "NSString*", "bundlePath", stream); 690} 691 692bool 693lldb_private::formatters::NSTimeZoneSummaryProvider (ValueObject& valobj, Stream& stream) 694{ 695 ProcessSP process_sp = valobj.GetProcessSP(); 696 if (!process_sp) 697 return false; 698 699 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 700 701 if (!runtime) 702 return false; 703 704 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj)); 705 706 if (!descriptor.get() || !descriptor->IsValid()) 707 return false; 708 709 uint32_t ptr_size = process_sp->GetAddressByteSize(); 710 711 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 712 713 if (!valobj_addr) 714 return false; 715 716 const char* class_name = descriptor->GetClassName().GetCString(); 717 718 if (!class_name || !*class_name) 719 return false; 720 721 if (!strcmp(class_name,"__NSTimeZone")) 722 { 723 uint64_t offset = ptr_size; 724 ClangASTType type(valobj.GetClangAST(),valobj.GetClangType()); 725 ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset, type, true)); 726 StreamString summary_stream; 727 bool was_nsstring_ok = NSStringSummaryProvider(*text.get(), summary_stream); 728 if (was_nsstring_ok && summary_stream.GetSize() > 0) 729 { 730 stream.Printf("%s",summary_stream.GetData()); 731 return true; 732 } 733 } 734 return ExtractSummaryFromObjCExpression(valobj, "NSString*", "name", stream); 735} 736 737bool 738lldb_private::formatters::NSNotificationSummaryProvider (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 if (!strcmp(class_name,"NSConcreteNotification")) 767 { 768 uint64_t offset = ptr_size; 769 ClangASTType type(valobj.GetClangAST(),valobj.GetClangType()); 770 ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset, type, true)); 771 StreamString summary_stream; 772 bool was_nsstring_ok = NSStringSummaryProvider(*text.get(), summary_stream); 773 if (was_nsstring_ok && summary_stream.GetSize() > 0) 774 { 775 stream.Printf("%s",summary_stream.GetData()); 776 return true; 777 } 778 } 779 // this is either an unknown subclass or an NSBundle that comes from [NSBundle mainBundle] 780 // which is encoded differently and needs to be handled by running code 781 return ExtractSummaryFromObjCExpression(valobj, "NSString*", "name", stream); 782} 783 784bool 785lldb_private::formatters::NSMachPortSummaryProvider (ValueObject& valobj, Stream& stream) 786{ 787 ProcessSP process_sp = valobj.GetProcessSP(); 788 if (!process_sp) 789 return false; 790 791 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 792 793 if (!runtime) 794 return false; 795 796 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj)); 797 798 if (!descriptor.get() || !descriptor->IsValid()) 799 return false; 800 801 uint32_t ptr_size = process_sp->GetAddressByteSize(); 802 803 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 804 805 if (!valobj_addr) 806 return false; 807 808 const char* class_name = descriptor->GetClassName().GetCString(); 809 810 if (!class_name || !*class_name) 811 return false; 812 813 uint64_t port_number = 0; 814 815 do 816 { 817 if (!strcmp(class_name,"NSMachPort")) 818 { 819 uint64_t offset = (ptr_size == 4 ? 12 : 20); 820 Error error; 821 port_number = process_sp->ReadUnsignedIntegerFromMemory(offset+valobj_addr, 4, 0, error); 822 if (error.Success()) 823 break; 824 } 825 if (!ExtractValueFromObjCExpression(valobj, "int", "machPort", port_number)) 826 return false; 827 } while (false); 828 829 stream.Printf("mach port: %u",(uint32_t)(port_number & 0x00000000FFFFFFFF)); 830 return true; 831} 832 833bool 834lldb_private::formatters::CFBagSummaryProvider (ValueObject& valobj, Stream& stream) 835{ 836 ProcessSP process_sp = valobj.GetProcessSP(); 837 if (!process_sp) 838 return false; 839 840 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 841 842 if (!runtime) 843 return false; 844 845 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj)); 846 847 if (!descriptor.get() || !descriptor->IsValid()) 848 return false; 849 850 uint32_t ptr_size = process_sp->GetAddressByteSize(); 851 852 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 853 854 if (!valobj_addr) 855 return false; 856 857 uint32_t count = 0; 858 859 bool is_type_ok = false; // check to see if this is a CFBag we know about 860 if (descriptor->IsCFType()) 861 { 862 ConstString type_name(valobj.GetTypeName()); 863 if (type_name == ConstString("__CFBag") || type_name == ConstString("const struct __CFBag")) 864 { 865 if (valobj.IsPointerType()) 866 is_type_ok = true; 867 } 868 } 869 870 if (is_type_ok == false) 871 { 872 StackFrameSP frame_sp(valobj.GetFrameSP()); 873 if (!frame_sp) 874 return false; 875 ValueObjectSP count_sp; 876 StreamString expr; 877 expr.Printf("(int)CFBagGetCount((void*)0x%" PRIx64 ")",valobj.GetPointerValue()); 878 if (process_sp->GetTarget().EvaluateExpression(expr.GetData(), frame_sp.get(), count_sp) != eExecutionCompleted) 879 return false; 880 if (!count_sp) 881 return false; 882 count = count_sp->GetValueAsUnsigned(0); 883 } 884 else 885 { 886 uint32_t offset = 2*ptr_size+4 + valobj_addr; 887 Error error; 888 count = process_sp->ReadUnsignedIntegerFromMemory(offset, 4, 0, error); 889 if (error.Fail()) 890 return false; 891 } 892 stream.Printf("@\"%u value%s\"", 893 count,(count == 1 ? "" : "s")); 894 return true; 895} 896 897bool 898lldb_private::formatters::CFBitVectorSummaryProvider (ValueObject& valobj, Stream& stream) 899{ 900 ProcessSP process_sp = valobj.GetProcessSP(); 901 if (!process_sp) 902 return false; 903 904 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 905 906 if (!runtime) 907 return false; 908 909 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj)); 910 911 if (!descriptor.get() || !descriptor->IsValid()) 912 return false; 913 914 uint32_t ptr_size = process_sp->GetAddressByteSize(); 915 916 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 917 918 if (!valobj_addr) 919 return false; 920 921 uint32_t count = 0; 922 923 bool is_type_ok = false; // check to see if this is a CFBag we know about 924 if (descriptor->IsCFType()) 925 { 926 ConstString type_name(valobj.GetTypeName()); 927 if (type_name == ConstString("__CFMutableBitVector") || type_name == ConstString("__CFBitVector") || type_name == ConstString("CFMutableBitVectorRef") || type_name == ConstString("CFBitVectorRef")) 928 { 929 if (valobj.IsPointerType()) 930 is_type_ok = true; 931 } 932 } 933 934 if (is_type_ok == false) 935 return false; 936 937 Error error; 938 count = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+2*ptr_size, ptr_size, 0, error); 939 if (error.Fail()) 940 return false; 941 uint64_t num_bytes = count / 8 + ((count & 7) ? 1 : 0); 942 addr_t data_ptr = process_sp->ReadPointerFromMemory(valobj_addr+2*ptr_size+2*ptr_size, error); 943 if (error.Fail()) 944 return false; 945 // make sure we do not try to read huge amounts of data 946 if (num_bytes > 1024) 947 num_bytes = 1024; 948 DataBufferSP buffer_sp(new DataBufferHeap(num_bytes,0)); 949 num_bytes = process_sp->ReadMemory(data_ptr, buffer_sp->GetBytes(), num_bytes, error); 950 if (error.Fail()) 951 return false; 952 for (int byte_idx = 0; byte_idx < num_bytes-1; byte_idx++) 953 { 954 uint8_t byte = buffer_sp->GetBytes()[byte_idx]; 955 bool bit0 = (byte & 1) == 1; 956 bool bit1 = (byte & 2) == 2; 957 bool bit2 = (byte & 4) == 4; 958 bool bit3 = (byte & 8) == 8; 959 bool bit4 = (byte & 16) == 16; 960 bool bit5 = (byte & 32) == 32; 961 bool bit6 = (byte & 64) == 64; 962 bool bit7 = (byte & 128) == 128; 963 stream.Printf("%c%c%c%c %c%c%c%c ", 964 (bit7 ? '1' : '0'), 965 (bit6 ? '1' : '0'), 966 (bit5 ? '1' : '0'), 967 (bit4 ? '1' : '0'), 968 (bit3 ? '1' : '0'), 969 (bit2 ? '1' : '0'), 970 (bit1 ? '1' : '0'), 971 (bit0 ? '1' : '0')); 972 count -= 8; 973 } 974 { 975 // print the last byte ensuring we do not print spurious bits 976 uint8_t byte = buffer_sp->GetBytes()[num_bytes-1]; 977 bool bit0 = (byte & 1) == 1; 978 bool bit1 = (byte & 2) == 2; 979 bool bit2 = (byte & 4) == 4; 980 bool bit3 = (byte & 8) == 8; 981 bool bit4 = (byte & 16) == 16; 982 bool bit5 = (byte & 32) == 32; 983 bool bit6 = (byte & 64) == 64; 984 bool bit7 = (byte & 128) == 128; 985 if (count) 986 { 987 stream.Printf("%c",bit7 ? '1' : '0'); 988 count -= 1; 989 } 990 if (count) 991 { 992 stream.Printf("%c",bit6 ? '1' : '0'); 993 count -= 1; 994 } 995 if (count) 996 { 997 stream.Printf("%c",bit5 ? '1' : '0'); 998 count -= 1; 999 } 1000 if (count) 1001 { 1002 stream.Printf("%c",bit4 ? '1' : '0'); 1003 count -= 1; 1004 } 1005 if (count) 1006 { 1007 stream.Printf("%c",bit3 ? '1' : '0'); 1008 count -= 1; 1009 } 1010 if (count) 1011 { 1012 stream.Printf("%c",bit2 ? '1' : '0'); 1013 count -= 1; 1014 } 1015 if (count) 1016 { 1017 stream.Printf("%c",bit1 ? '1' : '0'); 1018 count -= 1; 1019 } 1020 if (count) 1021 { 1022 stream.Printf("%c",bit0 ? '1' : '0'); 1023 count -= 1; 1024 } 1025 } 1026 return true; 1027} 1028 1029bool 1030lldb_private::formatters::CFBinaryHeapSummaryProvider (ValueObject& valobj, Stream& stream) 1031{ 1032 ProcessSP process_sp = valobj.GetProcessSP(); 1033 if (!process_sp) 1034 return false; 1035 1036 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 1037 1038 if (!runtime) 1039 return false; 1040 1041 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj)); 1042 1043 if (!descriptor.get() || !descriptor->IsValid()) 1044 return false; 1045 1046 uint32_t ptr_size = process_sp->GetAddressByteSize(); 1047 1048 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 1049 1050 if (!valobj_addr) 1051 return false; 1052 1053 uint32_t count = 0; 1054 1055 bool is_type_ok = false; // check to see if this is a CFBinaryHeap we know about 1056 if (descriptor->IsCFType()) 1057 { 1058 ConstString type_name(valobj.GetTypeName()); 1059 if (type_name == ConstString("__CFBinaryHeap") || type_name == ConstString("const struct __CFBinaryHeap")) 1060 { 1061 if (valobj.IsPointerType()) 1062 is_type_ok = true; 1063 } 1064 } 1065 1066 if (is_type_ok == false) 1067 { 1068 StackFrameSP frame_sp(valobj.GetFrameSP()); 1069 if (!frame_sp) 1070 return false; 1071 ValueObjectSP count_sp; 1072 StreamString expr; 1073 expr.Printf("(int)CFBinaryHeapGetCount((void*)0x%" PRIx64 ")",valobj.GetPointerValue()); 1074 if (process_sp->GetTarget().EvaluateExpression(expr.GetData(), frame_sp.get(), count_sp) != eExecutionCompleted) 1075 return false; 1076 if (!count_sp) 1077 return false; 1078 count = count_sp->GetValueAsUnsigned(0); 1079 } 1080 else 1081 { 1082 uint32_t offset = 2*ptr_size; 1083 Error error; 1084 count = process_sp->ReadUnsignedIntegerFromMemory(offset, 4, 0, error); 1085 if (error.Fail()) 1086 return false; 1087 } 1088 stream.Printf("@\"%u item%s\"", 1089 count,(count == 1 ? "" : "s")); 1090 return true; 1091} 1092 1093bool 1094lldb_private::formatters::NSIndexSetSummaryProvider (ValueObject& valobj, Stream& stream) 1095{ 1096 ProcessSP process_sp = valobj.GetProcessSP(); 1097 if (!process_sp) 1098 return false; 1099 1100 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 1101 1102 if (!runtime) 1103 return false; 1104 1105 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj)); 1106 1107 if (!descriptor.get() || !descriptor->IsValid()) 1108 return false; 1109 1110 uint32_t ptr_size = process_sp->GetAddressByteSize(); 1111 1112 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 1113 1114 if (!valobj_addr) 1115 return false; 1116 1117 const char* class_name = descriptor->GetClassName().GetCString(); 1118 1119 if (!class_name || !*class_name) 1120 return false; 1121 1122 uint64_t count = 0; 1123 1124 do { 1125 if (!strcmp(class_name,"NSIndexSet") || !strcmp(class_name,"NSMutableIndexSet")) 1126 { 1127 Error error; 1128 uint32_t mode = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+ptr_size, 4, 0, error); 1129 if (error.Fail()) 1130 return false; 1131 // this means the set is empty - count = 0 1132 if ((mode & 1) == 1) 1133 { 1134 count = 0; 1135 break; 1136 } 1137 if ((mode & 2) == 2) 1138 mode = 1; // this means the set only has one range 1139 else 1140 mode = 2; // this means the set has multiple ranges 1141 if (mode == 1) 1142 { 1143 count = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+3*ptr_size, ptr_size, 0, error); 1144 if (error.Fail()) 1145 return false; 1146 } 1147 else 1148 { 1149 // read a pointer to the data at 2*ptr_size 1150 count = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+2*ptr_size, ptr_size, 0, error); 1151 if (error.Fail()) 1152 return false; 1153 // read the data at 2*ptr_size from the first location 1154 count = process_sp->ReadUnsignedIntegerFromMemory(count+2*ptr_size, ptr_size, 0, error); 1155 if (error.Fail()) 1156 return false; 1157 } 1158 } 1159 else 1160 { 1161 if (!ExtractValueFromObjCExpression(valobj, "unsigned long long int", "count", count)) 1162 return false; 1163 } 1164 } while (false); 1165 stream.Printf("%llu index%s", 1166 count, 1167 (count == 1 ? "" : "es")); 1168 return true; 1169} 1170 1171bool 1172lldb_private::formatters::NSNumberSummaryProvider (ValueObject& valobj, Stream& stream) 1173{ 1174 ProcessSP process_sp = valobj.GetProcessSP(); 1175 if (!process_sp) 1176 return false; 1177 1178 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 1179 1180 if (!runtime) 1181 return false; 1182 1183 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj)); 1184 1185 if (!descriptor.get() || !descriptor->IsValid()) 1186 return false; 1187 1188 uint32_t ptr_size = process_sp->GetAddressByteSize(); 1189 1190 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 1191 1192 if (!valobj_addr) 1193 return false; 1194 1195 const char* class_name = descriptor->GetClassName().GetCString(); 1196 1197 if (!class_name || !*class_name) 1198 return false; 1199 1200 if (!strcmp(class_name,"NSNumber") || !strcmp(class_name,"__NSCFNumber")) 1201 { 1202 if (descriptor->IsTagged()) 1203 { 1204 // we have a call to get info and value bits in the tagged descriptor. but we prefer not to cast and replicate them 1205 int64_t value = (valobj_addr & ~0x0000000000000000FFL) >> 8; 1206 uint64_t i_bits = (valobj_addr & 0xF0) >> 4; 1207 1208 switch (i_bits) 1209 { 1210 case 0: 1211 stream.Printf("(char)%hhd",(char)value); 1212 break; 1213 case 4: 1214 stream.Printf("(short)%hd",(short)value); 1215 break; 1216 case 8: 1217 stream.Printf("(int)%d",(int)value); 1218 break; 1219 case 12: 1220 stream.Printf("(long)%" PRId64,value); 1221 break; 1222 default: 1223 stream.Printf("unexpected value:(info=%" PRIu64 ", value=%" PRIu64,i_bits,value); 1224 break; 1225 } 1226 return true; 1227 } 1228 else 1229 { 1230 Error error; 1231 uint8_t data_type = (process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, 1, 0, error) & 0x1F); 1232 uint64_t data_location = valobj_addr + 2*ptr_size; 1233 uint64_t value = 0; 1234 if (error.Fail()) 1235 return false; 1236 switch (data_type) 1237 { 1238 case 1: // 0B00001 1239 value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 1, 0, error); 1240 if (error.Fail()) 1241 return false; 1242 stream.Printf("(char)%hhd",(char)value); 1243 break; 1244 case 2: // 0B0010 1245 value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 2, 0, error); 1246 if (error.Fail()) 1247 return false; 1248 stream.Printf("(short)%hd",(short)value); 1249 break; 1250 case 3: // 0B0011 1251 value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 4, 0, error); 1252 if (error.Fail()) 1253 return false; 1254 stream.Printf("(int)%d",(int)value); 1255 break; 1256 case 17: // 0B10001 1257 data_location += 8; 1258 case 4: // 0B0100 1259 value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 8, 0, error); 1260 if (error.Fail()) 1261 return false; 1262 stream.Printf("(long)%" PRId64,value); 1263 break; 1264 case 5: // 0B0101 1265 { 1266 uint32_t flt_as_int = process_sp->ReadUnsignedIntegerFromMemory(data_location, 4, 0, error); 1267 if (error.Fail()) 1268 return false; 1269 float flt_value = *((float*)&flt_as_int); 1270 stream.Printf("(float)%f",flt_value); 1271 break; 1272 } 1273 case 6: // 0B0110 1274 { 1275 uint64_t dbl_as_lng = process_sp->ReadUnsignedIntegerFromMemory(data_location, 8, 0, error); 1276 if (error.Fail()) 1277 return false; 1278 double dbl_value = *((double*)&dbl_as_lng); 1279 stream.Printf("(double)%g",dbl_value); 1280 break; 1281 } 1282 default: 1283 stream.Printf("absurd: dt=%d",data_type); 1284 break; 1285 } 1286 return true; 1287 } 1288 } 1289 else 1290 { 1291 return ExtractSummaryFromObjCExpression(valobj, "NSString*", "stringValue", stream); 1292 } 1293} 1294 1295static bool 1296ReadAsciiBufferAndDumpToStream (lldb::addr_t location, 1297 lldb::ProcessSP& process_sp, 1298 Stream& dest, 1299 size_t size = 0, 1300 Error* error = NULL, 1301 size_t *data_read = NULL, 1302 char prefix_token = '@', 1303 char quote = '"') 1304{ 1305 Error my_error; 1306 size_t my_data_read; 1307 if (!process_sp || location == 0) 1308 return false; 1309 1310 if (size == 0) 1311 size = process_sp->GetTarget().GetMaximumSizeOfStringSummary(); 1312 1313 lldb::DataBufferSP buffer_sp(new DataBufferHeap(size,0)); 1314 1315 my_data_read = process_sp->ReadCStringFromMemory(location, (char*)buffer_sp->GetBytes(), size, my_error); 1316 1317 if (error) 1318 *error = my_error; 1319 if (data_read) 1320 *data_read = my_data_read; 1321 1322 if (my_error.Fail()) 1323 return false; 1324 if (my_data_read) 1325 dest.Printf("%c%c%s%c",prefix_token,quote,(char*)buffer_sp->GetBytes(),quote); 1326 1327 return true; 1328} 1329 1330bool 1331lldb_private::formatters::NSStringSummaryProvider (ValueObject& valobj, Stream& stream) 1332{ 1333 ProcessSP process_sp = valobj.GetProcessSP(); 1334 if (!process_sp) 1335 return false; 1336 1337 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 1338 1339 if (!runtime) 1340 return false; 1341 1342 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj)); 1343 1344 if (!descriptor.get() || !descriptor->IsValid()) 1345 return false; 1346 1347 uint32_t ptr_size = process_sp->GetAddressByteSize(); 1348 1349 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 1350 1351 if (!valobj_addr) 1352 return false; 1353 1354 const char* class_name = descriptor->GetClassName().GetCString(); 1355 1356 if (!class_name || !*class_name) 1357 return false; 1358 1359 uint64_t info_bits_location = valobj_addr + ptr_size; 1360 if (process_sp->GetByteOrder() != lldb::eByteOrderLittle) 1361 info_bits_location += 3; 1362 1363 Error error; 1364 1365 uint8_t info_bits = process_sp->ReadUnsignedIntegerFromMemory(info_bits_location, 1, 0, error); 1366 if (error.Fail()) 1367 return false; 1368 1369 bool is_mutable = (info_bits & 1) == 1; 1370 bool is_inline = (info_bits & 0x60) == 0; 1371 bool has_explicit_length = (info_bits & (1 | 4)) != 4; 1372 bool is_unicode = (info_bits & 0x10) == 0x10; 1373 bool is_special = strcmp(class_name,"NSPathStore2") == 0; 1374 1375 if (strcmp(class_name,"NSString") && 1376 strcmp(class_name,"CFStringRef") && 1377 strcmp(class_name,"CFMutableStringRef") && 1378 strcmp(class_name,"__NSCFConstantString") && 1379 strcmp(class_name,"__NSCFString") && 1380 strcmp(class_name,"NSCFConstantString") && 1381 strcmp(class_name,"NSCFString") && 1382 strcmp(class_name,"NSPathStore2")) 1383 { 1384 // not one of us - but tell me class name 1385 stream.Printf("class name = %s",class_name); 1386 return true; 1387 } 1388 1389 if (is_mutable) 1390 { 1391 uint64_t location = 2 * ptr_size + valobj_addr; 1392 location = process_sp->ReadPointerFromMemory(location, error); 1393 if (error.Fail()) 1394 return false; 1395 if (has_explicit_length and is_unicode) 1396 return ReadUTFBufferAndDumpToStream<UTF16> (ConvertUTF16toUTF8,location, process_sp, stream, '@'); 1397 else 1398 return ReadAsciiBufferAndDumpToStream(location+1,process_sp,stream); 1399 } 1400 else if (is_inline && has_explicit_length && !is_unicode && !is_special && !is_mutable) 1401 { 1402 uint64_t location = 3 * ptr_size + valobj_addr; 1403 return ReadAsciiBufferAndDumpToStream(location,process_sp,stream); 1404 } 1405 else if (is_unicode) 1406 { 1407 uint64_t location = valobj_addr + 2*ptr_size; 1408 if (is_inline) 1409 { 1410 if (!has_explicit_length) 1411 { 1412 stream.Printf("found new combo"); 1413 return true; 1414 } 1415 else 1416 location += ptr_size; 1417 } 1418 else 1419 { 1420 location = process_sp->ReadPointerFromMemory(location, error); 1421 if (error.Fail()) 1422 return false; 1423 } 1424 return ReadUTFBufferAndDumpToStream<UTF16> (ConvertUTF16toUTF8, location, process_sp, stream, '@'); 1425 } 1426 else if (is_special) 1427 { 1428 uint64_t location = valobj_addr + (ptr_size == 8 ? 12 : 8); 1429 return ReadUTFBufferAndDumpToStream<UTF16> (ConvertUTF16toUTF8, location, process_sp, stream, '@'); 1430 } 1431 else if (is_inline) 1432 { 1433 uint64_t location = valobj_addr + 2*ptr_size; 1434 if (!has_explicit_length) 1435 location++; 1436 return ReadAsciiBufferAndDumpToStream(location,process_sp,stream); 1437 } 1438 else 1439 { 1440 uint64_t location = valobj_addr + 2*ptr_size; 1441 location = process_sp->ReadPointerFromMemory(location, error); 1442 if (error.Fail()) 1443 return false; 1444 return ReadAsciiBufferAndDumpToStream(location,process_sp,stream); 1445 } 1446 1447 stream.Printf("class name = %s",class_name); 1448 return true; 1449 1450} 1451 1452bool 1453lldb_private::formatters::NSAttributedStringSummaryProvider (ValueObject& valobj, Stream& stream) 1454{ 1455 TargetSP target_sp(valobj.GetTargetSP()); 1456 if (!target_sp) 1457 return false; 1458 uint32_t addr_size = target_sp->GetArchitecture().GetAddressByteSize(); 1459 uint64_t pointee = valobj.GetValueAsUnsigned(0); 1460 if (!pointee) 1461 return false; 1462 pointee += addr_size; 1463 ClangASTType type(valobj.GetClangAST(),valobj.GetClangType()); 1464 ExecutionContext exe_ctx(target_sp,false); 1465 ValueObjectSP child_ptr_sp(valobj.CreateValueObjectFromAddress("string_ptr", pointee, exe_ctx, type)); 1466 if (!child_ptr_sp) 1467 return false; 1468 DataExtractor data; 1469 child_ptr_sp->GetData(data); 1470 ValueObjectSP child_sp(child_ptr_sp->CreateValueObjectFromData("string_data", data, exe_ctx, type)); 1471 child_sp->GetValueAsUnsigned(0); 1472 if (child_sp) 1473 return NSStringSummaryProvider(*child_sp, stream); 1474 return false; 1475} 1476 1477bool 1478lldb_private::formatters::NSMutableAttributedStringSummaryProvider (ValueObject& valobj, Stream& stream) 1479{ 1480 return NSAttributedStringSummaryProvider(valobj, stream); 1481} 1482 1483bool 1484lldb_private::formatters::RuntimeSpecificDescriptionSummaryProvider (ValueObject& valobj, Stream& stream) 1485{ 1486 stream.Printf("%s",valobj.GetObjectDescription()); 1487 return true; 1488} 1489 1490bool 1491lldb_private::formatters::NSURLSummaryProvider (ValueObject& valobj, Stream& stream) 1492{ 1493 ProcessSP process_sp = valobj.GetProcessSP(); 1494 if (!process_sp) 1495 return false; 1496 1497 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 1498 1499 if (!runtime) 1500 return false; 1501 1502 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj)); 1503 1504 if (!descriptor.get() || !descriptor->IsValid()) 1505 return false; 1506 1507 uint32_t ptr_size = process_sp->GetAddressByteSize(); 1508 1509 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 1510 1511 if (!valobj_addr) 1512 return false; 1513 1514 const char* class_name = descriptor->GetClassName().GetCString(); 1515 1516 if (!class_name || !*class_name) 1517 return false; 1518 1519 if (strcmp(class_name, "NSURL") == 0) 1520 { 1521 uint64_t offset_text = ptr_size + ptr_size + 8; // ISA + pointer + 8 bytes of data (even on 32bit) 1522 uint64_t offset_base = offset_text + ptr_size; 1523 ClangASTType type(valobj.GetClangAST(),valobj.GetClangType()); 1524 ValueObjectSP text(valobj.GetSyntheticChildAtOffset(offset_text, type, true)); 1525 ValueObjectSP base(valobj.GetSyntheticChildAtOffset(offset_base, type, true)); 1526 if (!text) 1527 return false; 1528 if (text->GetValueAsUnsigned(0) == 0) 1529 return false; 1530 StreamString summary; 1531 if (!NSStringSummaryProvider(*text, summary)) 1532 return false; 1533 if (base && base->GetValueAsUnsigned(0)) 1534 { 1535 if (summary.GetSize() > 0) 1536 summary.GetString().resize(summary.GetSize()-1); 1537 summary.Printf(" -- "); 1538 StreamString base_summary; 1539 if (NSURLSummaryProvider(*base, base_summary) && base_summary.GetSize() > 0) 1540 summary.Printf("%s",base_summary.GetSize() > 2 ? base_summary.GetData() + 2 : base_summary.GetData()); 1541 } 1542 if (summary.GetSize()) 1543 { 1544 stream.Printf("%s",summary.GetData()); 1545 return true; 1546 } 1547 } 1548 else 1549 { 1550 return ExtractSummaryFromObjCExpression(valobj, "NSString*", "description", stream); 1551 } 1552 return false; 1553} 1554 1555bool 1556lldb_private::formatters::ObjCBOOLSummaryProvider (ValueObject& valobj, Stream& stream) 1557{ 1558 const uint32_t type_info = ClangASTContext::GetTypeInfo(valobj.GetClangType(), 1559 valobj.GetClangAST(), 1560 NULL); 1561 1562 ValueObjectSP real_guy_sp = valobj.GetSP(); 1563 1564 if (type_info & ClangASTContext::eTypeIsPointer) 1565 { 1566 Error err; 1567 real_guy_sp = valobj.Dereference(err); 1568 if (err.Fail() || !real_guy_sp) 1569 return false; 1570 } 1571 else if (type_info & ClangASTContext::eTypeIsReference) 1572 { 1573 real_guy_sp = valobj.GetChildAtIndex(0, true); 1574 if (!real_guy_sp) 1575 return false; 1576 } 1577 uint64_t value = real_guy_sp->GetValueAsUnsigned(0); 1578 if (value == 0) 1579 { 1580 stream.Printf("NO"); 1581 return true; 1582 } 1583 stream.Printf("YES"); 1584 return true; 1585} 1586 1587template <bool is_sel_ptr> 1588bool 1589lldb_private::formatters::ObjCSELSummaryProvider (ValueObject& valobj, Stream& stream) 1590{ 1591 lldb::ValueObjectSP valobj_sp; 1592 1593 if (!valobj.GetClangAST()) 1594 return false; 1595 void* char_opaque_type = valobj.GetClangAST()->CharTy.getAsOpaquePtr(); 1596 if (!char_opaque_type) 1597 return false; 1598 ClangASTType charstar(valobj.GetClangAST(),ClangASTType::GetPointerType(valobj.GetClangAST(), char_opaque_type)); 1599 1600 ExecutionContext exe_ctx(valobj.GetExecutionContextRef()); 1601 1602 if (is_sel_ptr) 1603 { 1604 lldb::addr_t data_address = valobj.GetValueAsUnsigned(LLDB_INVALID_ADDRESS); 1605 if (data_address == LLDB_INVALID_ADDRESS) 1606 return false; 1607 valobj_sp = ValueObject::CreateValueObjectFromAddress("text", data_address, exe_ctx, charstar); 1608 } 1609 else 1610 { 1611 DataExtractor data; 1612 valobj.GetData(data); 1613 valobj_sp = ValueObject::CreateValueObjectFromData("text", data, exe_ctx, charstar); 1614 } 1615 1616 if (!valobj_sp) 1617 return false; 1618 1619 stream.Printf("%s",valobj_sp->GetSummaryAsCString()); 1620 return true; 1621} 1622 1623// POSIX has an epoch on Jan-1-1970, but Cocoa prefers Jan-1-2001 1624// this call gives the POSIX equivalent of the Cocoa epoch 1625time_t 1626GetOSXEpoch () 1627{ 1628 static time_t epoch = 0; 1629 if (!epoch) 1630 { 1631 tzset(); 1632 tm tm_epoch; 1633 tm_epoch.tm_sec = 0; 1634 tm_epoch.tm_hour = 0; 1635 tm_epoch.tm_min = 0; 1636 tm_epoch.tm_mon = 0; 1637 tm_epoch.tm_mday = 1; 1638 tm_epoch.tm_year = 2001-1900; // for some reason, we need to subtract 1900 from this field. not sure why. 1639 tm_epoch.tm_isdst = -1; 1640 tm_epoch.tm_gmtoff = 0; 1641 tm_epoch.tm_zone = NULL; 1642 epoch = timegm(&tm_epoch); 1643 } 1644 return epoch; 1645} 1646 1647bool 1648lldb_private::formatters::NSDateSummaryProvider (ValueObject& valobj, Stream& stream) 1649{ 1650 ProcessSP process_sp = valobj.GetProcessSP(); 1651 if (!process_sp) 1652 return false; 1653 1654 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 1655 1656 if (!runtime) 1657 return false; 1658 1659 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj)); 1660 1661 if (!descriptor.get() || !descriptor->IsValid()) 1662 return false; 1663 1664 uint32_t ptr_size = process_sp->GetAddressByteSize(); 1665 1666 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 1667 1668 if (!valobj_addr) 1669 return false; 1670 1671 uint64_t date_value_bits = 0; 1672 double date_value = 0.0; 1673 1674 const char* class_name = descriptor->GetClassName().GetCString(); 1675 1676 if (!class_name || !*class_name) 1677 return false; 1678 1679 if (strcmp(class_name,"NSDate") == 0 || 1680 strcmp(class_name,"__NSDate") == 0 || 1681 strcmp(class_name,"__NSTaggedDate") == 0) 1682 { 1683 if (descriptor->IsTagged()) 1684 { 1685 uint64_t info_bits = (valobj_addr & 0xF0ULL) >> 4; 1686 uint64_t value_bits = (valobj_addr & ~0x0000000000000000FFULL) >> 8; 1687 date_value_bits = ((value_bits << 8) | (info_bits << 4)); 1688 date_value = *((double*)&date_value_bits); 1689 } 1690 else 1691 { 1692 Error error; 1693 date_value_bits = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+ptr_size, 8, 0, error); 1694 date_value = *((double*)&date_value_bits); 1695 if (error.Fail()) 1696 return false; 1697 } 1698 } 1699 else if (!strcmp(class_name,"NSCalendarDate")) 1700 { 1701 Error error; 1702 date_value_bits = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr+2*ptr_size, 8, 0, error); 1703 date_value = *((double*)&date_value_bits); 1704 if (error.Fail()) 1705 return false; 1706 } 1707 else 1708 { 1709 if (ExtractValueFromObjCExpression(valobj, "NSTimeInterval", "ExtractValueFromObjCExpression", date_value_bits) == false) 1710 return false; 1711 date_value = *((double*)&date_value_bits); 1712 } 1713 if (date_value == -63114076800) 1714 { 1715 stream.Printf("0001-12-30 00:00:00 +0000"); 1716 return true; 1717 } 1718 // this snippet of code assumes that time_t == seconds since Jan-1-1970 1719 // this is generally true and POSIXly happy, but might break if a library 1720 // vendor decides to get creative 1721 time_t epoch = GetOSXEpoch(); 1722 epoch = epoch + (time_t)date_value; 1723 tm *tm_date = localtime(&epoch); 1724 if (!tm_date) 1725 return false; 1726 std::string buffer(1024,0); 1727 if (strftime (&buffer[0], 1023, "%Z", tm_date) == 0) 1728 return false; 1729 stream.Printf("%04d-%02d-%02d %02d:%02d:%02d %s", tm_date->tm_year+1900, tm_date->tm_mon+1, tm_date->tm_mday, tm_date->tm_hour, tm_date->tm_min, tm_date->tm_sec, buffer.c_str()); 1730 return true; 1731} 1732 1733bool 1734lldb_private::formatters::CFAbsoluteTimeSummaryProvider (ValueObject& valobj, Stream& stream) 1735{ 1736 time_t epoch = GetOSXEpoch(); 1737 epoch = epoch + (time_t)valobj.GetValueAsUnsigned(0); 1738 tm *tm_date = localtime(&epoch); 1739 if (!tm_date) 1740 return false; 1741 std::string buffer(1024,0); 1742 if (strftime (&buffer[0], 1023, "%Z", tm_date) == 0) 1743 return false; 1744 stream.Printf("%04d-%02d-%02d %02d:%02d:%02d %s", tm_date->tm_year+1900, tm_date->tm_mon+1, tm_date->tm_mday, tm_date->tm_hour, tm_date->tm_min, tm_date->tm_sec, buffer.c_str()); 1745 return true; 1746} 1747 1748size_t 1749lldb_private::formatters::ExtractIndexFromString (const char* item_name) 1750{ 1751 if (!item_name || !*item_name) 1752 return UINT32_MAX; 1753 if (*item_name != '[') 1754 return UINT32_MAX; 1755 item_name++; 1756 char* endptr = NULL; 1757 unsigned long int idx = ::strtoul(item_name, &endptr, 0); 1758 if (idx == 0 && endptr == item_name) 1759 return UINT32_MAX; 1760 if (idx == ULONG_MAX) 1761 return UINT32_MAX; 1762 return idx; 1763} 1764 1765lldb_private::formatters::VectorIteratorSyntheticFrontEnd::VectorIteratorSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp, 1766 ConstString item_name) : 1767SyntheticChildrenFrontEnd(*valobj_sp.get()), 1768m_exe_ctx_ref(), 1769m_item_name(item_name), 1770m_item_sp() 1771{ 1772 if (valobj_sp) 1773 Update(); 1774} 1775 1776bool 1777lldb_private::formatters::VectorIteratorSyntheticFrontEnd::Update() 1778{ 1779 ValueObjectSP valobj_sp = m_backend.GetSP(); 1780 if (!valobj_sp) 1781 return false; 1782 1783 if (!valobj_sp) 1784 return false; 1785 1786 ValueObjectSP item_ptr(valobj_sp->GetChildMemberWithName(m_item_name,true)); 1787 if (!item_ptr) 1788 return false; 1789 if (item_ptr->GetValueAsUnsigned(0) == 0) 1790 return false; 1791 Error err; 1792 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 1793 m_item_sp = ValueObject::CreateValueObjectFromAddress("item", item_ptr->GetValueAsUnsigned(0), m_exe_ctx_ref, ClangASTType(item_ptr->GetClangAST(),ClangASTType::GetPointeeType(item_ptr->GetClangType()))); 1794 if (err.Fail()) 1795 m_item_sp.reset(); 1796 return (m_item_sp.get() != NULL); 1797} 1798 1799size_t 1800lldb_private::formatters::VectorIteratorSyntheticFrontEnd::CalculateNumChildren () 1801{ 1802 return 1; 1803} 1804 1805lldb::ValueObjectSP 1806lldb_private::formatters::VectorIteratorSyntheticFrontEnd::GetChildAtIndex (size_t idx) 1807{ 1808 if (idx == 0) 1809 return m_item_sp; 1810 return lldb::ValueObjectSP(); 1811} 1812 1813bool 1814lldb_private::formatters::VectorIteratorSyntheticFrontEnd::MightHaveChildren () 1815{ 1816 return true; 1817} 1818 1819size_t 1820lldb_private::formatters::VectorIteratorSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name) 1821{ 1822 if (name == ConstString("item")) 1823 return 0; 1824 return UINT32_MAX; 1825} 1826 1827lldb_private::formatters::VectorIteratorSyntheticFrontEnd::~VectorIteratorSyntheticFrontEnd () 1828{ 1829} 1830 1831template bool 1832lldb_private::formatters::NSDataSummaryProvider<true> (ValueObject&, Stream&) ; 1833 1834template bool 1835lldb_private::formatters::NSDataSummaryProvider<false> (ValueObject&, Stream&) ; 1836 1837template bool 1838lldb_private::formatters::ObjCSELSummaryProvider<true> (ValueObject&, Stream&) ; 1839 1840template bool 1841lldb_private::formatters::ObjCSELSummaryProvider<false> (ValueObject&, Stream&) ; 1842