1 //===-- NSArray.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 bool 29 lldb_private::formatters::NSArraySummaryProvider (ValueObject& valobj, Stream& stream) 30 { 31 ProcessSP process_sp = valobj.GetProcessSP(); 32 if (!process_sp) 33 return false; 34 35 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 36 37 if (!runtime) 38 return false; 39 40 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(valobj)); 41 42 if (!descriptor.get() || !descriptor->IsValid()) 43 return false; 44 45 uint32_t ptr_size = process_sp->GetAddressByteSize(); 46 47 lldb::addr_t valobj_addr = valobj.GetValueAsUnsigned(0); 48 49 if (!valobj_addr) 50 return false; 51 52 uint64_t value = 0; 53 54 const char* class_name = descriptor->GetClassName().GetCString(); 55 56 if (!class_name || !*class_name) 57 return false; 58 59 if (!strcmp(class_name,"__NSArrayI")) 60 { 61 Error error; 62 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error); 63 if (error.Fail()) 64 return false; 65 } 66 else if (!strcmp(class_name,"__NSArrayM")) 67 { 68 Error error; 69 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + ptr_size, ptr_size, 0, error); 70 if (error.Fail()) 71 return false; 72 } 73 else if (!strcmp(class_name,"__NSCFArray")) 74 { 75 Error error; 76 value = process_sp->ReadUnsignedIntegerFromMemory(valobj_addr + 2 * ptr_size, ptr_size, 0, error); 77 if (error.Fail()) 78 return false; 79 } 80 else 81 { 82 if (!ExtractValueFromObjCExpression(valobj, "int", "count", value)) 83 return false; 84 } 85 86 stream.Printf("@\"%" PRIu64 " object%s\"", 87 value, 88 value == 1 ? "" : "s"); 89 return true; 90 } 91 92 lldb_private::formatters::NSArrayMSyntheticFrontEnd::NSArrayMSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) : 93 SyntheticChildrenFrontEnd(*valobj_sp.get()), 94 m_exe_ctx_ref(), 95 m_ptr_size(8), 96 m_data_32(NULL), 97 m_data_64(NULL) 98 { 99 if (valobj_sp) 100 { 101 clang::ASTContext *ast = valobj_sp->GetClangType().GetASTContext(); 102 if (ast) 103 m_id_type = ClangASTType(ast, ast->ObjCBuiltinIdTy); 104 } 105 } 106 107 size_t 108 lldb_private::formatters::NSArrayMSyntheticFrontEnd::CalculateNumChildren () 109 { 110 if (m_data_32) 111 return m_data_32->_used; 112 if (m_data_64) 113 return m_data_64->_used; 114 return 0; 115 } 116 117 lldb::ValueObjectSP 118 lldb_private::formatters::NSArrayMSyntheticFrontEnd::GetChildAtIndex (size_t idx) 119 { 120 if (!m_data_32 && !m_data_64) 121 return lldb::ValueObjectSP(); 122 if (idx >= CalculateNumChildren()) 123 return lldb::ValueObjectSP(); 124 lldb::addr_t object_at_idx = (m_data_32 ? m_data_32->_data : m_data_64->_data); 125 size_t pyhs_idx = idx; 126 pyhs_idx += (m_data_32 ? m_data_32->offset : m_data_64->offset); 127 if ((m_data_32 ? m_data_32->_size : m_data_64->_size) <= pyhs_idx) 128 pyhs_idx -= (m_data_32 ? m_data_32->_size : m_data_64->_size); 129 object_at_idx += (pyhs_idx * m_ptr_size); 130 StreamString idx_name; 131 idx_name.Printf("[%zu]",idx); 132 lldb::ValueObjectSP retval_sp = ValueObject::CreateValueObjectFromAddress(idx_name.GetData(), 133 object_at_idx, 134 m_exe_ctx_ref, 135 m_id_type); 136 m_children.push_back(retval_sp); 137 return retval_sp; 138 } 139 140 bool 141 lldb_private::formatters::NSArrayMSyntheticFrontEnd::Update() 142 { 143 m_children.clear(); 144 ValueObjectSP valobj_sp = m_backend.GetSP(); 145 m_ptr_size = 0; 146 delete m_data_32; 147 m_data_32 = NULL; 148 delete m_data_64; 149 m_data_64 = NULL; 150 if (!valobj_sp) 151 return false; 152 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 153 Error error; 154 error.Clear(); 155 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 156 if (!process_sp) 157 return false; 158 m_ptr_size = process_sp->GetAddressByteSize(); 159 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size; 160 if (m_ptr_size == 4) 161 { 162 m_data_32 = new DataDescriptor_32(); 163 process_sp->ReadMemory (data_location, m_data_32, sizeof(DataDescriptor_32), error); 164 } 165 else 166 { 167 m_data_64 = new DataDescriptor_64(); 168 process_sp->ReadMemory (data_location, m_data_64, sizeof(DataDescriptor_64), error); 169 } 170 if (error.Fail()) 171 return false; 172 return false; 173 } 174 175 bool 176 lldb_private::formatters::NSArrayMSyntheticFrontEnd::MightHaveChildren () 177 { 178 return true; 179 } 180 181 size_t 182 lldb_private::formatters::NSArrayMSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name) 183 { 184 if (!m_data_32 && !m_data_64) 185 return UINT32_MAX; 186 const char* item_name = name.GetCString(); 187 uint32_t idx = ExtractIndexFromString(item_name); 188 if (idx < UINT32_MAX && idx >= CalculateNumChildren()) 189 return UINT32_MAX; 190 return idx; 191 } 192 193 lldb_private::formatters::NSArrayMSyntheticFrontEnd::~NSArrayMSyntheticFrontEnd () 194 { 195 delete m_data_32; 196 m_data_32 = NULL; 197 delete m_data_64; 198 m_data_64 = NULL; 199 } 200 201 lldb_private::formatters::NSArrayISyntheticFrontEnd::NSArrayISyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) : 202 SyntheticChildrenFrontEnd (*valobj_sp.get()), 203 m_exe_ctx_ref (), 204 m_ptr_size (8), 205 m_items (0), 206 m_data_ptr (0) 207 { 208 if (valobj_sp) 209 { 210 clang::ASTContext *ast = valobj_sp->GetClangType().GetASTContext(); 211 if (ast) 212 m_id_type = ClangASTType(ast, ast->ObjCBuiltinIdTy); 213 } 214 } 215 216 lldb_private::formatters::NSArrayISyntheticFrontEnd::~NSArrayISyntheticFrontEnd () 217 { 218 } 219 220 size_t 221 lldb_private::formatters::NSArrayISyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name) 222 { 223 const char* item_name = name.GetCString(); 224 uint32_t idx = ExtractIndexFromString(item_name); 225 if (idx < UINT32_MAX && idx >= CalculateNumChildren()) 226 return UINT32_MAX; 227 return idx; 228 } 229 230 size_t 231 lldb_private::formatters::NSArrayISyntheticFrontEnd::CalculateNumChildren () 232 { 233 return m_items; 234 } 235 236 bool 237 lldb_private::formatters::NSArrayISyntheticFrontEnd::Update() 238 { 239 m_ptr_size = 0; 240 m_items = 0; 241 m_data_ptr = 0; 242 m_children.clear(); 243 ValueObjectSP valobj_sp = m_backend.GetSP(); 244 if (!valobj_sp) 245 return false; 246 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 247 Error error; 248 error.Clear(); 249 lldb::ProcessSP process_sp(valobj_sp->GetProcessSP()); 250 if (!process_sp) 251 return false; 252 m_ptr_size = process_sp->GetAddressByteSize(); 253 uint64_t data_location = valobj_sp->GetValueAsUnsigned(0) + m_ptr_size; 254 m_items = process_sp->ReadPointerFromMemory(data_location, error); 255 if (error.Fail()) 256 return false; 257 m_data_ptr = data_location+m_ptr_size; 258 return false; 259 } 260 261 bool 262 lldb_private::formatters::NSArrayISyntheticFrontEnd::MightHaveChildren () 263 { 264 return true; 265 } 266 267 lldb::ValueObjectSP 268 lldb_private::formatters::NSArrayISyntheticFrontEnd::GetChildAtIndex (size_t idx) 269 { 270 if (idx >= CalculateNumChildren()) 271 return lldb::ValueObjectSP(); 272 lldb::addr_t object_at_idx = m_data_ptr; 273 object_at_idx += (idx * m_ptr_size); 274 ProcessSP process_sp = m_exe_ctx_ref.GetProcessSP(); 275 if (!process_sp) 276 return lldb::ValueObjectSP(); 277 Error error; 278 if (error.Fail()) 279 return lldb::ValueObjectSP(); 280 StreamString idx_name; 281 idx_name.Printf("[%zu]",idx); 282 lldb::ValueObjectSP retval_sp = ValueObject::CreateValueObjectFromAddress(idx_name.GetData(), object_at_idx, m_exe_ctx_ref, m_id_type); 283 m_children.push_back(retval_sp); 284 return retval_sp; 285 } 286 287 SyntheticChildrenFrontEnd* lldb_private::formatters::NSArraySyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp) 288 { 289 lldb::ProcessSP process_sp (valobj_sp->GetProcessSP()); 290 if (!process_sp) 291 return NULL; 292 ObjCLanguageRuntime *runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 293 if (!runtime) 294 return NULL; 295 296 if (!valobj_sp->IsPointerType()) 297 { 298 Error error; 299 valobj_sp = valobj_sp->AddressOf(error); 300 if (error.Fail() || !valobj_sp) 301 return NULL; 302 } 303 304 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(*valobj_sp.get())); 305 306 if (!descriptor.get() || !descriptor->IsValid()) 307 return NULL; 308 309 const char* class_name = descriptor->GetClassName().GetCString(); 310 311 if (!class_name || !*class_name) 312 return NULL; 313 314 if (!strcmp(class_name,"__NSArrayI")) 315 { 316 return (new NSArrayISyntheticFrontEnd(valobj_sp)); 317 } 318 else if (!strcmp(class_name,"__NSArrayM")) 319 { 320 return (new NSArrayMSyntheticFrontEnd(valobj_sp)); 321 } 322 else 323 { 324 return (new NSArrayCodeRunningSyntheticFrontEnd(valobj_sp)); 325 } 326 } 327 328 lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::NSArrayCodeRunningSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) : 329 SyntheticChildrenFrontEnd(*valobj_sp.get()) 330 {} 331 332 size_t 333 lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::CalculateNumChildren () 334 { 335 uint64_t count = 0; 336 if (ExtractValueFromObjCExpression(m_backend, "int", "count", count)) 337 return count; 338 return 0; 339 } 340 341 lldb::ValueObjectSP 342 lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::GetChildAtIndex (size_t idx) 343 { 344 StreamString idx_name; 345 idx_name.Printf("[%zu]",idx); 346 lldb::ValueObjectSP valobj_sp = CallSelectorOnObject(m_backend,"id","objectAtIndex:",idx); 347 if (valobj_sp) 348 valobj_sp->SetName(ConstString(idx_name.GetData())); 349 return valobj_sp; 350 } 351 352 bool 353 lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::Update() 354 { 355 return false; 356 } 357 358 bool 359 lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::MightHaveChildren () 360 { 361 return true; 362 } 363 364 size_t 365 lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::GetIndexOfChildWithName (const ConstString &name) 366 { 367 return 0; 368 } 369 370 lldb_private::formatters::NSArrayCodeRunningSyntheticFrontEnd::~NSArrayCodeRunningSyntheticFrontEnd () 371 {} 372