CXXFormatterFunctions.cpp revision dcffc1a667665936b3dd33a9861a3de9d1d35636
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 64lldb::ValueObjectSP 65lldb_private::formatters::CallSelectorOnObject (ValueObject &valobj, 66 const char* return_type, 67 const char* selector, 68 uint64_t index) 69{ 70 lldb::ValueObjectSP valobj_sp; 71 if (!return_type || !*return_type) 72 return valobj_sp; 73 if (!selector || !*selector) 74 return valobj_sp; 75 StreamString expr_path_stream; 76 valobj.GetExpressionPath(expr_path_stream, false); 77 StreamString expr; 78 expr.Printf("(%s)[%s %s:%" PRId64 "]",return_type,expr_path_stream.GetData(),selector,index); 79 ExecutionContext exe_ctx (valobj.GetExecutionContextRef()); 80 lldb::ValueObjectSP result_sp; 81 Target* target = exe_ctx.GetTargetPtr(); 82 StackFrame* stack_frame = exe_ctx.GetFramePtr(); 83 if (!target || !stack_frame) 84 return valobj_sp; 85 86 EvaluateExpressionOptions options; 87 options.SetCoerceToId(false) 88 .SetUnwindOnError(true) 89 .SetKeepInMemory(true) 90 .SetUseDynamic(lldb::eDynamicCanRunTarget); 91 92 target->EvaluateExpression(expr.GetData(), 93 stack_frame, 94 valobj_sp, 95 options); 96 return valobj_sp; 97} 98 99lldb::ValueObjectSP 100lldb_private::formatters::CallSelectorOnObject (ValueObject &valobj, 101 const char* return_type, 102 const char* selector, 103 const char* key) 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 if (!key || !*key) 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:%s]",return_type,expr_path_stream.GetData(),selector,key); 116 ExecutionContext exe_ctx (valobj.GetExecutionContextRef()); 117 lldb::ValueObjectSP result_sp; 118 Target* target = exe_ctx.GetTargetPtr(); 119 StackFrame* stack_frame = exe_ctx.GetFramePtr(); 120 if (!target || !stack_frame) 121 return valobj_sp; 122 123 EvaluateExpressionOptions options; 124 options.SetCoerceToId(false) 125 .SetUnwindOnError(true) 126 .SetKeepInMemory(true) 127 .SetUseDynamic(lldb::eDynamicCanRunTarget); 128 129 target->EvaluateExpression(expr.GetData(), 130 stack_frame, 131 valobj_sp, 132 options); 133 return valobj_sp; 134} 135 136// use this call if you already have an LLDB-side buffer for the data 137template<typename SourceDataType> 138static bool 139DumpUTFBufferToStream (ConversionResult (*ConvertFunction) (const SourceDataType**, 140 const SourceDataType*, 141 UTF8**, 142 UTF8*, 143 ConversionFlags), 144 DataExtractor& data, 145 Stream& stream, 146 char prefix_token = '@', 147 char quote = '"', 148 int sourceSize = 0) 149{ 150 if (prefix_token != 0) 151 stream.Printf("%c",prefix_token); 152 if (quote != 0) 153 stream.Printf("%c",quote); 154 if (data.GetByteSize() && data.GetDataStart() && data.GetDataEnd()) 155 { 156 const int bufferSPSize = data.GetByteSize(); 157 if (sourceSize == 0) 158 { 159 const int origin_encoding = 8*sizeof(SourceDataType); 160 sourceSize = bufferSPSize/(origin_encoding >> 2); 161 } 162 163 SourceDataType *data_ptr = (SourceDataType*)data.GetDataStart(); 164 SourceDataType *data_end_ptr = data_ptr + sourceSize; 165 166 while (data_ptr < data_end_ptr) 167 { 168 if (!*data_ptr) 169 { 170 data_end_ptr = data_ptr; 171 break; 172 } 173 data_ptr++; 174 } 175 176 *data_ptr = 0; 177 data_ptr = (SourceDataType*)data.GetDataStart(); 178 179 lldb::DataBufferSP utf8_data_buffer_sp; 180 UTF8* utf8_data_ptr = nullptr; 181 UTF8* utf8_data_end_ptr = nullptr; 182 183 if (ConvertFunction) 184 { 185 utf8_data_buffer_sp.reset(new DataBufferHeap(bufferSPSize,0)); 186 utf8_data_ptr = (UTF8*)utf8_data_buffer_sp->GetBytes(); 187 utf8_data_end_ptr = utf8_data_ptr + bufferSPSize; 188 ConvertFunction ( (const SourceDataType**)&data_ptr, data_end_ptr, &utf8_data_ptr, utf8_data_end_ptr, lenientConversion ); 189 utf8_data_ptr = (UTF8*)utf8_data_buffer_sp->GetBytes(); // needed because the ConvertFunction will change the value of the data_ptr 190 } 191 else 192 { 193 // just copy the pointers - the cast is necessary to make the compiler happy 194 // but this should only happen if we are reading UTF8 data 195 utf8_data_ptr = (UTF8*)data_ptr; 196 utf8_data_end_ptr = (UTF8*)data_end_ptr; 197 } 198 199 // since we tend to accept partial data (and even partially malformed data) 200 // we might end up with no NULL terminator before the end_ptr 201 // hence we need to take a slower route and ensure we stay within boundaries 202 for (;utf8_data_ptr != utf8_data_end_ptr; utf8_data_ptr++) 203 { 204 if (!*utf8_data_ptr) 205 break; 206 stream.Printf("%c",*utf8_data_ptr); 207 } 208 } 209 if (quote != 0) 210 stream.Printf("%c",quote); 211 return true; 212} 213 214template<typename SourceDataType> 215static bool 216ReadUTFBufferAndDumpToStream (ConversionResult (*ConvertFunction) (const SourceDataType**, 217 const SourceDataType*, 218 UTF8**, 219 UTF8*, 220 ConversionFlags), 221 uint64_t location, 222 const ProcessSP& process_sp, 223 Stream& stream, 224 char prefix_token = '@', 225 char quote = '"', 226 int sourceSize = 0) 227{ 228 if (location == 0 || location == LLDB_INVALID_ADDRESS) 229 return false; 230 if (!process_sp) 231 return false; 232 233 const int origin_encoding = 8*sizeof(SourceDataType); 234 if (origin_encoding != 8 && origin_encoding != 16 && origin_encoding != 32) 235 return false; 236 // if not UTF8, I need a conversion function to return proper UTF8 237 if (origin_encoding != 8 && !ConvertFunction) 238 return false; 239 240 if (sourceSize == 0) 241 sourceSize = process_sp->GetTarget().GetMaximumSizeOfStringSummary(); 242 const int bufferSPSize = sourceSize * (origin_encoding >> 2); 243 244 Error error; 245 lldb::DataBufferSP buffer_sp(new DataBufferHeap(bufferSPSize,0)); 246 247 if (!buffer_sp->GetBytes()) 248 return false; 249 250 size_t data_read = process_sp->ReadMemoryFromInferior(location, (char*)buffer_sp->GetBytes(), bufferSPSize, error); 251 if (error.Fail() || data_read == 0) 252 { 253 stream.Printf("unable to read data"); 254 return true; 255 } 256 257 DataExtractor data(buffer_sp, process_sp->GetByteOrder(), process_sp->GetAddressByteSize()); 258 259 return DumpUTFBufferToStream(ConvertFunction, data, stream, prefix_token, quote, sourceSize); 260} 261 262bool 263lldb_private::formatters::Char16StringSummaryProvider (ValueObject& valobj, Stream& stream) 264{ 265 ProcessSP process_sp = valobj.GetProcessSP(); 266 if (!process_sp) 267 return false; 268 269 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 270 271 if (!valobj_addr) 272 return false; 273 274 if (!ReadUTFBufferAndDumpToStream<UTF16>(ConvertUTF16toUTF8,valobj_addr, 275 process_sp, 276 stream, 277 'u')) 278 { 279 stream.Printf("Summary Unavailable"); 280 return true; 281 } 282 283 return true; 284} 285 286bool 287lldb_private::formatters::Char32StringSummaryProvider (ValueObject& valobj, Stream& stream) 288{ 289 ProcessSP process_sp = valobj.GetProcessSP(); 290 if (!process_sp) 291 return false; 292 293 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 294 295 if (!valobj_addr) 296 return false; 297 298 if (!ReadUTFBufferAndDumpToStream<UTF32>(ConvertUTF32toUTF8,valobj_addr, 299 process_sp, 300 stream, 301 'U')) 302 { 303 stream.Printf("Summary Unavailable"); 304 return true; 305 } 306 307 return true; 308} 309 310bool 311lldb_private::formatters::WCharStringSummaryProvider (ValueObject& valobj, Stream& stream) 312{ 313 ProcessSP process_sp = valobj.GetProcessSP(); 314 if (!process_sp) 315 return false; 316 317 lldb::addr_t data_addr = 0; 318 319 if (valobj.IsPointerType()) 320 data_addr = valobj.GetValueAsUnsigned(0); 321 else if (valobj.IsArrayType()) 322 data_addr = valobj.GetAddressOf(); 323 324 if (data_addr == 0 || data_addr == LLDB_INVALID_ADDRESS) 325 return false; 326 327 clang::ASTContext* ast = valobj.GetClangAST(); 328 329 if (!ast) 330 return false; 331 332 uint32_t wchar_size = ClangASTType::GetClangTypeBitWidth(ast, ClangASTType::GetBasicType(ast, lldb::eBasicTypeWChar).GetOpaqueQualType()); 333 334 switch (wchar_size) 335 { 336 case 8: 337 // utf 8 338 return ReadUTFBufferAndDumpToStream<UTF8>(nullptr, data_addr, 339 process_sp, 340 stream, 341 'L'); 342 case 16: 343 // utf 16 344 return ReadUTFBufferAndDumpToStream<UTF16>(ConvertUTF16toUTF8, data_addr, 345 process_sp, 346 stream, 347 'L'); 348 case 32: 349 // utf 32 350 return ReadUTFBufferAndDumpToStream<UTF32>(ConvertUTF32toUTF8, data_addr, 351 process_sp, 352 stream, 353 'L'); 354 default: 355 stream.Printf("size for wchar_t is not valid"); 356 return true; 357 } 358 return true; 359} 360 361bool 362lldb_private::formatters::Char16SummaryProvider (ValueObject& valobj, Stream& stream) 363{ 364 DataExtractor data; 365 valobj.GetData(data); 366 367 std::string value; 368 valobj.GetValueAsCString(lldb::eFormatUnicode16, value); 369 if (!value.empty()) 370 stream.Printf("%s ", value.c_str()); 371 372 return DumpUTFBufferToStream<UTF16>(ConvertUTF16toUTF8,data,stream, 'u','\'',1); 373} 374 375bool 376lldb_private::formatters::Char32SummaryProvider (ValueObject& valobj, Stream& stream) 377{ 378 DataExtractor data; 379 valobj.GetData(data); 380 381 std::string value; 382 valobj.GetValueAsCString(lldb::eFormatUnicode32, value); 383 if (!value.empty()) 384 stream.Printf("%s ", value.c_str()); 385 386 return DumpUTFBufferToStream<UTF32>(ConvertUTF32toUTF8,data,stream, 'U','\'',1); 387} 388 389bool 390lldb_private::formatters::WCharSummaryProvider (ValueObject& valobj, Stream& stream) 391{ 392 DataExtractor data; 393 valobj.GetData(data); 394 395 clang::ASTContext* ast = valobj.GetClangAST(); 396 397 if (!ast) 398 return false; 399 400 std::string value; 401 402 uint32_t wchar_size = ClangASTType::GetClangTypeBitWidth(ast, ClangASTType::GetBasicType(ast, lldb::eBasicTypeWChar).GetOpaqueQualType()); 403 404 switch (wchar_size) 405 { 406 case 8: 407 // utf 8 408 valobj.GetValueAsCString(lldb::eFormatChar, value); 409 if (!value.empty()) 410 stream.Printf("%s ", value.c_str()); 411 return DumpUTFBufferToStream<UTF8>(nullptr, 412 data, 413 stream, 414 'L', 415 '\'', 416 1); 417 case 16: 418 // utf 16 419 valobj.GetValueAsCString(lldb::eFormatUnicode16, value); 420 if (!value.empty()) 421 stream.Printf("%s ", value.c_str()); 422 return DumpUTFBufferToStream<UTF16>(ConvertUTF16toUTF8, 423 data, 424 stream, 425 'L', 426 '\'', 427 1); 428 case 32: 429 // utf 32 430 valobj.GetValueAsCString(lldb::eFormatUnicode32, value); 431 if (!value.empty()) 432 stream.Printf("%s ", value.c_str()); 433 return DumpUTFBufferToStream<UTF32>(ConvertUTF32toUTF8, 434 data, 435 stream, 436 'L', 437 '\'', 438 1); 439 default: 440 stream.Printf("size for wchar_t is not valid"); 441 return true; 442 } 443 return true; 444} 445 446// this function extracts information from a libcxx std::basic_string<> 447// irregardless of template arguments. it reports the size (in item count not bytes) 448// and the location in memory where the string data can be found 449static bool 450ExtractLibcxxStringInfo (ValueObject& valobj, 451 ValueObjectSP &location_sp, 452 uint64_t& size) 453{ 454 ValueObjectSP D(valobj.GetChildAtIndexPath({0,0,0,0})); 455 if (!D) 456 return false; 457 458 ValueObjectSP size_mode(D->GetChildAtIndexPath({1,0,0})); 459 if (!size_mode) 460 return false; 461 462 uint64_t size_mode_value(size_mode->GetValueAsUnsigned(0)); 463 464 if ((size_mode_value & 1) == 0) // this means the string is in short-mode and the data is stored inline 465 { 466 ValueObjectSP s(D->GetChildAtIndex(1, true)); 467 if (!s) 468 return false; 469 size = ((size_mode_value >> 1) % 256); 470 location_sp = s->GetChildAtIndex(1, true); 471 return (location_sp.get() != nullptr); 472 } 473 else 474 { 475 ValueObjectSP l(D->GetChildAtIndex(0, true)); 476 if (!l) 477 return false; 478 location_sp = l->GetChildAtIndex(2, true); 479 ValueObjectSP size_vo(l->GetChildAtIndex(1, true)); 480 if (!size_vo || !location_sp) 481 return false; 482 size = size_vo->GetValueAsUnsigned(0); 483 return true; 484 } 485} 486 487bool 488lldb_private::formatters::LibcxxWStringSummaryProvider (ValueObject& valobj, Stream& stream) 489{ 490 uint64_t size = 0; 491 ValueObjectSP location_sp((ValueObject*)nullptr); 492 if (!ExtractLibcxxStringInfo(valobj, location_sp, size)) 493 return false; 494 if (size == 0) 495 { 496 stream.Printf("L\"\""); 497 return true; 498 } 499 if (!location_sp) 500 return false; 501 return WCharStringSummaryProvider(*location_sp.get(), stream); 502} 503 504bool 505lldb_private::formatters::LibcxxStringSummaryProvider (ValueObject& valobj, Stream& stream) 506{ 507 uint64_t size = 0; 508 ValueObjectSP location_sp((ValueObject*)nullptr); 509 if (!ExtractLibcxxStringInfo(valobj, location_sp, size)) 510 return false; 511 if (size == 0) 512 { 513 stream.Printf("\"\""); 514 return true; 515 } 516 if (!location_sp) 517 return false; 518 Error error; 519 location_sp->ReadPointedString(stream, 520 error, 521 0, // max length is decided by the settings 522 false); // do not honor array (terminates on first 0 byte even for a char[]) 523 return error.Success(); 524} 525 526template<bool name_entries> 527bool 528lldb_private::formatters::NSDictionarySummaryProvider (ValueObject& valobj, Stream& stream) 529{ 530 ProcessSP process_sp = valobj.GetProcessSP(); 531 if (!process_sp) 532 return false; 533 534 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 535 536 if (!runtime) 537 return false; 538 539 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj)); 540 541 if (!descriptor.get() || !descriptor->IsValid()) 542 return false; 543 544 uint32_t ptr_size = process_sp->GetAddressByteSize(); 545 bool is_64bit = (ptr_size == 8); 546 547 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 548 549 if (!valobj_addr) 550 return false; 551 552 uint64_t value = 0; 553 554 const char* class_name = descriptor->GetClassName().GetCString(); 555 556 if (!class_name || !*class_name) 557 return false; 558 559 if (!strcmp(class_name,"__NSDictionaryI")) 560 { 561 Error error; 562 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error); 563 if (error.Fail()) 564 return false; 565 value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U); 566 } 567 else if (!strcmp(class_name,"__NSDictionaryM")) 568 { 569 Error error; 570 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error); 571 if (error.Fail()) 572 return false; 573 value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U); 574 } 575 else if (!strcmp(class_name,"__NSCFDictionary")) 576 { 577 Error error; 578 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + (is_64bit ? 20 : 12), ptr_size, 0, error); 579 if (error.Fail()) 580 return false; 581 if (is_64bit) 582 value &= ~0x0f1f000000000000UL; 583 } 584 else 585 { 586 if (!ExtractValueFromObjCExpression(valobj, "int", "count", value)) 587 return false; 588 } 589 590 stream.Printf("%s%" PRIu64 " %s%s", 591 (name_entries ? "@\"" : ""), 592 value, 593 (name_entries ? (value == 1 ? "entry" : "entries") : (value == 1 ? "key/value pair" : "key/value pairs")), 594 (name_entries ? "\"" : "")); 595 return true; 596} 597 598bool 599lldb_private::formatters::NSArraySummaryProvider (ValueObject& valobj, Stream& stream) 600{ 601 ProcessSP process_sp = valobj.GetProcessSP(); 602 if (!process_sp) 603 return false; 604 605 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 606 607 if (!runtime) 608 return false; 609 610 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj)); 611 612 if (!descriptor.get() || !descriptor->IsValid()) 613 return false; 614 615 uint32_t ptr_size = process_sp->GetAddressByteSize(); 616 617 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 618 619 if (!valobj_addr) 620 return false; 621 622 uint64_t value = 0; 623 624 const char* class_name = descriptor->GetClassName().GetCString(); 625 626 if (!class_name || !*class_name) 627 return false; 628 629 if (!strcmp(class_name,"__NSArrayI")) 630 { 631 Error error; 632 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error); 633 if (error.Fail()) 634 return false; 635 } 636 else if (!strcmp(class_name,"__NSArrayM")) 637 { 638 Error error; 639 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error); 640 if (error.Fail()) 641 return false; 642 } 643 else if (!strcmp(class_name,"__NSCFArray")) 644 { 645 Error error; 646 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + 2 * ptr_size, ptr_size, 0, error); 647 if (error.Fail()) 648 return false; 649 } 650 else 651 { 652 if (!ExtractValueFromObjCExpression(valobj, "int", "count", value)) 653 return false; 654 } 655 656 stream.Printf("@\"%" PRIu64 " object%s\"", 657 value, 658 value == 1 ? "" : "s"); 659 return true; 660} 661 662template<bool needs_at> 663bool 664lldb_private::formatters::NSDataSummaryProvider (ValueObject& valobj, Stream& stream) 665{ 666 ProcessSP process_sp = valobj.GetProcessSP(); 667 if (!process_sp) 668 return false; 669 670 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 671 672 if (!runtime) 673 return false; 674 675 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj)); 676 677 if (!descriptor.get() || !descriptor->IsValid()) 678 return false; 679 680 bool is_64bit = (process_sp->GetAddressByteSize() == 8); 681 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 682 683 if (!valobj_addr) 684 return false; 685 686 uint64_t value = 0; 687 688 const char* class_name = descriptor->GetClassName().GetCString(); 689 690 if (!class_name || !*class_name) 691 return false; 692 693 if (!strcmp(class_name,"NSConcreteData") || 694 !strcmp(class_name,"NSConcreteMutableData") || 695 !strcmp(class_name,"__NSCFData")) 696 { 697 uint32_t offset = (is_64bit ? 16 : 8); 698 Error error; 699 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + offset, is_64bit ? 8 : 4, 0, error); 700 if (error.Fail()) 701 return false; 702 } 703 else 704 { 705 if (!ExtractValueFromObjCExpression(valobj, "int", "length", value)) 706 return false; 707 } 708 709 stream.Printf("%s%" PRIu64 " byte%s%s", 710 (needs_at ? "@\"" : ""), 711 value, 712 (value > 1 ? "s" : ""), 713 (needs_at ? "\"" : "")); 714 715 return true; 716} 717 718bool 719lldb_private::formatters::NSNumberSummaryProvider (ValueObject& valobj, Stream& stream) 720{ 721 ProcessSP process_sp = valobj.GetProcessSP(); 722 if (!process_sp) 723 return false; 724 725 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 726 727 if (!runtime) 728 return false; 729 730 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj)); 731 732 if (!descriptor.get() || !descriptor->IsValid()) 733 return false; 734 735 uint32_t ptr_size = process_sp->GetAddressByteSize(); 736 737 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 738 739 if (!valobj_addr) 740 return false; 741 742 const char* class_name = descriptor->GetClassName().GetCString(); 743 744 if (!class_name || !*class_name) 745 return false; 746 747 if (!strcmp(class_name,"NSNumber") || !strcmp(class_name,"__NSCFNumber")) 748 { 749 if (descriptor->IsTagged()) 750 { 751 // we have a call to get info and value bits in the tagged descriptor. but we prefer not to cast and replicate them 752 int64_t value = (valobj_addr & ~0x0000000000000000FFL) >> 8; 753 uint64_t i_bits = (valobj_addr & 0xF0) >> 4; 754 755 switch (i_bits) 756 { 757 case 0: 758 stream.Printf("(char)%hhd",(char)value); 759 break; 760 case 4: 761 stream.Printf("(short)%hd",(short)value); 762 break; 763 case 8: 764 stream.Printf("(int)%d",(int)value); 765 break; 766 case 12: 767 stream.Printf("(long)%" PRId64,value); 768 break; 769 default: 770 stream.Printf("unexpected value:(info=%" PRIu64 ", value=%" PRIu64,i_bits,value); 771 break; 772 } 773 return true; 774 } 775 else 776 { 777 Error error; 778 uint8_t data_type = (process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, 1, 0, error) & 0x1F); 779 uint64_t data_location = valobj_addr + 2*ptr_size; 780 uint64_t value = 0; 781 if (error.Fail()) 782 return false; 783 switch (data_type) 784 { 785 case 1: // 0B00001 786 value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 1, 0, error); 787 if (error.Fail()) 788 return false; 789 stream.Printf("(char)%hhd",(char)value); 790 break; 791 case 2: // 0B0010 792 value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 2, 0, error); 793 if (error.Fail()) 794 return false; 795 stream.Printf("(short)%hd",(short)value); 796 break; 797 case 3: // 0B0011 798 value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 4, 0, error); 799 if (error.Fail()) 800 return false; 801 stream.Printf("(int)%d",(int)value); 802 break; 803 case 17: // 0B10001 804 data_location += 8; 805 case 4: // 0B0100 806 value = process_sp->ReadUnsignedIntegerFromMemory(data_location, 8, 0, error); 807 if (error.Fail()) 808 return false; 809 stream.Printf("(long)%" PRId64,value); 810 break; 811 case 5: // 0B0101 812 { 813 uint32_t flt_as_int = process_sp->ReadUnsignedIntegerFromMemory(data_location, 4, 0, error); 814 if (error.Fail()) 815 return false; 816 float flt_value = *((float*)&flt_as_int); 817 stream.Printf("(float)%f",flt_value); 818 break; 819 } 820 case 6: // 0B0110 821 { 822 uint64_t dbl_as_lng = process_sp->ReadUnsignedIntegerFromMemory(data_location, 8, 0, error); 823 if (error.Fail()) 824 return false; 825 double dbl_value = *((double*)&dbl_as_lng); 826 stream.Printf("(double)%g",dbl_value); 827 break; 828 } 829 default: 830 stream.Printf("absurd: dt=%d",data_type); 831 break; 832 } 833 return true; 834 } 835 } 836 else 837 { 838 // similar to ExtractValueFromObjCExpression but uses summary instead of value 839 StreamString expr_path_stream; 840 valobj.GetExpressionPath(expr_path_stream, false); 841 StreamString expr; 842 expr.Printf("(NSString*)[%s stringValue]",expr_path_stream.GetData()); 843 ExecutionContext exe_ctx (valobj.GetExecutionContextRef()); 844 lldb::ValueObjectSP result_sp; 845 Target* target = exe_ctx.GetTargetPtr(); 846 StackFrame* stack_frame = exe_ctx.GetFramePtr(); 847 if (!target || !stack_frame) 848 return false; 849 850 EvaluateExpressionOptions options; 851 options.SetCoerceToId(false) 852 .SetUnwindOnError(true) 853 .SetKeepInMemory(true) 854 .SetUseDynamic(lldb::eDynamicCanRunTarget); 855 856 target->EvaluateExpression(expr.GetData(), 857 stack_frame, 858 result_sp, 859 options); 860 if (!result_sp) 861 return false; 862 stream.Printf("%s",result_sp->GetSummaryAsCString()); 863 return true; 864 } 865} 866 867bool 868lldb_private::formatters::NSStringSummaryProvider (ValueObject& valobj, Stream& stream) 869{ 870 ProcessSP process_sp = valobj.GetProcessSP(); 871 if (!process_sp) 872 return false; 873 874 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 875 876 if (!runtime) 877 return false; 878 879 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj)); 880 881 if (!descriptor.get() || !descriptor->IsValid()) 882 return false; 883 884 uint32_t ptr_size = process_sp->GetAddressByteSize(); 885 886 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 887 888 if (!valobj_addr) 889 return false; 890 891 const char* class_name = descriptor->GetClassName().GetCString(); 892 893 if (!class_name || !*class_name) 894 return false; 895 896 uint64_t info_bits_location = valobj_addr + ptr_size; 897 if (process_sp->GetByteOrder() != lldb::eByteOrderLittle) 898 info_bits_location += 3; 899 900 Error error; 901 902 uint8_t info_bits = process_sp->ReadUnsignedIntegerFromMemory(info_bits_location, 1, 0, error); 903 if (error.Fail()) 904 return false; 905 906 bool is_mutable = (info_bits & 1) == 1; 907 bool is_inline = (info_bits & 0x60) == 0; 908 bool has_explicit_length = (info_bits & (1 | 4)) != 4; 909 bool is_unicode = (info_bits & 0x10) == 0x10; 910 bool is_special = strcmp(class_name,"NSPathStore2") == 0; 911 912 if (strcmp(class_name,"NSString") && 913 strcmp(class_name,"CFStringRef") && 914 strcmp(class_name,"CFMutableStringRef") && 915 strcmp(class_name,"__NSCFConstantString") && 916 strcmp(class_name,"__NSCFString") && 917 strcmp(class_name,"NSCFConstantString") && 918 strcmp(class_name,"NSCFString") && 919 strcmp(class_name,"NSPathStore2")) 920 { 921 // probably not one of us - bail out 922 return false; 923 } 924 925 if (is_mutable) 926 { 927 uint64_t location = 2 * ptr_size + valobj_addr; 928 location = process_sp->ReadPointerFromMemory(location, error); 929 if (error.Fail()) 930 return false; 931 if (has_explicit_length and is_unicode) 932 return ReadUTFBufferAndDumpToStream<UTF16> (ConvertUTF16toUTF8,location, process_sp, stream, '@'); 933 else 934 { 935 location++; 936 lldb::DataBufferSP buffer_sp(new DataBufferHeap(1024,0)); 937 size_t data_read = process_sp->ReadCStringFromMemory(location, (char*)buffer_sp->GetBytes(), 1024, error); 938 if (error.Fail()) 939 return false; 940 if (data_read) 941 stream.Printf("@\"%s\"",(char*)buffer_sp->GetBytes()); 942 return true; 943 } 944 } 945 else if (is_inline && has_explicit_length && !is_unicode && !is_special && !is_mutable) 946 { 947 uint64_t location = 3 * ptr_size + valobj_addr; 948 lldb::DataBufferSP buffer_sp(new DataBufferHeap(1024,0)); 949 size_t data_read = process_sp->ReadCStringFromMemory(location, (char*)buffer_sp->GetBytes(), 1024, error); 950 if (error.Fail()) 951 return false; 952 if (data_read) 953 stream.Printf("@\"%s\"",(char*)buffer_sp->GetBytes()); 954 return true; 955 } 956 else if (is_unicode) 957 { 958 uint64_t location = valobj_addr + ptr_size + 4 + (ptr_size == 8 ? 4 : 0); 959 if (is_inline) 960 { 961 if (!has_explicit_length) 962 { 963 stream.Printf("found new combo"); 964 return true; 965 } 966 else 967 location += ptr_size; 968 } 969 else 970 { 971 location = process_sp->ReadPointerFromMemory(location, error); 972 if (error.Fail()) 973 return false; 974 } 975 return ReadUTFBufferAndDumpToStream<UTF16> (ConvertUTF16toUTF8, location, process_sp, stream, '@'); 976 } 977 else if (is_special) 978 { 979 uint64_t location = valobj_addr + (ptr_size == 8 ? 12 : 8); 980 return ReadUTFBufferAndDumpToStream<UTF16> (ConvertUTF16toUTF8, location, process_sp, stream, '@'); 981 } 982 else if (is_inline) 983 { 984 uint64_t location = valobj_addr + ptr_size + 4 + (ptr_size == 8 ? 4 : 0); 985 if (!has_explicit_length) 986 location++; 987 lldb::DataBufferSP buffer_sp(new DataBufferHeap(1024,0)); 988 size_t data_read = process_sp->ReadCStringFromMemory(location, (char*)buffer_sp->GetBytes(), 1024, error); 989 if (error.Fail()) 990 return false; 991 if (data_read) 992 stream.Printf("@\"%s\"",(char*)buffer_sp->GetBytes()); 993 return true; 994 } 995 else 996 { 997 uint64_t location = valobj_addr + ptr_size + 4 + (ptr_size == 8 ? 4 : 0); 998 location = process_sp->ReadPointerFromMemory(location, error); 999 if (error.Fail()) 1000 return false; 1001 lldb::DataBufferSP buffer_sp(new DataBufferHeap(1024,0)); 1002 size_t data_read = process_sp->ReadCStringFromMemory(location, (char*)buffer_sp->GetBytes(), 1024, error); 1003 if (error.Fail()) 1004 return false; 1005 if (data_read) 1006 stream.Printf("@\"%s\"",(char*)buffer_sp->GetBytes()); 1007 return true; 1008 } 1009 1010 stream.Printf("class name = %s",class_name); 1011 return true; 1012 1013} 1014 1015bool 1016lldb_private::formatters::NSAttributedStringSummaryProvider (ValueObject& valobj, Stream& stream) 1017{ 1018 TargetSP target_sp(valobj.GetTargetSP()); 1019 if (!target_sp) 1020 return false; 1021 uint32_t addr_size = target_sp->GetArchitecture().GetAddressByteSize(); 1022 uint64_t pointee = valobj.GetValueAsUnsigned(0); 1023 if (!pointee) 1024 return false; 1025 pointee += addr_size; 1026 ClangASTType type(valobj.GetClangAST(),valobj.GetClangType()); 1027 ExecutionContext exe_ctx(target_sp,false); 1028 ValueObjectSP child_ptr_sp(valobj.CreateValueObjectFromAddress("string_ptr", pointee, exe_ctx, type)); 1029 if (!child_ptr_sp) 1030 return false; 1031 DataExtractor data; 1032 child_ptr_sp->GetData(data); 1033 ValueObjectSP child_sp(child_ptr_sp->CreateValueObjectFromData("string_data", data, exe_ctx, type)); 1034 child_sp->GetValueAsUnsigned(0); 1035 if (child_sp) 1036 return NSStringSummaryProvider(*child_sp, stream); 1037 return false; 1038} 1039 1040bool 1041lldb_private::formatters::NSMutableAttributedStringSummaryProvider (ValueObject& valobj, Stream& stream) 1042{ 1043 return NSAttributedStringSummaryProvider(valobj, stream); 1044} 1045 1046bool 1047lldb_private::formatters::RuntimeSpecificDescriptionSummaryProvider (ValueObject& valobj, Stream& stream) 1048{ 1049 stream.Printf("%s",valobj.GetObjectDescription()); 1050 return true; 1051} 1052 1053bool 1054lldb_private::formatters::ObjCBOOLSummaryProvider (ValueObject& valobj, Stream& stream) 1055{ 1056 const uint32_t type_info = ClangASTContext::GetTypeInfo(valobj.GetClangType(), 1057 valobj.GetClangAST(), 1058 NULL); 1059 1060 ValueObjectSP real_guy_sp = valobj.GetSP(); 1061 1062 if (type_info & ClangASTContext::eTypeIsPointer) 1063 { 1064 Error err; 1065 real_guy_sp = valobj.Dereference(err); 1066 if (err.Fail() || !real_guy_sp) 1067 return false; 1068 } 1069 else if (type_info & ClangASTContext::eTypeIsReference) 1070 { 1071 real_guy_sp = valobj.GetChildAtIndex(0, true); 1072 if (!real_guy_sp) 1073 return false; 1074 } 1075 uint64_t value = real_guy_sp->GetValueAsUnsigned(0); 1076 if (value == 0) 1077 { 1078 stream.Printf("NO"); 1079 return true; 1080 } 1081 stream.Printf("YES"); 1082 return true; 1083} 1084 1085template <bool is_sel_ptr> 1086bool 1087lldb_private::formatters::ObjCSELSummaryProvider (ValueObject& valobj, Stream& stream) 1088{ 1089 lldb::addr_t data_address = LLDB_INVALID_ADDRESS; 1090 1091 if (is_sel_ptr) 1092 data_address = valobj.GetValueAsUnsigned(LLDB_INVALID_ADDRESS); 1093 else 1094 data_address = valobj.GetAddressOf(); 1095 1096 if (data_address == LLDB_INVALID_ADDRESS) 1097 return false; 1098 1099 ExecutionContext exe_ctx(valobj.GetExecutionContextRef()); 1100 1101 void* char_opaque_type = valobj.GetClangAST()->CharTy.getAsOpaquePtr(); 1102 ClangASTType charstar(valobj.GetClangAST(),ClangASTType::GetPointerType(valobj.GetClangAST(), char_opaque_type)); 1103 1104 ValueObjectSP valobj_sp(ValueObject::CreateValueObjectFromAddress("text", data_address, exe_ctx, charstar)); 1105 1106 stream.Printf("%s",valobj_sp->GetSummaryAsCString()); 1107 return true; 1108} 1109 1110lldb_private::formatters::NSArrayMSyntheticFrontEnd::NSArrayMSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) : 1111SyntheticChildrenFrontEnd(*valobj_sp.get()), 1112m_exe_ctx_ref(), 1113m_ptr_size(8), 1114m_data_32(NULL), 1115m_data_64(NULL) 1116{ 1117 if (valobj_sp) 1118 { 1119 m_id_type = ClangASTType(valobj_sp->GetClangAST(),valobj_sp->GetClangAST()->ObjCBuiltinIdTy.getAsOpaquePtr()); 1120 Update(); 1121 } 1122} 1123 1124size_t 1125lldb_private::formatters::NSArrayMSyntheticFrontEnd::CalculateNumChildren () 1126{ 1127 if (m_data_32) 1128 return m_data_32->_used; 1129 if (m_data_64) 1130 return m_data_64->_used; 1131 return 0; 1132} 1133 1134lldb::ValueObjectSP 1135lldb_private::formatters::NSArrayMSyntheticFrontEnd::GetChildAtIndex (size_t idx) 1136{ 1137 if (!m_data_32 && !m_data_64) 1138 return lldb::ValueObjectSP(); 1139 if (idx >= CalculateNumChildren()) 1140 return lldb::ValueObjectSP(); 1141 lldb::addr_t object_at_idx = (m_data_32 ? m_data_32->_data : m_data_64->_data); 1142 object_at_idx += (idx * m_ptr_size); 1143 StreamString idx_name; 1144 idx_name.Printf("[%zu]",idx); 1145 lldb::ValueObjectSP retval_sp = ValueObject::CreateValueObjectFromAddress(idx_name.GetData(), 1146 object_at_idx, 1147 m_exe_ctx_ref, 1148 m_id_type); 1149 m_children.push_back(retval_sp); 1150 return retval_sp; 1151} 1152 1153bool 1154lldb_private::formatters::NSArrayMSyntheticFrontEnd::Update() 1155{ 1156 m_children.clear(); 1157 ValueObjectSP valobj_sp = m_backend.GetSP(); 1158 m_ptr_size = 0; 1159 delete m_data_32; 1160 m_data_32 = NULL; 1161 delete m_data_64; 1162 m_data_64 = NULL; 1163 if (valobj_sp->IsDynamic()) 1164 valobj_sp = valobj_sp->GetStaticValue(); 1165 if (!valobj_sp) 1166 return false; 1167 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 1168 Error error; 1169 if (valobj_sp->IsPointerType()) 1170 { 1171 valobj_sp = valobj_sp->Dereference(error); 1172 if (error.Fail() || !valobj_sp) 1173 return false; 1174 } 1175 error.Clear(); 1176 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 1177 if (!process_sp) 1178 return false; 1179 m_ptr_size = process_sp->GetAddressByteSize(); 1180 uint64_t data_location = valobj_sp->GetAddressOf() + m_ptr_size; 1181 if (m_ptr_size == 4) 1182 { 1183 m_data_32 = new DataDescriptor_32(); 1184 process_sp->ReadMemory (data_location, m_data_32, sizeof(DataDescriptor_32), error); 1185 } 1186 else 1187 { 1188 m_data_64 = new DataDescriptor_64(); 1189 process_sp->ReadMemory (data_location, m_data_64, sizeof(DataDescriptor_64), error); 1190 } 1191 if (error.Fail()) 1192 return false; 1193 return false; 1194} 1195 1196bool 1197lldb_private::formatters::NSArrayMSyntheticFrontEnd::MightHaveChildren () 1198{ 1199 return true; 1200} 1201 1202static uint32_t 1203ExtractIndexFromString (const char* item_name) 1204{ 1205 if (!item_name || !*item_name) 1206 return UINT32_MAX; 1207 if (*item_name != '[') 1208 return UINT32_MAX; 1209 item_name++; 1210 uint32_t idx = 0; 1211 while(*item_name) 1212 { 1213 char x = *item_name; 1214 if (x == ']') 1215 break; 1216 if (x < '0' || x > '9') 1217 return UINT32_MAX; 1218 idx = 10*idx + (x-'0'); 1219 item_name++; 1220 } 1221 return idx; 1222} 1223 1224size_t 1225lldb_private::formatters::NSArrayMSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name) 1226{ 1227 if (!m_data_32 && !m_data_64) 1228 return UINT32_MAX; 1229 const char* item_name = name.GetCString(); 1230 uint32_t idx = ExtractIndexFromString(item_name); 1231 if (idx < UINT32_MAX && idx >= CalculateNumChildren()) 1232 return UINT32_MAX; 1233 return idx; 1234} 1235 1236lldb_private::formatters::NSArrayMSyntheticFrontEnd::~NSArrayMSyntheticFrontEnd () 1237{ 1238 delete m_data_32; 1239 m_data_32 = NULL; 1240 delete m_data_64; 1241 m_data_64 = NULL; 1242} 1243 1244lldb_private::formatters::NSArrayISyntheticFrontEnd::NSArrayISyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) : 1245SyntheticChildrenFrontEnd(*valobj_sp.get()), 1246m_exe_ctx_ref(), 1247m_ptr_size(8), 1248m_items(0), 1249m_data_ptr(0) 1250{ 1251 if (valobj_sp) 1252 { 1253 m_id_type = ClangASTType(valobj_sp->GetClangAST(),valobj_sp->GetClangAST()->ObjCBuiltinIdTy.getAsOpaquePtr()); 1254 Update(); 1255 } 1256} 1257 1258lldb_private::formatters::NSArrayISyntheticFrontEnd::~NSArrayISyntheticFrontEnd () 1259{ 1260} 1261 1262size_t 1263lldb_private::formatters::NSArrayISyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name) 1264{ 1265 const char* item_name = name.GetCString(); 1266 uint32_t idx = ExtractIndexFromString(item_name); 1267 if (idx < UINT32_MAX && idx >= CalculateNumChildren()) 1268 return UINT32_MAX; 1269 return idx; 1270} 1271 1272size_t 1273lldb_private::formatters::NSArrayISyntheticFrontEnd::CalculateNumChildren () 1274{ 1275 return m_items; 1276} 1277 1278bool 1279lldb_private::formatters::NSArrayISyntheticFrontEnd::Update() 1280{ 1281 m_ptr_size = 0; 1282 m_items = 0; 1283 m_data_ptr = 0; 1284 m_children.clear(); 1285 ValueObjectSP valobj_sp = m_backend.GetSP(); 1286 if (valobj_sp->IsDynamic()) 1287 valobj_sp = valobj_sp->GetStaticValue(); 1288 if (!valobj_sp) 1289 return false; 1290 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 1291 Error error; 1292 if (valobj_sp->IsPointerType()) 1293 { 1294 valobj_sp = valobj_sp->Dereference(error); 1295 if (error.Fail() || !valobj_sp) 1296 return false; 1297 } 1298 error.Clear(); 1299 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 1300 if (!process_sp) 1301 return false; 1302 m_ptr_size = process_sp->GetAddressByteSize(); 1303 uint64_t data_location = valobj_sp->GetAddressOf() + m_ptr_size; 1304 m_items = process_sp->ReadPointerFromMemory(data_location, error); 1305 if (error.Fail()) 1306 return false; 1307 m_data_ptr = data_location+m_ptr_size; 1308 return false; 1309} 1310 1311bool 1312lldb_private::formatters::NSArrayISyntheticFrontEnd::MightHaveChildren () 1313{ 1314 return true; 1315} 1316 1317lldb::ValueObjectSP 1318lldb_private::formatters::NSArrayISyntheticFrontEnd::GetChildAtIndex (size_t idx) 1319{ 1320 if (idx >= CalculateNumChildren()) 1321 return lldb::ValueObjectSP(); 1322 lldb::addr_t object_at_idx = m_data_ptr; 1323 object_at_idx += (idx * m_ptr_size); 1324 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP(); 1325 if (!process_sp) 1326 return lldb::ValueObjectSP(); 1327 Error error; 1328 object_at_idx = process_sp->ReadPointerFromMemory(object_at_idx, error); 1329 if (error.Fail()) 1330 return lldb::ValueObjectSP(); 1331 StreamString expr; 1332 expr.Printf("(id)%" PRIu64,object_at_idx); 1333 StreamString idx_name; 1334 idx_name.Printf("[%zu]",idx); 1335 lldb::ValueObjectSP retval_sp = ValueObject::CreateValueObjectFromExpression(idx_name.GetData(), expr.GetData(), m_exe_ctx_ref); 1336 m_children.push_back(retval_sp); 1337 return retval_sp; 1338} 1339 1340SyntheticChildrenFrontEnd* lldb_private::formatters::NSArraySyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp) 1341{ 1342 lldb::ProcessSP process_sp (valobj_sp->GetProcessSP()); 1343 if (!process_sp) 1344 return NULL; 1345 ObjCLanguageRuntime *runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 1346 if (!runtime) 1347 return NULL; 1348 1349 if (!valobj_sp->IsPointerType()) 1350 { 1351 Error error; 1352 valobj_sp = valobj_sp->AddressOf(error); 1353 if (error.Fail() || !valobj_sp) 1354 return NULL; 1355 } 1356 1357 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(*valobj_sp.get())); 1358 1359 if (!descriptor.get() || !descriptor->IsValid()) 1360 return NULL; 1361 1362 const char* class_name = descriptor->GetClassName().GetCString(); 1363 1364 if (!class_name || !*class_name) 1365 return NULL; 1366 1367 if (!strcmp(class_name,"__NSArrayI")) 1368 { 1369 return (new NSArrayISyntheticFrontEnd(valobj_sp)); 1370 } 1371 else if (!strcmp(class_name,"__NSArrayM")) 1372 { 1373 return (new NSArrayMSyntheticFrontEnd(valobj_sp)); 1374 } 1375 else 1376 { 1377 return (new NSArrayCodeRunningSyntheticFrontEnd(valobj_sp)); 1378 } 1379} 1380 1381lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::NSArrayCodeRunningSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) : 1382SyntheticChildrenFrontEnd(*valobj_sp.get()) 1383{} 1384 1385size_t 1386lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::CalculateNumChildren () 1387{ 1388 uint64_t count = 0; 1389 if (ExtractValueFromObjCExpression(m_backend, "int", "count", count)) 1390 return count; 1391 return 0; 1392} 1393 1394lldb::ValueObjectSP 1395lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::GetChildAtIndex (size_t idx) 1396{ 1397 StreamString idx_name; 1398 idx_name.Printf("[%zu]",idx); 1399 lldb::ValueObjectSP valobj_sp = CallSelectorOnObject(m_backend,"id","objectAtIndex:",idx); 1400 if (valobj_sp) 1401 valobj_sp->SetName(ConstString(idx_name.GetData())); 1402 return valobj_sp; 1403} 1404 1405bool 1406lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::Update() 1407{ 1408 return false; 1409} 1410 1411bool 1412lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::MightHaveChildren () 1413{ 1414 return true; 1415} 1416 1417size_t 1418lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name) 1419{ 1420 return 0; 1421} 1422 1423lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::~NSArrayCodeRunningSyntheticFrontEnd () 1424{} 1425 1426SyntheticChildrenFrontEnd* lldb_private::formatters::NSDictionarySyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp) 1427{ 1428 1429 lldb::ProcessSP process_sp (valobj_sp->GetProcessSP()); 1430 if (!process_sp) 1431 return NULL; 1432 ObjCLanguageRuntime *runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 1433 if (!runtime) 1434 return NULL; 1435 1436 if (!valobj_sp->IsPointerType()) 1437 { 1438 Error error; 1439 valobj_sp = valobj_sp->AddressOf(error); 1440 if (error.Fail() || !valobj_sp) 1441 return NULL; 1442 } 1443 1444 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(*valobj_sp.get())); 1445 1446 if (!descriptor.get() || !descriptor->IsValid()) 1447 return NULL; 1448 1449 const char* class_name = descriptor->GetClassName().GetCString(); 1450 1451 if (!class_name || !*class_name) 1452 return NULL; 1453 1454 if (!strcmp(class_name,"__NSDictionaryI")) 1455 { 1456 return (new NSDictionaryISyntheticFrontEnd(valobj_sp)); 1457 } 1458 else if (!strcmp(class_name,"__NSDictionaryM")) 1459 { 1460 return (new NSDictionaryMSyntheticFrontEnd(valobj_sp)); 1461 } 1462 else 1463 { 1464 return (new NSDictionaryCodeRunningSyntheticFrontEnd(valobj_sp)); 1465 } 1466} 1467 1468lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::NSDictionaryCodeRunningSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) : 1469SyntheticChildrenFrontEnd(*valobj_sp.get()) 1470{} 1471 1472size_t 1473lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::CalculateNumChildren () 1474{ 1475 uint64_t count = 0; 1476 if (ExtractValueFromObjCExpression(m_backend, "int", "count", count)) 1477 return count; 1478 return 0; 1479} 1480 1481lldb::ValueObjectSP 1482lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::GetChildAtIndex (size_t idx) 1483{ 1484 StreamString idx_name; 1485 idx_name.Printf("[%zu]",idx); 1486 StreamString valobj_expr_path; 1487 m_backend.GetExpressionPath(valobj_expr_path, false); 1488 StreamString key_fetcher_expr; 1489 key_fetcher_expr.Printf("(id)[(NSArray*)[%s allKeys] objectAtIndex:%zu]",valobj_expr_path.GetData(),idx); 1490 StreamString value_fetcher_expr; 1491 value_fetcher_expr.Printf("(id)[%s objectForKey:%s]",valobj_expr_path.GetData(),key_fetcher_expr.GetData()); 1492 StreamString object_fetcher_expr; 1493 object_fetcher_expr.Printf("struct __lldb_autogen_nspair { id key; id value; } _lldb_valgen_item; _lldb_valgen_item.key = %s; _lldb_valgen_item.value = %s; _lldb_valgen_item;",key_fetcher_expr.GetData(),value_fetcher_expr.GetData()); 1494 lldb::ValueObjectSP child_sp; 1495 m_backend.GetTargetSP()->EvaluateExpression(object_fetcher_expr.GetData(), m_backend.GetFrameSP().get(), child_sp, 1496 EvaluateExpressionOptions().SetKeepInMemory(true)); 1497 if (child_sp) 1498 child_sp->SetName(ConstString(idx_name.GetData())); 1499 return child_sp; 1500} 1501 1502bool 1503lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::Update() 1504{ 1505 return false; 1506} 1507 1508bool 1509lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::MightHaveChildren () 1510{ 1511 return true; 1512} 1513 1514size_t 1515lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name) 1516{ 1517 return 0; 1518} 1519 1520lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::~NSDictionaryCodeRunningSyntheticFrontEnd () 1521{} 1522 1523lldb_private::formatters::NSDictionaryISyntheticFrontEnd::NSDictionaryISyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) : 1524 SyntheticChildrenFrontEnd(*valobj_sp.get()), 1525 m_exe_ctx_ref(), 1526 m_ptr_size(8), 1527 m_data_32(NULL), 1528 m_data_64(NULL) 1529{ 1530 if (valobj_sp) 1531 Update(); 1532} 1533 1534lldb_private::formatters::NSDictionaryISyntheticFrontEnd::~NSDictionaryISyntheticFrontEnd () 1535{ 1536 delete m_data_32; 1537 m_data_32 = NULL; 1538 delete m_data_64; 1539 m_data_64 = NULL; 1540} 1541 1542size_t 1543lldb_private::formatters::NSDictionaryISyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name) 1544{ 1545 const char* item_name = name.GetCString(); 1546 uint32_t idx = ExtractIndexFromString(item_name); 1547 if (idx < UINT32_MAX && idx >= CalculateNumChildren()) 1548 return UINT32_MAX; 1549 return idx; 1550} 1551 1552size_t 1553lldb_private::formatters::NSDictionaryISyntheticFrontEnd::CalculateNumChildren () 1554{ 1555 if (!m_data_32 && !m_data_64) 1556 return 0; 1557 return (m_data_32 ? m_data_32->_used : m_data_64->_used); 1558} 1559 1560bool 1561lldb_private::formatters::NSDictionaryISyntheticFrontEnd::Update() 1562{ 1563 m_children.clear(); 1564 delete m_data_32; 1565 m_data_32 = NULL; 1566 delete m_data_64; 1567 m_data_64 = NULL; 1568 m_ptr_size = 0; 1569 ValueObjectSP valobj_sp = m_backend.GetSP(); 1570 if (!valobj_sp) 1571 return false; 1572 if (valobj_sp->IsDynamic()) 1573 valobj_sp = valobj_sp->GetStaticValue(); 1574 if (!valobj_sp) 1575 return false; 1576 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 1577 Error error; 1578 if (valobj_sp->IsPointerType()) 1579 { 1580 valobj_sp = valobj_sp->Dereference(error); 1581 if (error.Fail() || !valobj_sp) 1582 return false; 1583 } 1584 error.Clear(); 1585 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 1586 if (!process_sp) 1587 return false; 1588 m_ptr_size = process_sp->GetAddressByteSize(); 1589 uint64_t data_location = valobj_sp->GetAddressOf() + m_ptr_size; 1590 if (m_ptr_size == 4) 1591 { 1592 m_data_32 = new DataDescriptor_32(); 1593 process_sp->ReadMemory (data_location, m_data_32, sizeof(DataDescriptor_32), error); 1594 } 1595 else 1596 { 1597 m_data_64 = new DataDescriptor_64(); 1598 process_sp->ReadMemory (data_location, m_data_64, sizeof(DataDescriptor_64), error); 1599 } 1600 if (error.Fail()) 1601 return false; 1602 m_data_ptr = data_location + m_ptr_size; 1603 return false; 1604} 1605 1606bool 1607lldb_private::formatters::NSDictionaryISyntheticFrontEnd::MightHaveChildren () 1608{ 1609 return true; 1610} 1611 1612lldb::ValueObjectSP 1613lldb_private::formatters::NSDictionaryISyntheticFrontEnd::GetChildAtIndex (size_t idx) 1614{ 1615 uint32_t num_children = CalculateNumChildren(); 1616 1617 if (idx >= num_children) 1618 return lldb::ValueObjectSP(); 1619 1620 if (m_children.empty()) 1621 { 1622 // do the scan phase 1623 lldb::addr_t key_at_idx = 0, val_at_idx = 0; 1624 1625 uint32_t tries = 0; 1626 uint32_t test_idx = 0; 1627 1628 while(tries < num_children) 1629 { 1630 key_at_idx = m_data_ptr + (2*test_idx * m_ptr_size); 1631 val_at_idx = key_at_idx + m_ptr_size; 1632 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP(); 1633 if (!process_sp) 1634 return lldb::ValueObjectSP(); 1635 Error error; 1636 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error); 1637 if (error.Fail()) 1638 return lldb::ValueObjectSP(); 1639 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error); 1640 if (error.Fail()) 1641 return lldb::ValueObjectSP(); 1642 1643 test_idx++; 1644 1645 if (!key_at_idx || !val_at_idx) 1646 continue; 1647 tries++; 1648 1649 DictionaryItemDescriptor descriptor = {key_at_idx,val_at_idx,lldb::ValueObjectSP()}; 1650 1651 m_children.push_back(descriptor); 1652 } 1653 } 1654 1655 if (idx >= m_children.size()) // should never happen 1656 return lldb::ValueObjectSP(); 1657 1658 DictionaryItemDescriptor &dict_item = m_children[idx]; 1659 if (!dict_item.valobj_sp) 1660 { 1661 // make the new ValueObject 1662 StreamString expr; 1663 expr.Printf("struct __lldb_autogen_nspair { id key; id value; } _lldb_valgen_item; _lldb_valgen_item.key = (id)%" PRIu64 " ; _lldb_valgen_item.value = (id)%" PRIu64 "; _lldb_valgen_item;",dict_item.key_ptr,dict_item.val_ptr); 1664 StreamString idx_name; 1665 idx_name.Printf("[%zu]",idx); 1666 dict_item.valobj_sp = ValueObject::CreateValueObjectFromExpression(idx_name.GetData(), expr.GetData(), m_exe_ctx_ref); 1667 } 1668 return dict_item.valobj_sp; 1669} 1670 1671lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::NSDictionaryMSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) : 1672 SyntheticChildrenFrontEnd(*valobj_sp.get()), 1673 m_exe_ctx_ref(), 1674 m_ptr_size(8), 1675 m_data_32(NULL), 1676 m_data_64(NULL) 1677{ 1678 if (valobj_sp) 1679 Update (); 1680} 1681 1682lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::~NSDictionaryMSyntheticFrontEnd () 1683{ 1684 delete m_data_32; 1685 m_data_32 = NULL; 1686 delete m_data_64; 1687 m_data_64 = NULL; 1688} 1689 1690size_t 1691lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name) 1692{ 1693 const char* item_name = name.GetCString(); 1694 uint32_t idx = ExtractIndexFromString(item_name); 1695 if (idx < UINT32_MAX && idx >= CalculateNumChildren()) 1696 return UINT32_MAX; 1697 return idx; 1698} 1699 1700size_t 1701lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::CalculateNumChildren () 1702{ 1703 if (!m_data_32 && !m_data_64) 1704 return 0; 1705 return (m_data_32 ? m_data_32->_used : m_data_64->_used); 1706} 1707 1708bool 1709lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::Update() 1710{ 1711 m_children.clear(); 1712 ValueObjectSP valobj_sp = m_backend.GetSP(); 1713 m_ptr_size = 0; 1714 delete m_data_32; 1715 m_data_32 = NULL; 1716 delete m_data_64; 1717 m_data_64 = NULL; 1718 if (!valobj_sp) 1719 return false; 1720 if (valobj_sp->IsDynamic()) 1721 valobj_sp = valobj_sp->GetStaticValue(); 1722 if (!valobj_sp) 1723 return false; 1724 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 1725 Error error; 1726 if (valobj_sp->IsPointerType()) 1727 { 1728 valobj_sp = valobj_sp->Dereference(error); 1729 if (error.Fail() || !valobj_sp) 1730 return false; 1731 } 1732 error.Clear(); 1733 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 1734 if (!process_sp) 1735 return false; 1736 m_ptr_size = process_sp->GetAddressByteSize(); 1737 uint64_t data_location = valobj_sp->GetAddressOf() + m_ptr_size; 1738 if (m_ptr_size == 4) 1739 { 1740 m_data_32 = new DataDescriptor_32(); 1741 process_sp->ReadMemory (data_location, m_data_32, sizeof(DataDescriptor_32), error); 1742 } 1743 else 1744 { 1745 m_data_64 = new DataDescriptor_64(); 1746 process_sp->ReadMemory (data_location, m_data_64, sizeof(DataDescriptor_64), error); 1747 } 1748 if (error.Fail()) 1749 return false; 1750 return false; 1751} 1752 1753bool 1754lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::MightHaveChildren () 1755{ 1756 return true; 1757} 1758 1759lldb::ValueObjectSP 1760lldb_private::formatters::NSDictionaryMSyntheticFrontEnd::GetChildAtIndex (size_t idx) 1761{ 1762 lldb::addr_t m_keys_ptr = (m_data_32 ? m_data_32->_keys_addr : m_data_64->_keys_addr); 1763 lldb::addr_t m_values_ptr = (m_data_32 ? m_data_32->_objs_addr : m_data_64->_objs_addr); 1764 1765 uint32_t num_children = CalculateNumChildren(); 1766 1767 if (idx >= num_children) 1768 return lldb::ValueObjectSP(); 1769 1770 if (m_children.empty()) 1771 { 1772 // do the scan phase 1773 lldb::addr_t key_at_idx = 0, val_at_idx = 0; 1774 1775 uint32_t tries = 0; 1776 uint32_t test_idx = 0; 1777 1778 while(tries < num_children) 1779 { 1780 key_at_idx = m_keys_ptr + (test_idx * m_ptr_size); 1781 val_at_idx = m_values_ptr + (test_idx * m_ptr_size);; 1782 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP(); 1783 if (!process_sp) 1784 return lldb::ValueObjectSP(); 1785 Error error; 1786 key_at_idx = process_sp->ReadPointerFromMemory(key_at_idx, error); 1787 if (error.Fail()) 1788 return lldb::ValueObjectSP(); 1789 val_at_idx = process_sp->ReadPointerFromMemory(val_at_idx, error); 1790 if (error.Fail()) 1791 return lldb::ValueObjectSP(); 1792 1793 test_idx++; 1794 1795 if (!key_at_idx || !val_at_idx) 1796 continue; 1797 tries++; 1798 1799 DictionaryItemDescriptor descriptor = {key_at_idx,val_at_idx,lldb::ValueObjectSP()}; 1800 1801 m_children.push_back(descriptor); 1802 } 1803 } 1804 1805 if (idx >= m_children.size()) // should never happen 1806 return lldb::ValueObjectSP(); 1807 1808 DictionaryItemDescriptor &dict_item = m_children[idx]; 1809 if (!dict_item.valobj_sp) 1810 { 1811 // make the new ValueObject 1812 StreamString expr; 1813 expr.Printf("struct __lldb_autogen_nspair { id key; id value; } _lldb_valgen_item; _lldb_valgen_item.key = (id)%" PRIu64 " ; _lldb_valgen_item.value = (id)%" PRIu64 "; _lldb_valgen_item;",dict_item.key_ptr,dict_item.val_ptr); 1814 StreamString idx_name; 1815 idx_name.Printf("[%zu]",idx); 1816 dict_item.valobj_sp = ValueObject::CreateValueObjectFromExpression(idx_name.GetData(), expr.GetData(), m_exe_ctx_ref); 1817 } 1818 return dict_item.valobj_sp; 1819} 1820 1821lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::LibcxxVectorBoolSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) : 1822 SyntheticChildrenFrontEnd(*valobj_sp.get()), 1823 m_exe_ctx_ref(), 1824 m_count(0), 1825 m_base_data_address(0), 1826 m_options() 1827 { 1828 if (valobj_sp) 1829 Update(); 1830 m_options.SetCoerceToId(false) 1831 .SetUnwindOnError(true) 1832 .SetKeepInMemory(true) 1833 .SetUseDynamic(lldb::eDynamicCanRunTarget); 1834 } 1835 1836size_t 1837lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::CalculateNumChildren () 1838{ 1839 return m_count; 1840} 1841 1842lldb::ValueObjectSP 1843lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::GetChildAtIndex (size_t idx) 1844{ 1845 if (idx >= m_count) 1846 return ValueObjectSP(); 1847 if (m_base_data_address == 0 || m_count == 0) 1848 return ValueObjectSP(); 1849 size_t byte_idx = (idx >> 3); // divide by 8 to get byte index 1850 size_t bit_index = (idx & 7); // efficient idx % 8 for bit index 1851 lldb::addr_t byte_location = m_base_data_address + byte_idx; 1852 ProcessSP process_sp(m_exe_ctx_ref.GetProcessSP()); 1853 if (!process_sp) 1854 return ValueObjectSP(); 1855 uint8_t byte = 0; 1856 uint8_t mask = 0; 1857 Error err; 1858 size_t bytes_read = process_sp->ReadMemory(byte_location, &byte, 1, err); 1859 if (err.Fail() || bytes_read == 0) 1860 return ValueObjectSP(); 1861 switch (bit_index) 1862 { 1863 case 0: 1864 mask = 1; break; 1865 case 1: 1866 mask = 2; break; 1867 case 2: 1868 mask = 4; break; 1869 case 3: 1870 mask = 8; break; 1871 case 4: 1872 mask = 16; break; 1873 case 5: 1874 mask = 32; break; 1875 case 6: 1876 mask = 64; break; 1877 case 7: 1878 mask = 128; break; 1879 default: 1880 return ValueObjectSP(); 1881 } 1882 bool bit_set = ((byte & mask) != 0); 1883 Target& target(process_sp->GetTarget()); 1884 ValueObjectSP retval_sp; 1885 if (bit_set) 1886 target.EvaluateExpression("(bool)true", NULL, retval_sp); 1887 else 1888 target.EvaluateExpression("(bool)false", NULL, retval_sp); 1889 StreamString name; name.Printf("[%zu]",idx); 1890 if (retval_sp) 1891 retval_sp->SetName(ConstString(name.GetData())); 1892 return retval_sp; 1893} 1894 1895/*(std::__1::vector<std::__1::allocator<bool> >) vBool = { 1896 __begin_ = 0x00000001001000e0 1897 __size_ = 56 1898 __cap_alloc_ = { 1899 std::__1::__libcpp_compressed_pair_imp<unsigned long, std::__1::allocator<unsigned long> > = { 1900 __first_ = 1 1901 } 1902 } 1903}*/ 1904 1905bool 1906lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::Update() 1907{ 1908 ValueObjectSP valobj_sp = m_backend.GetSP(); 1909 if (!valobj_sp) 1910 return false; 1911 if (valobj_sp->IsDynamic()) 1912 valobj_sp = valobj_sp->GetStaticValue(); 1913 if (!valobj_sp) 1914 return false; 1915 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 1916 ValueObjectSP size_sp(valobj_sp->GetChildMemberWithName(ConstString("__size_"), true)); 1917 if (!size_sp) 1918 return false; 1919 m_count = size_sp->GetValueAsUnsigned(0); 1920 if (!m_count) 1921 return true; 1922 ValueObjectSP begin_sp(valobj_sp->GetChildMemberWithName(ConstString("__begin_"), true)); 1923 if (!begin_sp) 1924 { 1925 m_count = 0; 1926 return false; 1927 } 1928 m_base_data_address = begin_sp->GetValueAsUnsigned(0); 1929 if (!m_base_data_address) 1930 { 1931 m_count = 0; 1932 return false; 1933 } 1934 return true; 1935} 1936 1937bool 1938lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::MightHaveChildren () 1939{ 1940 return true; 1941} 1942 1943size_t 1944lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name) 1945{ 1946 if (!m_count || !m_base_data_address) 1947 return UINT32_MAX; 1948 const char* item_name = name.GetCString(); 1949 uint32_t idx = ExtractIndexFromString(item_name); 1950 if (idx < UINT32_MAX && idx >= CalculateNumChildren()) 1951 return UINT32_MAX; 1952 return idx; 1953} 1954 1955lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::~LibcxxVectorBoolSyntheticFrontEnd () 1956{} 1957 1958SyntheticChildrenFrontEnd* 1959lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp) 1960{ 1961 if (!valobj_sp) 1962 return NULL; 1963 return (new LibcxxVectorBoolSyntheticFrontEnd(valobj_sp)); 1964} 1965 1966lldb_private::formatters::LibstdcppVectorBoolSyntheticFrontEnd::LibstdcppVectorBoolSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) : 1967SyntheticChildrenFrontEnd(*valobj_sp.get()), 1968m_exe_ctx_ref(), 1969m_count(0), 1970m_base_data_address(0), 1971m_options() 1972{ 1973 if (valobj_sp) 1974 Update(); 1975 m_options.SetCoerceToId(false) 1976 .SetUnwindOnError(true) 1977 .SetKeepInMemory(true) 1978 .SetUseDynamic(lldb::eDynamicCanRunTarget); 1979} 1980 1981size_t 1982lldb_private::formatters::LibstdcppVectorBoolSyntheticFrontEnd::CalculateNumChildren () 1983{ 1984 return m_count; 1985} 1986 1987lldb::ValueObjectSP 1988lldb_private::formatters::LibstdcppVectorBoolSyntheticFrontEnd::GetChildAtIndex (size_t idx) 1989{ 1990 if (idx >= m_count) 1991 return ValueObjectSP(); 1992 if (m_base_data_address == 0 || m_count == 0) 1993 return ValueObjectSP(); 1994 size_t byte_idx = (idx >> 3); // divide by 8 to get byte index 1995 size_t bit_index = (idx & 7); // efficient idx % 8 for bit index 1996 lldb::addr_t byte_location = m_base_data_address + byte_idx; 1997 ProcessSP process_sp(m_exe_ctx_ref.GetProcessSP()); 1998 if (!process_sp) 1999 return ValueObjectSP(); 2000 uint8_t byte = 0; 2001 uint8_t mask = 0; 2002 Error err; 2003 size_t bytes_read = process_sp->ReadMemory(byte_location, &byte, 1, err); 2004 if (err.Fail() || bytes_read == 0) 2005 return ValueObjectSP(); 2006 switch (bit_index) 2007 { 2008 case 0: 2009 mask = 1; break; 2010 case 1: 2011 mask = 2; break; 2012 case 2: 2013 mask = 4; break; 2014 case 3: 2015 mask = 8; break; 2016 case 4: 2017 mask = 16; break; 2018 case 5: 2019 mask = 32; break; 2020 case 6: 2021 mask = 64; break; 2022 case 7: 2023 mask = 128; break; 2024 default: 2025 return ValueObjectSP(); 2026 } 2027 bool bit_set = ((byte & mask) != 0); 2028 Target& target(process_sp->GetTarget()); 2029 ValueObjectSP retval_sp; 2030 if (bit_set) 2031 target.EvaluateExpression("(bool)true", NULL, retval_sp); 2032 else 2033 target.EvaluateExpression("(bool)false", NULL, retval_sp); 2034 StreamString name; name.Printf("[%zu]",idx); 2035 if (retval_sp) 2036 retval_sp->SetName(ConstString(name.GetData())); 2037 return retval_sp; 2038} 2039 2040/*((std::vector<std::allocator<bool> >) vBool = { 2041 (std::_Bvector_base<std::allocator<bool> >) std::_Bvector_base<std::allocator<bool> > = { 2042 (std::_Bvector_base<std::allocator<bool> >::_Bvector_impl) _M_impl = { 2043 (std::_Bit_iterator) _M_start = { 2044 (std::_Bit_iterator_base) std::_Bit_iterator_base = { 2045 (_Bit_type *) _M_p = 0x0016b160 2046 (unsigned int) _M_offset = 0 2047 } 2048 } 2049 (std::_Bit_iterator) _M_finish = { 2050 (std::_Bit_iterator_base) std::_Bit_iterator_base = { 2051 (_Bit_type *) _M_p = 0x0016b16c 2052 (unsigned int) _M_offset = 16 2053 } 2054 } 2055 (_Bit_type *) _M_end_of_storage = 0x0016b170 2056 } 2057 } 2058 } 2059*/ 2060 2061bool 2062lldb_private::formatters::LibstdcppVectorBoolSyntheticFrontEnd::Update() 2063{ 2064 ValueObjectSP valobj_sp = m_backend.GetSP(); 2065 if (!valobj_sp) 2066 return false; 2067 if (valobj_sp->IsDynamic()) 2068 valobj_sp = valobj_sp->GetStaticValue(); 2069 if (!valobj_sp) 2070 return false; 2071 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 2072 2073 ValueObjectSP m_impl_sp(valobj_sp->GetChildMemberWithName(ConstString("_M_impl"), true)); 2074 if (!m_impl_sp) 2075 return false; 2076 2077 ValueObjectSP m_start_sp(m_impl_sp->GetChildMemberWithName(ConstString("_M_start"), true)); 2078 ValueObjectSP m_finish_sp(m_impl_sp->GetChildMemberWithName(ConstString("_M_finish"), true)); 2079 2080 ValueObjectSP start_p_sp, finish_p_sp, finish_offset_sp; 2081 2082 if (!m_start_sp || !m_finish_sp) 2083 return false; 2084 2085 start_p_sp = m_start_sp->GetChildMemberWithName(ConstString("_M_p"), true); 2086 finish_p_sp = m_finish_sp->GetChildMemberWithName(ConstString("_M_p"), true); 2087 finish_offset_sp = m_finish_sp->GetChildMemberWithName(ConstString("_M_offset"), true); 2088 2089 if (!start_p_sp || !finish_offset_sp || !finish_p_sp) 2090 return false; 2091 2092 m_base_data_address = start_p_sp->GetValueAsUnsigned(0); 2093 if (!m_base_data_address) 2094 return false; 2095 2096 lldb::addr_t end_data_address(finish_p_sp->GetValueAsUnsigned(0)); 2097 if (!end_data_address) 2098 return false; 2099 2100 if (end_data_address < m_base_data_address) 2101 return false; 2102 else 2103 m_count = finish_offset_sp->GetValueAsUnsigned(0) + (end_data_address-m_base_data_address)*8; 2104 2105 return true; 2106} 2107 2108bool 2109lldb_private::formatters::LibstdcppVectorBoolSyntheticFrontEnd::MightHaveChildren () 2110{ 2111 return true; 2112} 2113 2114size_t 2115lldb_private::formatters::LibstdcppVectorBoolSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name) 2116{ 2117 if (!m_count || !m_base_data_address) 2118 return UINT32_MAX; 2119 const char* item_name = name.GetCString(); 2120 uint32_t idx = ExtractIndexFromString(item_name); 2121 if (idx < UINT32_MAX && idx >= CalculateNumChildren()) 2122 return UINT32_MAX; 2123 return idx; 2124} 2125 2126lldb_private::formatters::LibstdcppVectorBoolSyntheticFrontEnd::~LibstdcppVectorBoolSyntheticFrontEnd () 2127{} 2128 2129SyntheticChildrenFrontEnd* 2130lldb_private::formatters::LibstdcppVectorBoolSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp) 2131{ 2132 if (!valobj_sp) 2133 return NULL; 2134 return (new LibstdcppVectorBoolSyntheticFrontEnd(valobj_sp)); 2135} 2136 2137template bool 2138lldb_private::formatters::NSDictionarySummaryProvider<true> (ValueObject&, Stream&) ; 2139 2140template bool 2141lldb_private::formatters::NSDictionarySummaryProvider<false> (ValueObject&, Stream&) ; 2142 2143template bool 2144lldb_private::formatters::NSDataSummaryProvider<true> (ValueObject&, Stream&) ; 2145 2146template bool 2147lldb_private::formatters::NSDataSummaryProvider<false> (ValueObject&, Stream&) ; 2148 2149template bool 2150lldb_private::formatters::ObjCSELSummaryProvider<true> (ValueObject&, Stream&) ; 2151 2152template bool 2153lldb_private::formatters::ObjCSELSummaryProvider<false> (ValueObject&, Stream&) ; 2154