1 //===-- NSIndexPath.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 // C Includes 11 // C++ Includes 12 // Other libraries and framework includes 13 // Project includes 14 #include "Cocoa.h" 15 16 #include "lldb/Core/ValueObject.h" 17 #include "lldb/Core/ValueObjectConstResult.h" 18 #include "lldb/DataFormatters/FormattersHelpers.h" 19 #include "lldb/DataFormatters/TypeSynthetic.h" 20 #include "lldb/Symbol/ClangASTContext.h" 21 #include "lldb/Target/ObjCLanguageRuntime.h" 22 #include "lldb/Target/Process.h" 23 #include "lldb/Target/Target.h" 24 25 using namespace lldb; 26 using namespace lldb_private; 27 using namespace lldb_private::formatters; 28 29 class NSIndexPathSyntheticFrontEnd : public SyntheticChildrenFrontEnd 30 { 31 public: 32 NSIndexPathSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) : 33 SyntheticChildrenFrontEnd (*valobj_sp.get()), 34 m_descriptor_sp(nullptr), 35 m_impl(), 36 m_ptr_size(0), 37 m_uint_star_type() 38 { 39 m_ptr_size = m_backend.GetTargetSP()->GetArchitecture().GetAddressByteSize(); 40 } 41 42 ~NSIndexPathSyntheticFrontEnd() override = default; 43 44 size_t 45 CalculateNumChildren() override 46 { 47 return m_impl.GetNumIndexes(); 48 } 49 50 lldb::ValueObjectSP 51 GetChildAtIndex(size_t idx) override 52 { 53 return m_impl.GetIndexAtIndex(idx, m_uint_star_type); 54 } 55 56 bool 57 Update() override 58 { 59 m_impl.Clear(); 60 61 TypeSystem* type_system = m_backend.GetCompilerType().GetTypeSystem(); 62 if (!type_system) 63 return false; 64 65 ClangASTContext *ast = m_backend.GetExecutionContextRef().GetTargetSP()->GetScratchClangASTContext(); 66 if (!ast) 67 return false; 68 69 m_uint_star_type = ast->GetPointerSizedIntType(false); 70 71 static ConstString g__indexes("_indexes"); 72 static ConstString g__length("_length"); 73 74 ProcessSP process_sp = m_backend.GetProcessSP(); 75 if (!process_sp) 76 return false; 77 78 ObjCLanguageRuntime* runtime = (ObjCLanguageRuntime*)process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); 79 80 if (!runtime) 81 return false; 82 83 ObjCLanguageRuntime::ClassDescriptorSP descriptor(runtime->GetClassDescriptor(m_backend)); 84 85 if (!descriptor.get() || !descriptor->IsValid()) 86 return false; 87 88 uint64_t info_bits(0),value_bits(0),payload(0); 89 90 if (descriptor->GetTaggedPointerInfo(&info_bits, &value_bits, &payload)) 91 { 92 m_impl.m_inlined.SetIndexes(payload, *process_sp); 93 m_impl.m_mode = Mode::Inlined; 94 } 95 else 96 { 97 ObjCLanguageRuntime::ClassDescriptor::iVarDescriptor _indexes_id; 98 ObjCLanguageRuntime::ClassDescriptor::iVarDescriptor _length_id; 99 100 bool has_indexes(false),has_length(false); 101 102 for (size_t x = 0; 103 x < descriptor->GetNumIVars(); 104 x++) 105 { 106 const auto& ivar = descriptor->GetIVarAtIndex(x); 107 if (ivar.m_name == g__indexes) 108 { 109 _indexes_id = ivar; 110 has_indexes = true; 111 } 112 else if (ivar.m_name == g__length) 113 { 114 _length_id = ivar; 115 has_length = true; 116 } 117 118 if (has_length && has_indexes) 119 break; 120 } 121 122 if (has_length && has_indexes) 123 { 124 m_impl.m_outsourced.m_indexes = m_backend.GetSyntheticChildAtOffset(_indexes_id.m_offset, 125 m_uint_star_type.GetPointerType(), 126 true).get(); 127 ValueObjectSP length_sp(m_backend.GetSyntheticChildAtOffset(_length_id.m_offset, 128 m_uint_star_type, 129 true)); 130 if (length_sp) 131 { 132 m_impl.m_outsourced.m_count = length_sp->GetValueAsUnsigned(0); 133 if (m_impl.m_outsourced.m_indexes) 134 m_impl.m_mode = Mode::Outsourced; 135 } 136 } 137 } 138 return false; 139 } 140 141 bool 142 MightHaveChildren() override 143 { 144 if (m_impl.m_mode == Mode::Invalid) 145 return false; 146 return true; 147 } 148 149 size_t 150 GetIndexOfChildWithName(const ConstString &name) override 151 { 152 const char* item_name = name.GetCString(); 153 uint32_t idx = ExtractIndexFromString(item_name); 154 if (idx < UINT32_MAX && idx >= CalculateNumChildren()) 155 return UINT32_MAX; 156 return idx; 157 } 158 159 lldb::ValueObjectSP 160 GetSyntheticValue() override 161 { 162 return nullptr; 163 } 164 165 protected: 166 ObjCLanguageRuntime::ClassDescriptorSP m_descriptor_sp; 167 168 enum class Mode { 169 Inlined, 170 Outsourced, 171 Invalid 172 }; 173 174 struct Impl 175 { 176 size_t 177 GetNumIndexes () 178 { 179 switch (m_mode) 180 { 181 case Mode::Inlined: 182 return m_inlined.GetNumIndexes(); 183 case Mode::Outsourced: 184 return m_outsourced.m_count; 185 default: 186 return 0; 187 } 188 } 189 190 lldb::ValueObjectSP 191 GetIndexAtIndex (size_t idx, const CompilerType& desired_type) 192 { 193 if (idx >= GetNumIndexes()) 194 return nullptr; 195 switch (m_mode) 196 { 197 default: return nullptr; 198 case Mode::Inlined: 199 return m_inlined.GetIndexAtIndex (idx, desired_type); 200 case Mode::Outsourced: 201 return m_outsourced.GetIndexAtIndex (idx); 202 } 203 } 204 205 struct InlinedIndexes 206 { 207 public: 208 void SetIndexes(uint64_t value, Process& p) 209 { 210 m_indexes = value; 211 _lengthForInlinePayload(p.GetAddressByteSize()); 212 m_process = &p; 213 } 214 215 size_t 216 GetNumIndexes () 217 { 218 return m_count; 219 } 220 221 lldb::ValueObjectSP 222 GetIndexAtIndex (size_t idx, const CompilerType& desired_type) 223 { 224 if (!m_process) 225 return nullptr; 226 227 std::pair<uint64_t, bool> value(_indexAtPositionForInlinePayload(idx)); 228 if (!value.second) 229 return nullptr; 230 231 Value v; 232 if (m_ptr_size == 8) 233 { 234 Scalar scalar( (unsigned long long)value.first ); 235 v = Value(scalar); 236 } 237 else 238 { 239 Scalar scalar( (unsigned int)value.first ); 240 v = Value(scalar); 241 } 242 243 v.SetCompilerType(desired_type); 244 245 StreamString idx_name; 246 idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx); 247 248 return ValueObjectConstResult::Create(m_process, v, ConstString(idx_name.GetData())); 249 } 250 251 void 252 Clear () 253 { 254 m_indexes = 0; 255 m_count = 0; 256 m_ptr_size = 0; 257 m_process = nullptr; 258 } 259 260 InlinedIndexes () : 261 m_indexes(0), 262 m_count(0), 263 m_ptr_size(0), 264 m_process(nullptr) 265 { 266 } 267 268 private: 269 uint64_t m_indexes; 270 size_t m_count; 271 uint32_t m_ptr_size; 272 Process *m_process; 273 274 // cfr. Foundation for the details of this code 275 size_t _lengthForInlinePayload(uint32_t ptr_size) { 276 m_ptr_size = ptr_size; 277 if (m_ptr_size == 8) 278 m_count = ((m_indexes >> 3) & 0x7); 279 else 280 m_count = ((m_indexes >> 3) & 0x3); 281 return m_count; 282 } 283 284 std::pair<uint64_t, bool> 285 _indexAtPositionForInlinePayload(size_t pos) 286 { 287 if (m_ptr_size == 8) 288 { 289 switch (pos) { 290 case 5: return {((m_indexes >> 51) & 0x1ff),true}; 291 case 4: return {((m_indexes >> 42) & 0x1ff),true}; 292 case 3: return {((m_indexes >> 33) & 0x1ff),true}; 293 case 2: return {((m_indexes >> 24) & 0x1ff),true}; 294 case 1: return {((m_indexes >> 15) & 0x1ff),true}; 295 case 0: return {((m_indexes >> 6) & 0x1ff),true}; 296 } 297 } 298 else 299 { 300 switch (pos) { 301 case 2: return {((m_indexes >> 23) & 0x1ff),true}; 302 case 1: return {((m_indexes >> 14) & 0x1ff),true}; 303 case 0: return {((m_indexes >> 5) & 0x1ff),true}; 304 } 305 } 306 return {0,false}; 307 } 308 309 }; 310 311 struct OutsourcedIndexes 312 { 313 lldb::ValueObjectSP 314 GetIndexAtIndex (size_t idx) 315 { 316 if (m_indexes) 317 { 318 ValueObjectSP index_sp(m_indexes->GetSyntheticArrayMember(idx, true)); 319 return index_sp; 320 } 321 return nullptr; 322 } 323 324 void 325 Clear () 326 { 327 m_indexes = nullptr; 328 m_count = 0; 329 } 330 331 OutsourcedIndexes () : 332 m_indexes(nullptr), 333 m_count(0) 334 { 335 } 336 337 ValueObject *m_indexes; 338 size_t m_count; 339 }; 340 341 union 342 { 343 struct InlinedIndexes m_inlined; 344 struct OutsourcedIndexes m_outsourced; 345 }; 346 347 void 348 Clear () 349 { 350 m_mode = Mode::Invalid; 351 m_inlined.Clear(); 352 m_outsourced.Clear(); 353 } 354 355 Impl() : 356 m_mode(Mode::Invalid) 357 { 358 } 359 360 Mode m_mode; 361 } m_impl; 362 363 uint32_t m_ptr_size; 364 CompilerType m_uint_star_type; 365 }; 366 367 namespace lldb_private { 368 namespace formatters { 369 370 SyntheticChildrenFrontEnd* NSIndexPathSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp) 371 { 372 if (valobj_sp) 373 return new NSIndexPathSyntheticFrontEnd(valobj_sp); 374 return nullptr; 375 } 376 377 } // namespace formatters 378 } // namespace lldb_private 379