306 lines · cpp
1//===-- MsvcStlVector.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-exception6//7//===----------------------------------------------------------------------===//8 9#include "MsvcStl.h"10 11#include "lldb/DataFormatters/FormattersHelpers.h"12#include "lldb/DataFormatters/TypeSynthetic.h"13 14using namespace lldb;15 16namespace lldb_private {17namespace formatters {18 19class MsvcStlVectorSyntheticFrontEnd : public SyntheticChildrenFrontEnd {20public:21 MsvcStlVectorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);22 23 llvm::Expected<uint32_t> CalculateNumChildren() override;24 25 lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;26 27 lldb::ChildCacheState Update() override;28 29 llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;30 31private:32 ValueObject *m_start = nullptr;33 ValueObject *m_finish = nullptr;34 CompilerType m_element_type;35 uint32_t m_element_size = 0;36};37 38class MsvcStlVectorBoolSyntheticFrontEnd : public SyntheticChildrenFrontEnd {39public:40 MsvcStlVectorBoolSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp);41 42 llvm::Expected<uint32_t> CalculateNumChildren() override;43 44 lldb::ValueObjectSP GetChildAtIndex(uint32_t idx) override;45 46 lldb::ChildCacheState Update() override;47 48 llvm::Expected<size_t> GetIndexOfChildWithName(ConstString name) override;49 50private:51 CompilerType m_bool_type;52 ExecutionContextRef m_exe_ctx_ref;53 uint64_t m_count = 0;54 uint64_t m_element_bit_size = 0;55 lldb::addr_t m_base_data_address = 0;56 std::map<size_t, lldb::ValueObjectSP> m_children;57};58 59} // namespace formatters60} // namespace lldb_private61 62lldb_private::formatters::MsvcStlVectorSyntheticFrontEnd::63 MsvcStlVectorSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)64 : SyntheticChildrenFrontEnd(*valobj_sp), m_element_type() {65 if (valobj_sp)66 Update();67}68 69llvm::Expected<uint32_t> lldb_private::formatters::70 MsvcStlVectorSyntheticFrontEnd::CalculateNumChildren() {71 if (!m_start || !m_finish)72 return llvm::createStringError(73 "failed to determine start/end of vector data");74 75 uint64_t start_val = m_start->GetValueAsUnsigned(0);76 uint64_t finish_val = m_finish->GetValueAsUnsigned(0);77 78 // A default-initialized empty vector.79 if (start_val == 0 && finish_val == 0)80 return 0;81 82 if (start_val == 0)83 return llvm::createStringError("invalid value for start of vector");84 85 if (finish_val == 0)86 return llvm::createStringError("invalid value for end of vector");87 88 if (start_val > finish_val)89 return llvm::createStringError(90 "start of vector data begins after end pointer");91 92 size_t num_children = (finish_val - start_val);93 if (num_children % m_element_size)94 return llvm::createStringError("size not multiple of element size");95 96 return num_children / m_element_size;97}98 99lldb::ValueObjectSP100lldb_private::formatters::MsvcStlVectorSyntheticFrontEnd::GetChildAtIndex(101 uint32_t idx) {102 if (!m_start || !m_finish)103 return lldb::ValueObjectSP();104 105 uint64_t offset = idx * m_element_size;106 offset = offset + m_start->GetValueAsUnsigned(0);107 StreamString name;108 name.Printf("[%" PRIu64 "]", (uint64_t)idx);109 return CreateValueObjectFromAddress(name.GetString(), offset,110 m_backend.GetExecutionContextRef(),111 m_element_type);112}113 114lldb::ChildCacheState115lldb_private::formatters::MsvcStlVectorSyntheticFrontEnd::Update() {116 m_start = m_finish = nullptr;117 ValueObjectSP data_sp(m_backend.GetChildAtNamePath({"_Mypair", "_Myval2"}));118 119 if (!data_sp)120 return lldb::ChildCacheState::eRefetch;121 122 m_start = data_sp->GetChildMemberWithName("_Myfirst").get();123 m_finish = data_sp->GetChildMemberWithName("_Mylast").get();124 if (!m_start || !m_finish)125 return lldb::ChildCacheState::eRefetch;126 127 m_element_type = m_start->GetCompilerType().GetPointeeType();128 llvm::Expected<uint64_t> size_or_err = m_element_type.GetByteSize(nullptr);129 if (size_or_err)130 m_element_size = *size_or_err;131 else132 LLDB_LOG_ERRORV(GetLog(LLDBLog::DataFormatters), size_or_err.takeError(),133 "{0}");134 135 return lldb::ChildCacheState::eRefetch;136}137 138llvm::Expected<size_t> lldb_private::formatters::139 MsvcStlVectorSyntheticFrontEnd::GetIndexOfChildWithName(ConstString name) {140 if (!m_start || !m_finish)141 return llvm::createStringError("Type has no child named '%s'",142 name.AsCString());143 auto optional_idx = ExtractIndexFromString(name.GetCString());144 if (!optional_idx) {145 return llvm::createStringError("Type has no child named '%s'",146 name.AsCString());147 }148 return *optional_idx;149}150 151lldb_private::formatters::MsvcStlVectorBoolSyntheticFrontEnd::152 MsvcStlVectorBoolSyntheticFrontEnd(lldb::ValueObjectSP valobj_sp)153 : SyntheticChildrenFrontEnd(*valobj_sp), m_bool_type(), m_exe_ctx_ref(),154 m_children() {155 if (valobj_sp) {156 Update();157 m_bool_type =158 valobj_sp->GetCompilerType().GetBasicTypeFromAST(lldb::eBasicTypeBool);159 }160}161 162llvm::Expected<uint32_t> lldb_private::formatters::163 MsvcStlVectorBoolSyntheticFrontEnd::CalculateNumChildren() {164 return m_count;165}166 167lldb::ValueObjectSP168lldb_private::formatters::MsvcStlVectorBoolSyntheticFrontEnd::GetChildAtIndex(169 uint32_t idx) {170 auto iter = m_children.find(idx), end = m_children.end();171 if (iter != end)172 return iter->second;173 if (idx >= m_count)174 return {};175 if (m_base_data_address == 0 || m_count == 0)176 return {};177 if (!m_bool_type)178 return {};179 180 // The vector<bool> is represented as a sequence of `int`s.181 // The size of an `int` is in `m_element_bit_size` (most often 32b).182 // To access the element at index `i`:183 // (bool)((data_address[i / bit_size] >> (i % bit_size)) & 1)184 185 // int *byte_location = &data_address[i / bit_size]186 size_t byte_idx = (idx / m_element_bit_size) * (m_element_bit_size / 8);187 lldb::addr_t byte_location = m_base_data_address + byte_idx;188 189 ProcessSP process_sp(m_exe_ctx_ref.GetProcessSP());190 if (!process_sp)191 return {};192 Status err;193 Scalar scalar;194 size_t bytes_read = process_sp->ReadScalarIntegerFromMemory(195 byte_location, m_element_bit_size / 8, false, scalar, err);196 if (err.Fail() || bytes_read == 0 || !scalar.IsValid())197 return {};198 199 size_t bit_index = idx % m_element_bit_size;200 bool bit_set = scalar.GetAPSInt()[bit_index];201 std::optional<uint64_t> size =202 llvm::expectedToOptional(m_bool_type.GetByteSize(nullptr));203 if (!size)204 return {};205 WritableDataBufferSP buffer_sp(new DataBufferHeap(*size, 0));206 if (bit_set && buffer_sp && buffer_sp->GetBytes()) {207 // regardless of endianness, anything non-zero is true208 *(buffer_sp->GetBytes()) = 1;209 }210 StreamString name;211 name.Printf("[%" PRIu64 "]", (uint64_t)idx);212 ValueObjectSP retval_sp(CreateValueObjectFromData(213 name.GetString(),214 DataExtractor(buffer_sp, process_sp->GetByteOrder(),215 process_sp->GetAddressByteSize()),216 m_exe_ctx_ref, m_bool_type));217 if (retval_sp)218 m_children[idx] = retval_sp;219 return retval_sp;220}221 222lldb::ChildCacheState223lldb_private::formatters::MsvcStlVectorBoolSyntheticFrontEnd::Update() {224 m_exe_ctx_ref.Clear();225 m_count = 0;226 m_element_bit_size = 0;227 m_base_data_address = 0;228 m_children.clear();229 230 ValueObjectSP valobj_sp = m_backend.GetSP();231 if (!valobj_sp)232 return lldb::ChildCacheState::eRefetch;233 auto exe_ctx_ref = valobj_sp->GetExecutionContextRef();234 235 ValueObjectSP size_sp = valobj_sp->GetChildMemberWithName("_Mysize");236 if (!size_sp)237 return lldb::ChildCacheState::eRefetch;238 uint64_t count = size_sp->GetValueAsUnsigned(0);239 if (count == 0)240 return lldb::ChildCacheState::eReuse;241 242 ValueObjectSP begin_sp(valobj_sp->GetChildAtNamePath(243 {"_Myvec", "_Mypair", "_Myval2", "_Myfirst"}));244 if (!begin_sp)245 return lldb::ChildCacheState::eRefetch;246 247 // FIXME: the STL exposes _EEN_VBITS as a constant - it should be used instead248 CompilerType begin_ty = begin_sp->GetCompilerType().GetPointeeType();249 if (!begin_ty.IsValid())250 return lldb::ChildCacheState::eRefetch;251 llvm::Expected<uint64_t> element_bit_size = begin_ty.GetBitSize(nullptr);252 if (!element_bit_size)253 return lldb::ChildCacheState::eRefetch;254 255 uint64_t base_data_address = begin_sp->GetValueAsUnsigned(0);256 if (!base_data_address)257 return lldb::ChildCacheState::eRefetch;258 259 m_exe_ctx_ref = exe_ctx_ref;260 m_count = count;261 m_element_bit_size = *element_bit_size;262 m_base_data_address = base_data_address;263 return lldb::ChildCacheState::eRefetch;264}265 266llvm::Expected<size_t>267lldb_private::formatters::MsvcStlVectorBoolSyntheticFrontEnd::268 GetIndexOfChildWithName(ConstString name) {269 if (!m_count || !m_base_data_address)270 return llvm::createStringError("Type has no child named '%s'",271 name.AsCString());272 auto optional_idx = ExtractIndexFromString(name.AsCString());273 if (!optional_idx) {274 return llvm::createStringError("Type has no child named '%s'",275 name.AsCString());276 }277 uint32_t idx = *optional_idx;278 if (idx >= CalculateNumChildrenIgnoringErrors())279 return llvm::createStringError("Type has no child named '%s'",280 name.AsCString());281 return idx;282}283 284lldb_private::SyntheticChildrenFrontEnd *285lldb_private::formatters::MsvcStlVectorSyntheticFrontEndCreator(286 lldb::ValueObjectSP valobj_sp) {287 if (!valobj_sp)288 return nullptr;289 290 valobj_sp = valobj_sp->GetNonSyntheticValue();291 if (!valobj_sp)292 return nullptr;293 294 // We can't check the template parameter here, because PDB doesn't include295 // this information.296 297 // vector<T>298 if (valobj_sp->GetChildMemberWithName("_Mypair") != nullptr)299 return new MsvcStlVectorSyntheticFrontEnd(valobj_sp);300 // vector<bool>301 if (valobj_sp->GetChildMemberWithName("_Myvec") != nullptr)302 return new MsvcStlVectorBoolSyntheticFrontEnd(valobj_sp);303 304 return nullptr;305}306