1//===-- NSSet.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 "lldb/Core/DataBufferHeap.h" 15#include "lldb/Core/Error.h" 16#include "lldb/Core/Stream.h" 17#include "lldb/Core/ValueObject.h" 18#include "lldb/Core/ValueObjectConstResult.h" 19#include "lldb/Host/Endian.h" 20#include "lldb/Symbol/ClangASTContext.h" 21#include "lldb/Target/ObjCLanguageRuntime.h" 22#include "lldb/Target/Target.h" 23 24using namespace lldb; 25using namespace lldb_private; 26using namespace lldb_private::formatters; 27 28template<bool cf_style> 29bool 30lldb_private::formatters::NSSetSummaryProvider (ValueObject& valobj, Stream& stream) 31{ 32 ProcessSP process_sp = valobj.GetProcessSP(); 33 if (!process_sp) 34 return false; 35 36 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 37 38 if (!runtime) 39 return false; 40 41 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj)); 42 43 if (!descriptor.get() || !descriptor->IsValid()) 44 return false; 45 46 uint32_t ptr_size = process_sp->GetAddressByteSize(); 47 bool is_64bit = (ptr_size == 8); 48 49 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 50 51 if (!valobj_addr) 52 return false; 53 54 uint64_t value = 0; 55 56 const char* class_name = descriptor->GetClassName().GetCString(); 57 58 if (!class_name || !*class_name) 59 return false; 60 61 if (!strcmp(class_name,"__NSSetI")) 62 { 63 Error error; 64 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error); 65 if (error.Fail()) 66 return false; 67 value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U); 68 } 69 else if (!strcmp(class_name,"__NSSetM")) 70 { 71 Error error; 72 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error); 73 if (error.Fail()) 74 return false; 75 value &= (is_64bit ? ~0xFC00000000000000UL : ~0xFC000000U); 76 } 77 /*else if (!strcmp(class_name,"__NSCFSet")) 78 { 79 Error error; 80 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + (is_64bit ? 20 : 12), 4, 0, error); 81 if (error.Fail()) 82 return false; 83 if (is_64bit) 84 value &= ~0x1fff000000000000UL; 85 } 86 else if (!strcmp(class_name,"NSCountedSet")) 87 { 88 Error error; 89 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error); 90 if (error.Fail()) 91 return false; 92 value = process_sp->ReadUnsignedIntegerFromMemory(value + (is_64bit ? 20 : 12), 4, 0, error); 93 if (error.Fail()) 94 return false; 95 if (is_64bit) 96 value &= ~0x1fff000000000000UL; 97 }*/ 98 else 99 { 100 if (!ExtractValueFromObjCExpression(valobj, "int", "count", value)) 101 return false; 102 } 103 104 stream.Printf("%s%" PRIu64 " %s%s", 105 (cf_style ? "@\"" : ""), 106 value, 107 (cf_style ? (value == 1 ? "value" : "values") : (value == 1 ? "object" : "objects")), 108 (cf_style ? "\"" : "")); 109 return true; 110} 111 112SyntheticChildrenFrontEnd* lldb_private::formatters::NSSetSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp) 113{ 114 lldb::ProcessSP process_sp (valobj_sp->GetProcessSP()); 115 if (!process_sp) 116 return NULL; 117 ObjCLanguageRuntime *runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 118 if (!runtime) 119 return NULL; 120 121 if (!valobj_sp->IsPointerType()) 122 { 123 Error error; 124 valobj_sp = valobj_sp->AddressOf(error); 125 if (error.Fail() || !valobj_sp) 126 return NULL; 127 } 128 129 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(*valobj_sp.get())); 130 131 if (!descriptor.get() || !descriptor->IsValid()) 132 return NULL; 133 134 const char* class_name = descriptor->GetClassName().GetCString(); 135 136 if (!class_name || !*class_name) 137 return NULL; 138 139 if (!strcmp(class_name,"__NSSetI")) 140 { 141 return (new NSSetISyntheticFrontEnd(valobj_sp)); 142 } 143 else if (!strcmp(class_name,"__NSSetM")) 144 { 145 return (new NSSetMSyntheticFrontEnd(valobj_sp)); 146 } 147 else if ((!strcmp(class_name,"__NSOrderedSetI")) || (!strcmp(class_name,"__NSOrderedSetM"))) 148 { 149 return new NSOrderedSetSyntheticFrontEnd(valobj_sp); // this runs code 150 } 151 else 152 { 153 return /*(new NSSetCodeRunningSyntheticFrontEnd(valobj_sp))*/ NULL; 154 } 155} 156 157lldb_private::formatters::NSSetISyntheticFrontEnd::NSSetISyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) : 158SyntheticChildrenFrontEnd(*valobj_sp.get()), 159m_exe_ctx_ref(), 160m_ptr_size(8), 161m_data_32(NULL), 162m_data_64(NULL) 163{ 164 if (valobj_sp) 165 Update(); 166} 167 168lldb_private::formatters::NSSetISyntheticFrontEnd::~NSSetISyntheticFrontEnd () 169{ 170 delete m_data_32; 171 m_data_32 = NULL; 172 delete m_data_64; 173 m_data_64 = NULL; 174} 175 176size_t 177lldb_private::formatters::NSSetISyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name) 178{ 179 const char* item_name = name.GetCString(); 180 uint32_t idx = ExtractIndexFromString(item_name); 181 if (idx < UINT32_MAX && idx >= CalculateNumChildren()) 182 return UINT32_MAX; 183 return idx; 184} 185 186size_t 187lldb_private::formatters::NSSetISyntheticFrontEnd::CalculateNumChildren () 188{ 189 if (!m_data_32 && !m_data_64) 190 return 0; 191 return (m_data_32 ? m_data_32->_used : m_data_64->_used); 192} 193 194bool 195lldb_private::formatters::NSSetISyntheticFrontEnd::Update() 196{ 197 m_children.clear(); 198 delete m_data_32; 199 m_data_32 = NULL; 200 delete m_data_64; 201 m_data_64 = NULL; 202 m_ptr_size = 0; 203 ValueObjectSP valobj_sp = m_backend.GetSP(); 204 if (!valobj_sp) 205 return false; 206 if (!valobj_sp) 207 return false; 208 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 209 Error error; 210 if (valobj_sp->IsPointerType()) 211 { 212 valobj_sp = valobj_sp->Dereference(error); 213 if (error.Fail() || !valobj_sp) 214 return false; 215 } 216 error.Clear(); 217 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 218 if (!process_sp) 219 return false; 220 m_ptr_size = process_sp->GetAddressByteSize(); 221 uint64_t data_location = valobj_sp->GetAddressOf() + m_ptr_size; 222 if (m_ptr_size == 4) 223 { 224 m_data_32 = new DataDescriptor_32(); 225 process_sp->ReadMemory (data_location, m_data_32, sizeof(DataDescriptor_32), error); 226 } 227 else 228 { 229 m_data_64 = new DataDescriptor_64(); 230 process_sp->ReadMemory (data_location, m_data_64, sizeof(DataDescriptor_64), error); 231 } 232 if (error.Fail()) 233 return false; 234 m_data_ptr = data_location + m_ptr_size; 235 return false; 236} 237 238bool 239lldb_private::formatters::NSSetISyntheticFrontEnd::MightHaveChildren () 240{ 241 return true; 242} 243 244lldb::ValueObjectSP 245lldb_private::formatters::NSSetISyntheticFrontEnd::GetChildAtIndex (size_t idx) 246{ 247 uint32_t num_children = CalculateNumChildren(); 248 249 if (idx >= num_children) 250 return lldb::ValueObjectSP(); 251 252 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP(); 253 if (!process_sp) 254 return lldb::ValueObjectSP(); 255 256 if (m_children.empty()) 257 { 258 // do the scan phase 259 lldb::addr_t obj_at_idx = 0; 260 261 uint32_t tries = 0; 262 uint32_t test_idx = 0; 263 264 while(tries < num_children) 265 { 266 obj_at_idx = m_data_ptr + (test_idx * m_ptr_size); 267 if (!process_sp) 268 return lldb::ValueObjectSP(); 269 Error error; 270 obj_at_idx = process_sp->ReadPointerFromMemory(obj_at_idx, error); 271 if (error.Fail()) 272 return lldb::ValueObjectSP(); 273 274 test_idx++; 275 276 if (!obj_at_idx) 277 continue; 278 tries++; 279 280 SetItemDescriptor descriptor = {obj_at_idx,lldb::ValueObjectSP()}; 281 282 m_children.push_back(descriptor); 283 } 284 } 285 286 if (idx >= m_children.size()) // should never happen 287 return lldb::ValueObjectSP(); 288 289 SetItemDescriptor &set_item = m_children[idx]; 290 if (!set_item.valobj_sp) 291 { 292 auto ptr_size = process_sp->GetAddressByteSize(); 293 DataBufferHeap buffer(ptr_size,0); 294 switch (ptr_size) 295 { 296 case 0: // architecture has no clue?? - fail 297 return lldb::ValueObjectSP(); 298 case 4: 299 *((uint32_t*)buffer.GetBytes()) = (uint32_t)set_item.item_ptr; 300 break; 301 case 8: 302 *((uint64_t*)buffer.GetBytes()) = (uint64_t)set_item.item_ptr; 303 break; 304 default: 305 assert(false && "pointer size is not 4 nor 8 - get out of here ASAP"); 306 } 307 StreamString idx_name; 308 idx_name.Printf("[%zu]",idx); 309 310 DataExtractor data(buffer.GetBytes(), 311 buffer.GetByteSize(), 312 process_sp->GetByteOrder(), 313 process_sp->GetAddressByteSize()); 314 315 set_item.valobj_sp = 316 ValueObject::CreateValueObjectFromData(idx_name.GetData(), 317 data, 318 m_exe_ctx_ref, 319 m_backend.GetClangType().GetBasicTypeFromAST(lldb::eBasicTypeObjCID)); 320 } 321 return set_item.valobj_sp; 322} 323 324lldb_private::formatters::NSSetMSyntheticFrontEnd::NSSetMSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) : 325SyntheticChildrenFrontEnd(*valobj_sp.get()), 326m_exe_ctx_ref(), 327m_ptr_size(8), 328m_data_32(NULL), 329m_data_64(NULL) 330{ 331 if (valobj_sp) 332 Update (); 333} 334 335lldb_private::formatters::NSSetMSyntheticFrontEnd::~NSSetMSyntheticFrontEnd () 336{ 337 delete m_data_32; 338 m_data_32 = NULL; 339 delete m_data_64; 340 m_data_64 = NULL; 341} 342 343size_t 344lldb_private::formatters::NSSetMSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name) 345{ 346 const char* item_name = name.GetCString(); 347 uint32_t idx = ExtractIndexFromString(item_name); 348 if (idx < UINT32_MAX && idx >= CalculateNumChildren()) 349 return UINT32_MAX; 350 return idx; 351} 352 353size_t 354lldb_private::formatters::NSSetMSyntheticFrontEnd::CalculateNumChildren () 355{ 356 if (!m_data_32 && !m_data_64) 357 return 0; 358 return (m_data_32 ? m_data_32->_used : m_data_64->_used); 359} 360 361bool 362lldb_private::formatters::NSSetMSyntheticFrontEnd::Update() 363{ 364 m_children.clear(); 365 ValueObjectSP valobj_sp = m_backend.GetSP(); 366 m_ptr_size = 0; 367 delete m_data_32; 368 m_data_32 = NULL; 369 delete m_data_64; 370 m_data_64 = NULL; 371 if (!valobj_sp) 372 return false; 373 if (!valobj_sp) 374 return false; 375 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 376 Error error; 377 if (valobj_sp->IsPointerType()) 378 { 379 valobj_sp = valobj_sp->Dereference(error); 380 if (error.Fail() || !valobj_sp) 381 return false; 382 } 383 error.Clear(); 384 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 385 if (!process_sp) 386 return false; 387 m_ptr_size = process_sp->GetAddressByteSize(); 388 uint64_t data_location = valobj_sp->GetAddressOf() + m_ptr_size; 389 if (m_ptr_size == 4) 390 { 391 m_data_32 = new DataDescriptor_32(); 392 process_sp->ReadMemory (data_location, m_data_32, sizeof(DataDescriptor_32), error); 393 } 394 else 395 { 396 m_data_64 = new DataDescriptor_64(); 397 process_sp->ReadMemory (data_location, m_data_64, sizeof(DataDescriptor_64), error); 398 } 399 if (error.Fail()) 400 return false; 401 return false; 402} 403 404bool 405lldb_private::formatters::NSSetMSyntheticFrontEnd::MightHaveChildren () 406{ 407 return true; 408} 409 410lldb::ValueObjectSP 411lldb_private::formatters::NSSetMSyntheticFrontEnd::GetChildAtIndex (size_t idx) 412{ 413 lldb::addr_t m_objs_addr = (m_data_32 ? m_data_32->_objs_addr : m_data_64->_objs_addr); 414 415 uint32_t num_children = CalculateNumChildren(); 416 417 if (idx >= num_children) 418 return lldb::ValueObjectSP(); 419 420 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP(); 421 if (!process_sp) 422 return lldb::ValueObjectSP(); 423 424 if (m_children.empty()) 425 { 426 // do the scan phase 427 lldb::addr_t obj_at_idx = 0; 428 429 uint32_t tries = 0; 430 uint32_t test_idx = 0; 431 432 while(tries < num_children) 433 { 434 obj_at_idx = m_objs_addr + (test_idx * m_ptr_size); 435 if (!process_sp) 436 return lldb::ValueObjectSP(); 437 Error error; 438 obj_at_idx = process_sp->ReadPointerFromMemory(obj_at_idx, error); 439 if (error.Fail()) 440 return lldb::ValueObjectSP(); 441 442 test_idx++; 443 444 if (!obj_at_idx) 445 continue; 446 tries++; 447 448 SetItemDescriptor descriptor = {obj_at_idx,lldb::ValueObjectSP()}; 449 450 m_children.push_back(descriptor); 451 } 452 } 453 454 if (idx >= m_children.size()) // should never happen 455 return lldb::ValueObjectSP(); 456 457 SetItemDescriptor &set_item = m_children[idx]; 458 if (!set_item.valobj_sp) 459 { 460 auto ptr_size = process_sp->GetAddressByteSize(); 461 DataBufferHeap buffer(ptr_size,0); 462 switch (ptr_size) 463 { 464 case 0: // architecture has no clue?? - fail 465 return lldb::ValueObjectSP(); 466 case 4: 467 *((uint32_t*)buffer.GetBytes()) = (uint32_t)set_item.item_ptr; 468 break; 469 case 8: 470 *((uint64_t*)buffer.GetBytes()) = (uint64_t)set_item.item_ptr; 471 break; 472 default: 473 assert(false && "pointer size is not 4 nor 8 - get out of here ASAP"); 474 } 475 StreamString idx_name; 476 idx_name.Printf("[%zu]",idx); 477 478 DataExtractor data(buffer.GetBytes(), 479 buffer.GetByteSize(), 480 process_sp->GetByteOrder(), 481 process_sp->GetAddressByteSize()); 482 483 set_item.valobj_sp = 484 ValueObject::CreateValueObjectFromData(idx_name.GetData(), 485 data, 486 m_exe_ctx_ref, 487 m_backend.GetClangType().GetBasicTypeFromAST(lldb::eBasicTypeObjCID)); 488 } 489 return set_item.valobj_sp; 490} 491 492lldb_private::formatters::NSOrderedSetSyntheticFrontEnd::NSOrderedSetSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) : 493SyntheticChildrenFrontEnd(*valobj_sp.get()), 494m_count(UINT32_MAX), 495m_children() 496{} 497 498size_t 499lldb_private::formatters::NSOrderedSetSyntheticFrontEnd::CalculateNumChildren () 500{ 501 if (m_count != UINT32_MAX) 502 return m_count; 503 uint64_t count_temp; 504 if (ExtractValueFromObjCExpression(m_backend,"unsigned int","count",count_temp)) 505 return (m_count = count_temp); 506 return (m_count = 0); 507} 508 509lldb::ValueObjectSP 510lldb_private::formatters::NSOrderedSetSyntheticFrontEnd::GetChildAtIndex (size_t idx) 511{ 512 auto iter = m_children.find(idx); 513 if (iter == m_children.end()) 514 { 515 lldb::ValueObjectSP retval_sp; 516 if (idx <= m_count) 517 { 518 retval_sp = CallSelectorOnObject(m_backend, "id", "objectAtIndex", idx); 519 if (retval_sp) 520 { 521 StreamString idx_name; 522 idx_name.Printf("[%zu]",idx); 523 retval_sp->SetName(ConstString(idx_name.GetData())); 524 } 525 m_children[idx] = retval_sp; 526 } 527 return retval_sp; 528 } 529 else 530 return iter->second; 531} 532 533bool 534lldb_private::formatters::NSOrderedSetSyntheticFrontEnd::Update() 535{ 536 return false; 537} 538 539bool 540lldb_private::formatters::NSOrderedSetSyntheticFrontEnd::MightHaveChildren () 541{ 542 return true; 543} 544 545size_t 546lldb_private::formatters::NSOrderedSetSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name) 547{ 548 const char* item_name = name.GetCString(); 549 uint32_t idx = ExtractIndexFromString(item_name); 550 if (idx < UINT32_MAX && idx >= CalculateNumChildren()) 551 return UINT32_MAX; 552 return idx; 553} 554 555lldb_private::formatters::NSOrderedSetSyntheticFrontEnd::~NSOrderedSetSyntheticFrontEnd () 556{ 557} 558 559template bool 560lldb_private::formatters::NSSetSummaryProvider<true> (ValueObject& valobj, Stream& stream); 561 562template bool 563lldb_private::formatters::NSSetSummaryProvider<false> (ValueObject& valobj, Stream& stream); 564