1254721Semaste//===-- ValueObjectChild.cpp ------------------------------------*- C++ -*-===// 2254721Semaste// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6254721Semaste// 7254721Semaste//===----------------------------------------------------------------------===// 8254721Semaste 9254721Semaste#include "lldb/Core/ValueObjectChild.h" 10254721Semaste 11344779Sdim#include "lldb/Core/Value.h" 12296417Sdim#include "lldb/Symbol/CompilerType.h" 13254721Semaste#include "lldb/Target/ExecutionContext.h" 14254721Semaste#include "lldb/Target/Process.h" 15344779Sdim#include "lldb/Utility/Flags.h" 16344779Sdim#include "lldb/Utility/Scalar.h" 17344779Sdim#include "lldb/Utility/Status.h" 18344779Sdim#include "lldb/lldb-forward.h" 19254721Semaste 20344779Sdim#include <functional> 21344779Sdim#include <memory> 22344779Sdim#include <vector> 23321369Sdim 24344779Sdim#include <stdio.h> 25344779Sdim#include <string.h> 26321369Sdim 27254721Semasteusing namespace lldb_private; 28254721Semaste 29314564SdimValueObjectChild::ValueObjectChild( 30314564Sdim ValueObject &parent, const CompilerType &compiler_type, 31353358Sdim ConstString name, uint64_t byte_size, int32_t byte_offset, 32314564Sdim uint32_t bitfield_bit_size, uint32_t bitfield_bit_offset, 33314564Sdim bool is_base_class, bool is_deref_of_parent, 34314564Sdim AddressType child_ptr_or_ref_addr_type, uint64_t language_flags) 35314564Sdim : ValueObject(parent), m_compiler_type(compiler_type), 36314564Sdim m_byte_size(byte_size), m_byte_offset(byte_offset), 37314564Sdim m_bitfield_bit_size(bitfield_bit_size), 38314564Sdim m_bitfield_bit_offset(bitfield_bit_offset), 39314564Sdim m_is_base_class(is_base_class), m_is_deref_of_parent(is_deref_of_parent), 40314564Sdim m_can_update_with_invalid_exe_ctx() { 41314564Sdim m_name = name; 42314564Sdim SetAddressTypeOfChildren(child_ptr_or_ref_addr_type); 43314564Sdim SetLanguageFlags(language_flags); 44254721Semaste} 45254721Semaste 46314564SdimValueObjectChild::~ValueObjectChild() {} 47254721Semaste 48314564Sdimlldb::ValueType ValueObjectChild::GetValueType() const { 49314564Sdim return m_parent->GetValueType(); 50254721Semaste} 51254721Semaste 52314564Sdimsize_t ValueObjectChild::CalculateNumChildren(uint32_t max) { 53344779Sdim ExecutionContext exe_ctx(GetExecutionContextRef()); 54344779Sdim auto children_count = GetCompilerType().GetNumChildren(true, &exe_ctx); 55314564Sdim return children_count <= max ? children_count : max; 56254721Semaste} 57254721Semaste 58314564Sdimstatic void AdjustForBitfieldness(ConstString &name, 59314564Sdim uint8_t bitfield_bit_size) { 60314564Sdim if (name && bitfield_bit_size) { 61314564Sdim const char *compiler_type_name = name.AsCString(); 62314564Sdim if (compiler_type_name) { 63314564Sdim std::vector<char> bitfield_type_name(strlen(compiler_type_name) + 32, 0); 64314564Sdim ::snprintf(&bitfield_type_name.front(), bitfield_type_name.size(), 65314564Sdim "%s:%u", compiler_type_name, bitfield_bit_size); 66314564Sdim name.SetCString(&bitfield_type_name.front()); 67276479Sdim } 68314564Sdim } 69276479Sdim} 70276479Sdim 71314564SdimConstString ValueObjectChild::GetTypeName() { 72314564Sdim if (m_type_name.IsEmpty()) { 73314564Sdim m_type_name = GetCompilerType().GetConstTypeName(); 74314564Sdim AdjustForBitfieldness(m_type_name, m_bitfield_bit_size); 75314564Sdim } 76314564Sdim return m_type_name; 77254721Semaste} 78254721Semaste 79314564SdimConstString ValueObjectChild::GetQualifiedTypeName() { 80314564Sdim ConstString qualified_name = GetCompilerType().GetConstTypeName(); 81314564Sdim AdjustForBitfieldness(qualified_name, m_bitfield_bit_size); 82314564Sdim return qualified_name; 83254721Semaste} 84254721Semaste 85314564SdimConstString ValueObjectChild::GetDisplayTypeName() { 86314564Sdim ConstString display_name = GetCompilerType().GetDisplayTypeName(); 87314564Sdim AdjustForBitfieldness(display_name, m_bitfield_bit_size); 88314564Sdim return display_name; 89276479Sdim} 90276479Sdim 91314564SdimLazyBool ValueObjectChild::CanUpdateWithInvalidExecutionContext() { 92314564Sdim if (m_can_update_with_invalid_exe_ctx.hasValue()) 93314564Sdim return m_can_update_with_invalid_exe_ctx.getValue(); 94314564Sdim if (m_parent) { 95314564Sdim ValueObject *opinionated_parent = 96314564Sdim m_parent->FollowParentChain([](ValueObject *valobj) -> bool { 97314564Sdim return (valobj->CanUpdateWithInvalidExecutionContext() == 98314564Sdim eLazyBoolCalculate); 99296417Sdim }); 100314564Sdim if (opinionated_parent) 101314564Sdim return (m_can_update_with_invalid_exe_ctx = 102314564Sdim opinionated_parent->CanUpdateWithInvalidExecutionContext()) 103314564Sdim .getValue(); 104314564Sdim } 105314564Sdim return (m_can_update_with_invalid_exe_ctx = 106314564Sdim this->ValueObject::CanUpdateWithInvalidExecutionContext()) 107314564Sdim .getValue(); 108288943Sdim} 109288943Sdim 110314564Sdimbool ValueObjectChild::UpdateValue() { 111314564Sdim m_error.Clear(); 112314564Sdim SetValueIsValid(false); 113314564Sdim ValueObject *parent = m_parent; 114314564Sdim if (parent) { 115314564Sdim if (parent->UpdateValueIfNeeded(false)) { 116314564Sdim m_value.SetCompilerType(GetCompilerType()); 117254721Semaste 118314564Sdim CompilerType parent_type(parent->GetCompilerType()); 119314564Sdim // Copy the parent scalar value and the scalar value type 120314564Sdim m_value.GetScalar() = parent->GetValue().GetScalar(); 121314564Sdim Value::ValueType value_type = parent->GetValue().GetValueType(); 122314564Sdim m_value.SetValueType(value_type); 123314564Sdim 124314564Sdim Flags parent_type_flags(parent_type.GetTypeInfo()); 125314564Sdim const bool is_instance_ptr_base = 126344779Sdim ((m_is_base_class) && 127314564Sdim (parent_type_flags.AnySet(lldb::eTypeInstanceIsPointer))); 128314564Sdim 129314564Sdim if (parent->GetCompilerType().ShouldTreatScalarValueAsAddress()) { 130314564Sdim lldb::addr_t addr = parent->GetPointerValue(); 131314564Sdim m_value.GetScalar() = addr; 132314564Sdim 133314564Sdim if (addr == LLDB_INVALID_ADDRESS) { 134314564Sdim m_error.SetErrorString("parent address is invalid."); 135314564Sdim } else if (addr == 0) { 136314564Sdim m_error.SetErrorString("parent is NULL"); 137314564Sdim } else { 138314564Sdim m_value.GetScalar() += m_byte_offset; 139314564Sdim AddressType addr_type = parent->GetAddressTypeOfChildren(); 140314564Sdim 141314564Sdim switch (addr_type) { 142314564Sdim case eAddressTypeFile: { 143314564Sdim lldb::ProcessSP process_sp(GetProcessSP()); 144344779Sdim if (process_sp && process_sp->IsAlive()) 145314564Sdim m_value.SetValueType(Value::eValueTypeLoadAddress); 146254721Semaste else 147314564Sdim m_value.SetValueType(Value::eValueTypeFileAddress); 148314564Sdim } break; 149314564Sdim case eAddressTypeLoad: 150314564Sdim m_value.SetValueType(is_instance_ptr_base 151314564Sdim ? Value::eValueTypeScalar 152314564Sdim : Value::eValueTypeLoadAddress); 153314564Sdim break; 154314564Sdim case eAddressTypeHost: 155314564Sdim m_value.SetValueType(Value::eValueTypeHostAddress); 156314564Sdim break; 157314564Sdim case eAddressTypeInvalid: 158314564Sdim // TODO: does this make sense? 159314564Sdim m_value.SetValueType(Value::eValueTypeScalar); 160314564Sdim break; 161314564Sdim } 162254721Semaste } 163314564Sdim } else { 164314564Sdim switch (value_type) { 165314564Sdim case Value::eValueTypeLoadAddress: 166314564Sdim case Value::eValueTypeFileAddress: 167314564Sdim case Value::eValueTypeHostAddress: { 168314564Sdim lldb::addr_t addr = 169314564Sdim m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS); 170314564Sdim if (addr == LLDB_INVALID_ADDRESS) { 171314564Sdim m_error.SetErrorString("parent address is invalid."); 172314564Sdim } else if (addr == 0) { 173314564Sdim m_error.SetErrorString("parent is NULL"); 174314564Sdim } else { 175341825Sdim // Set this object's scalar value to the address of its value by 176341825Sdim // adding its byte offset to the parent address 177314564Sdim m_value.GetScalar() += GetByteOffset(); 178360784Sdim 179360784Sdim // If a bitfield doesn't fit into the child_byte_size'd 180360784Sdim // window at child_byte_offset, move the window forward 181360784Sdim // until it fits. The problem here is that Value has no 182360784Sdim // notion of bitfields and thus the Value's DataExtractor 183360784Sdim // is sized like the bitfields CompilerType; a sequence of 184360784Sdim // bitfields, however, can be larger than their underlying 185360784Sdim // type. 186360784Sdim if (m_bitfield_bit_offset) { 187360784Sdim const bool thread_and_frame_only_if_stopped = true; 188360784Sdim ExecutionContext exe_ctx(GetExecutionContextRef().Lock( 189360784Sdim thread_and_frame_only_if_stopped)); 190360784Sdim if (auto type_bit_size = GetCompilerType().GetBitSize( 191360784Sdim exe_ctx.GetBestExecutionContextScope())) { 192360784Sdim uint64_t bitfield_end = 193360784Sdim m_bitfield_bit_size + m_bitfield_bit_offset; 194360784Sdim if (bitfield_end > *type_bit_size) { 195360784Sdim uint64_t overhang_bytes = 196360784Sdim (bitfield_end - *type_bit_size + 7) / 8; 197360784Sdim m_value.GetScalar() += overhang_bytes; 198360784Sdim m_bitfield_bit_offset -= overhang_bytes * 8; 199360784Sdim } 200360784Sdim } 201360784Sdim } 202314564Sdim } 203314564Sdim } break; 204314564Sdim 205314564Sdim case Value::eValueTypeScalar: 206314564Sdim // try to extract the child value from the parent's scalar value 207314564Sdim { 208314564Sdim Scalar scalar(m_value.GetScalar()); 209314564Sdim if (m_bitfield_bit_size) 210314564Sdim scalar.ExtractBitfield(m_bitfield_bit_size, 211314564Sdim m_bitfield_bit_offset); 212314564Sdim else 213314564Sdim scalar.ExtractBitfield(8 * m_byte_size, 8 * m_byte_offset); 214314564Sdim m_value.GetScalar() = scalar; 215314564Sdim } 216314564Sdim break; 217314564Sdim default: 218314564Sdim m_error.SetErrorString("parent has invalid value."); 219314564Sdim break; 220254721Semaste } 221314564Sdim } 222314564Sdim 223314564Sdim if (m_error.Success()) { 224314564Sdim const bool thread_and_frame_only_if_stopped = true; 225314564Sdim ExecutionContext exe_ctx( 226314564Sdim GetExecutionContextRef().Lock(thread_and_frame_only_if_stopped)); 227314564Sdim if (GetCompilerType().GetTypeInfo() & lldb::eTypeHasValue) { 228344779Sdim Value &value = is_instance_ptr_base ? m_parent->GetValue() : m_value; 229344779Sdim m_error = 230360784Sdim value.GetValueAsData(&exe_ctx, m_data, GetModule().get()); 231314564Sdim } else { 232314564Sdim m_error.Clear(); // No value so nothing to read... 233314564Sdim } 234314564Sdim } 235314564Sdim 236314564Sdim } else { 237314564Sdim m_error.SetErrorStringWithFormat("parent failed to evaluate: %s", 238314564Sdim parent->GetError().AsCString()); 239254721Semaste } 240314564Sdim } else { 241314564Sdim m_error.SetErrorString("ValueObjectChild has a NULL parent ValueObject."); 242314564Sdim } 243314564Sdim 244314564Sdim return m_error.Success(); 245254721Semaste} 246254721Semaste 247314564Sdimbool ValueObjectChild::IsInScope() { 248314564Sdim ValueObject *root(GetRoot()); 249314564Sdim if (root) 250314564Sdim return root->IsInScope(); 251314564Sdim return false; 252254721Semaste} 253