1 //===-- LibCxxVector.cpp --------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "LibCxx.h" 10 11 #include "lldb/Core/ValueObject.h" 12 #include "lldb/DataFormatters/FormattersHelpers.h" 13 #include "lldb/Utility/ConstString.h" 14 15 using namespace lldb; 16 using namespace lldb_private; 17 using namespace lldb_private::formatters; 18 19 namespace lldb_private { 20 namespace formatters { 21 class LibcxxStdVectorSyntheticFrontEnd : public SyntheticChildrenFrontEnd { 22 public: 23 LibcxxStdVectorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); 24 25 ~LibcxxStdVectorSyntheticFrontEnd() override; 26 27 size_t CalculateNumChildren() override; 28 29 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; 30 31 bool Update() override; 32 33 bool MightHaveChildren() override; 34 35 size_t GetIndexOfChildWithName(ConstString name) override; 36 37 private: 38 ValueObject *m_start = nullptr; 39 ValueObject *m_finish = nullptr; 40 CompilerType m_element_type; 41 uint32_t m_element_size = 0; 42 }; 43 44 class LibcxxVectorBoolSyntheticFrontEnd : public SyntheticChildrenFrontEnd { 45 public: 46 LibcxxVectorBoolSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp); 47 48 size_t CalculateNumChildren() override; 49 50 lldb::ValueObjectSP GetChildAtIndex(size_t idx) override; 51 52 bool Update() override; 53 54 bool MightHaveChildren() override { return true; } 55 56 size_t GetIndexOfChildWithName(ConstString name) override; 57 58 private: 59 CompilerType m_bool_type; 60 ExecutionContextRef m_exe_ctx_ref; 61 uint64_t m_count = 0; 62 lldb::addr_t m_base_data_address = 0; 63 std::map<size_t, lldb::ValueObjectSP> m_children; 64 }; 65 66 } // namespace formatters 67 } // namespace lldb_private 68 69 lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd:: 70 LibcxxStdVectorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 71 : SyntheticChildrenFrontEnd(*valobj_sp), m_element_type() { 72 if (valobj_sp) 73 Update(); 74 } 75 76 lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd:: 77 ~LibcxxStdVectorSyntheticFrontEnd() { 78 // these need to stay around because they are child objects who will follow 79 // their parent's life cycle 80 // delete m_start; 81 // delete m_finish; 82 } 83 84 size_t lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd:: 85 CalculateNumChildren() { 86 if (!m_start || !m_finish) 87 return 0; 88 uint64_t start_val = m_start->GetValueAsUnsigned(0); 89 uint64_t finish_val = m_finish->GetValueAsUnsigned(0); 90 91 if (start_val == 0 || finish_val == 0) 92 return 0; 93 94 if (start_val >= finish_val) 95 return 0; 96 97 size_t num_children = (finish_val - start_val); 98 if (num_children % m_element_size) 99 return 0; 100 return num_children / m_element_size; 101 } 102 103 lldb::ValueObjectSP 104 lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::GetChildAtIndex( 105 size_t idx) { 106 if (!m_start || !m_finish) 107 return lldb::ValueObjectSP(); 108 109 uint64_t offset = idx * m_element_size; 110 offset = offset + m_start->GetValueAsUnsigned(0); 111 StreamString name; 112 name.Printf("[%" PRIu64 "]", (uint64_t)idx); 113 return CreateValueObjectFromAddress(name.GetString(), offset, 114 m_backend.GetExecutionContextRef(), 115 m_element_type); 116 } 117 118 bool lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd::Update() { 119 m_start = m_finish = nullptr; 120 ValueObjectSP data_type_finder_sp( 121 m_backend.GetChildMemberWithName(ConstString("__end_cap_"), true)); 122 if (!data_type_finder_sp) 123 return false; 124 125 switch (data_type_finder_sp->GetCompilerType().GetNumDirectBaseClasses()) { 126 case 1: 127 // Assume a pre llvm r300140 __compressed_pair implementation: 128 data_type_finder_sp = data_type_finder_sp->GetChildMemberWithName( 129 ConstString("__first_"), true); 130 break; 131 case 2: { 132 // Assume a post llvm r300140 __compressed_pair implementation: 133 ValueObjectSP first_elem_parent_sp = 134 data_type_finder_sp->GetChildAtIndex(0, true); 135 data_type_finder_sp = first_elem_parent_sp->GetChildMemberWithName( 136 ConstString("__value_"), true); 137 break; 138 } 139 default: 140 return false; 141 } 142 143 if (!data_type_finder_sp) 144 return false; 145 m_element_type = data_type_finder_sp->GetCompilerType().GetPointeeType(); 146 if (llvm::Optional<uint64_t> size = m_element_type.GetByteSize(nullptr)) { 147 m_element_size = *size; 148 149 if (m_element_size > 0) { 150 // store raw pointers or end up with a circular dependency 151 m_start = 152 m_backend.GetChildMemberWithName(ConstString("__begin_"), true).get(); 153 m_finish = 154 m_backend.GetChildMemberWithName(ConstString("__end_"), true).get(); 155 } 156 } 157 return false; 158 } 159 160 bool lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd:: 161 MightHaveChildren() { 162 return true; 163 } 164 165 size_t lldb_private::formatters::LibcxxStdVectorSyntheticFrontEnd:: 166 GetIndexOfChildWithName(ConstString name) { 167 if (!m_start || !m_finish) 168 return UINT32_MAX; 169 return ExtractIndexFromString(name.GetCString()); 170 } 171 172 lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd:: 173 LibcxxVectorBoolSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp) 174 : SyntheticChildrenFrontEnd(*valobj_sp), m_bool_type(), m_exe_ctx_ref(), 175 m_children() { 176 if (valobj_sp) { 177 Update(); 178 m_bool_type = 179 valobj_sp->GetCompilerType().GetBasicTypeFromAST(lldb::eBasicTypeBool); 180 } 181 } 182 183 size_t lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd:: 184 CalculateNumChildren() { 185 return m_count; 186 } 187 188 lldb::ValueObjectSP 189 lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::GetChildAtIndex( 190 size_t idx) { 191 auto iter = m_children.find(idx), end = m_children.end(); 192 if (iter != end) 193 return iter->second; 194 if (idx >= m_count) 195 return {}; 196 if (m_base_data_address == 0 || m_count == 0) 197 return {}; 198 if (!m_bool_type) 199 return {}; 200 size_t byte_idx = (idx >> 3); // divide by 8 to get byte index 201 size_t bit_index = (idx & 7); // efficient idx % 8 for bit index 202 lldb::addr_t byte_location = m_base_data_address + byte_idx; 203 ProcessSP process_sp(m_exe_ctx_ref.GetProcessSP()); 204 if (!process_sp) 205 return {}; 206 uint8_t byte = 0; 207 uint8_t mask = 0; 208 Status err; 209 size_t bytes_read = process_sp->ReadMemory(byte_location, &byte, 1, err); 210 if (err.Fail() || bytes_read == 0) 211 return {}; 212 mask = 1 << bit_index; 213 bool bit_set = ((byte & mask) != 0); 214 llvm::Optional<uint64_t> size = m_bool_type.GetByteSize(nullptr); 215 if (!size) 216 return {}; 217 WritableDataBufferSP buffer_sp(new DataBufferHeap(*size, 0)); 218 if (bit_set && buffer_sp && buffer_sp->GetBytes()) { 219 // regardless of endianness, anything non-zero is true 220 *(buffer_sp->GetBytes()) = 1; 221 } 222 StreamString name; 223 name.Printf("[%" PRIu64 "]", (uint64_t)idx); 224 ValueObjectSP retval_sp(CreateValueObjectFromData( 225 name.GetString(), 226 DataExtractor(buffer_sp, process_sp->GetByteOrder(), 227 process_sp->GetAddressByteSize()), 228 m_exe_ctx_ref, m_bool_type)); 229 if (retval_sp) 230 m_children[idx] = retval_sp; 231 return retval_sp; 232 } 233 234 /*(std::__1::vector<std::__1::allocator<bool> >) vBool = { 235 __begin_ = 0x00000001001000e0 236 __size_ = 56 237 __cap_alloc_ = { 238 std::__1::__libcpp_compressed_pair_imp<unsigned long, 239 std::__1::allocator<unsigned long> > = { 240 __first_ = 1 241 } 242 } 243 }*/ 244 245 bool lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd::Update() { 246 m_children.clear(); 247 ValueObjectSP valobj_sp = m_backend.GetSP(); 248 if (!valobj_sp) 249 return false; 250 m_exe_ctx_ref = valobj_sp->GetExecutionContextRef(); 251 ValueObjectSP size_sp( 252 valobj_sp->GetChildMemberWithName(ConstString("__size_"), true)); 253 if (!size_sp) 254 return false; 255 m_count = size_sp->GetValueAsUnsigned(0); 256 if (!m_count) 257 return true; 258 ValueObjectSP begin_sp( 259 valobj_sp->GetChildMemberWithName(ConstString("__begin_"), true)); 260 if (!begin_sp) { 261 m_count = 0; 262 return false; 263 } 264 m_base_data_address = begin_sp->GetValueAsUnsigned(0); 265 if (!m_base_data_address) { 266 m_count = 0; 267 return false; 268 } 269 return false; 270 } 271 272 size_t lldb_private::formatters::LibcxxVectorBoolSyntheticFrontEnd:: 273 GetIndexOfChildWithName(ConstString name) { 274 if (!m_count || !m_base_data_address) 275 return UINT32_MAX; 276 const char *item_name = name.GetCString(); 277 uint32_t idx = ExtractIndexFromString(item_name); 278 if (idx < UINT32_MAX && idx >= CalculateNumChildren()) 279 return UINT32_MAX; 280 return idx; 281 } 282 283 lldb_private::SyntheticChildrenFrontEnd * 284 lldb_private::formatters::LibcxxStdVectorSyntheticFrontEndCreator( 285 CXXSyntheticChildren *, lldb::ValueObjectSP valobj_sp) { 286 if (!valobj_sp) 287 return nullptr; 288 CompilerType type = valobj_sp->GetCompilerType(); 289 if (!type.IsValid() || type.GetNumTemplateArguments() == 0) 290 return nullptr; 291 CompilerType arg_type = type.GetTypeTemplateArgument(0); 292 if (arg_type.GetTypeName() == "bool") 293 return new LibcxxVectorBoolSyntheticFrontEnd(valobj_sp); 294 return new LibcxxStdVectorSyntheticFrontEnd(valobj_sp); 295 } 296