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