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