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