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 24 using namespace lldb; 25 using namespace lldb_private; 26 using namespace lldb_private::formatters; 27 28 template<bool cf_style> 29 bool 30 lldb_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 112 SyntheticChildrenFrontEnd* 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 157 lldb_private::formatters::NSSetISyntheticFrontEnd::NSSetISyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) : 158 SyntheticChildrenFrontEnd(*valobj_sp.get()), 159 m_exe_ctx_ref(), 160 m_ptr_size(8), 161 m_data_32(NULL), 162 m_data_64(NULL) 163 { 164 if (valobj_sp) 165 Update(); 166 } 167 168 lldb_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 176 size_t 177 lldb_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 186 size_t 187 lldb_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 194 bool 195 lldb_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 238 bool 239 lldb_private::formatters::NSSetISyntheticFrontEnd::MightHaveChildren () 240 { 241 return true; 242 } 243 244 lldb::ValueObjectSP 245 lldb_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 if (m_children.empty()) 253 { 254 // do the scan phase 255 lldb::addr_t obj_at_idx = 0; 256 257 uint32_t tries = 0; 258 uint32_t test_idx = 0; 259 260 while(tries < num_children) 261 { 262 obj_at_idx = m_data_ptr + (test_idx * m_ptr_size); 263 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP(); 264 if (!process_sp) 265 return lldb::ValueObjectSP(); 266 Error error; 267 obj_at_idx = process_sp->ReadPointerFromMemory(obj_at_idx, error); 268 if (error.Fail()) 269 return lldb::ValueObjectSP(); 270 271 test_idx++; 272 273 if (!obj_at_idx) 274 continue; 275 tries++; 276 277 SetItemDescriptor descriptor = {obj_at_idx,lldb::ValueObjectSP()}; 278 279 m_children.push_back(descriptor); 280 } 281 } 282 283 if (idx >= m_children.size()) // should never happen 284 return lldb::ValueObjectSP(); 285 286 SetItemDescriptor &set_item = m_children[idx]; 287 if (!set_item.valobj_sp) 288 { 289 // make the new ValueObject 290 StreamString expr; 291 expr.Printf("(id)%" PRIu64,set_item.item_ptr); 292 StreamString idx_name; 293 idx_name.Printf("[%zu]",idx); 294 set_item.valobj_sp = ValueObject::CreateValueObjectFromExpression(idx_name.GetData(), expr.GetData(), m_exe_ctx_ref); 295 } 296 return set_item.valobj_sp; 297 } 298 299 lldb_private::formatters::NSSetMSyntheticFrontEnd::NSSetMSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) : 300 SyntheticChildrenFrontEnd(*valobj_sp.get()), 301 m_exe_ctx_ref(), 302 m_ptr_size(8), 303 m_data_32(NULL), 304 m_data_64(NULL) 305 { 306 if (valobj_sp) 307 Update (); 308 } 309 310 lldb_private::formatters::NSSetMSyntheticFrontEnd::~NSSetMSyntheticFrontEnd () 311 { 312 delete m_data_32; 313 m_data_32 = NULL; 314 delete m_data_64; 315 m_data_64 = NULL; 316 } 317 318 size_t 319 lldb_private::formatters::NSSetMSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name) 320 { 321 const char* item_name = name.GetCString(); 322 uint32_t idx = ExtractIndexFromString(item_name); 323 if (idx < UINT32_MAX && idx >= CalculateNumChildren()) 324 return UINT32_MAX; 325 return idx; 326 } 327 328 size_t 329 lldb_private::formatters::NSSetMSyntheticFrontEnd::CalculateNumChildren () 330 { 331 if (!m_data_32 && !m_data_64) 332 return 0; 333 return (m_data_32 ? m_data_32->_used : m_data_64->_used); 334 } 335 336 bool 337 lldb_private::formatters::NSSetMSyntheticFrontEnd::Update() 338 { 339 m_children.clear(); 340 ValueObjectSP valobj_sp = m_backend.GetSP(); 341 m_ptr_size = 0; 342 delete m_data_32; 343 m_data_32 = NULL; 344 delete m_data_64; 345 m_data_64 = NULL; 346 if (!valobj_sp) 347 return false; 348 if (!valobj_sp) 349 return false; 350 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 351 Error error; 352 if (valobj_sp->IsPointerType()) 353 { 354 valobj_sp = valobj_sp->Dereference(error); 355 if (error.Fail() || !valobj_sp) 356 return false; 357 } 358 error.Clear(); 359 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 360 if (!process_sp) 361 return false; 362 m_ptr_size = process_sp->GetAddressByteSize(); 363 uint64_t data_location = valobj_sp->GetAddressOf() + m_ptr_size; 364 if (m_ptr_size == 4) 365 { 366 m_data_32 = new DataDescriptor_32(); 367 process_sp->ReadMemory (data_location, m_data_32, sizeof(DataDescriptor_32), error); 368 } 369 else 370 { 371 m_data_64 = new DataDescriptor_64(); 372 process_sp->ReadMemory (data_location, m_data_64, sizeof(DataDescriptor_64), error); 373 } 374 if (error.Fail()) 375 return false; 376 return false; 377 } 378 379 bool 380 lldb_private::formatters::NSSetMSyntheticFrontEnd::MightHaveChildren () 381 { 382 return true; 383 } 384 385 lldb::ValueObjectSP 386 lldb_private::formatters::NSSetMSyntheticFrontEnd::GetChildAtIndex (size_t idx) 387 { 388 lldb::addr_t m_objs_addr = (m_data_32 ? m_data_32->_objs_addr : m_data_64->_objs_addr); 389 390 uint32_t num_children = CalculateNumChildren(); 391 392 if (idx >= num_children) 393 return lldb::ValueObjectSP(); 394 395 if (m_children.empty()) 396 { 397 // do the scan phase 398 lldb::addr_t obj_at_idx = 0; 399 400 uint32_t tries = 0; 401 uint32_t test_idx = 0; 402 403 while(tries < num_children) 404 { 405 obj_at_idx = m_objs_addr + (test_idx * m_ptr_size); 406 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP(); 407 if (!process_sp) 408 return lldb::ValueObjectSP(); 409 Error error; 410 obj_at_idx = process_sp->ReadPointerFromMemory(obj_at_idx, error); 411 if (error.Fail()) 412 return lldb::ValueObjectSP(); 413 414 test_idx++; 415 416 if (!obj_at_idx) 417 continue; 418 tries++; 419 420 SetItemDescriptor descriptor = {obj_at_idx,lldb::ValueObjectSP()}; 421 422 m_children.push_back(descriptor); 423 } 424 } 425 426 if (idx >= m_children.size()) // should never happen 427 return lldb::ValueObjectSP(); 428 429 SetItemDescriptor &set_item = m_children[idx]; 430 if (!set_item.valobj_sp) 431 { 432 // make the new ValueObject 433 StreamString expr; 434 expr.Printf("(id)%" PRIu64,set_item.item_ptr); 435 StreamString idx_name; 436 idx_name.Printf("[%zu]",idx); 437 set_item.valobj_sp = ValueObject::CreateValueObjectFromExpression(idx_name.GetData(), expr.GetData(), m_exe_ctx_ref); 438 } 439 return set_item.valobj_sp; 440 } 441 442 lldb_private::formatters::NSOrderedSetSyntheticFrontEnd::NSOrderedSetSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) : 443 SyntheticChildrenFrontEnd(*valobj_sp.get()), 444 m_count(UINT32_MAX), 445 m_children() 446 {} 447 448 size_t 449 lldb_private::formatters::NSOrderedSetSyntheticFrontEnd::CalculateNumChildren () 450 { 451 if (m_count != UINT32_MAX) 452 return m_count; 453 uint64_t count_temp; 454 if (ExtractValueFromObjCExpression(m_backend,"unsigned int","count",count_temp)) 455 return (m_count = count_temp); 456 return (m_count = 0); 457 } 458 459 lldb::ValueObjectSP 460 lldb_private::formatters::NSOrderedSetSyntheticFrontEnd::GetChildAtIndex (size_t idx) 461 { 462 auto iter = m_children.find(idx); 463 if (iter == m_children.end()) 464 { 465 lldb::ValueObjectSP retval_sp; 466 if (idx <= m_count) 467 { 468 retval_sp = CallSelectorOnObject(m_backend, "id", "objectAtIndex", idx); 469 if (retval_sp) 470 { 471 StreamString idx_name; 472 idx_name.Printf("[%zu]",idx); 473 retval_sp->SetName(ConstString(idx_name.GetData())); 474 } 475 m_children[idx] = retval_sp; 476 } 477 return retval_sp; 478 } 479 else 480 return iter->second; 481 } 482 483 bool 484 lldb_private::formatters::NSOrderedSetSyntheticFrontEnd::Update() 485 { 486 return false; 487 } 488 489 bool 490 lldb_private::formatters::NSOrderedSetSyntheticFrontEnd::MightHaveChildren () 491 { 492 return true; 493 } 494 495 size_t 496 lldb_private::formatters::NSOrderedSetSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name) 497 { 498 const char* item_name = name.GetCString(); 499 uint32_t idx = ExtractIndexFromString(item_name); 500 if (idx < UINT32_MAX && idx >= CalculateNumChildren()) 501 return UINT32_MAX; 502 return idx; 503 } 504 505 lldb_private::formatters::NSOrderedSetSyntheticFrontEnd::~NSOrderedSetSyntheticFrontEnd () 506 { 507 } 508 509 template bool 510 lldb_private::formatters::NSSetSummaryProvider<true> (ValueObject& valobj, Stream& stream); 511 512 template bool 513 lldb_private::formatters::NSSetSummaryProvider<false> (ValueObject& valobj, Stream& stream); 514