1//===-- ValueObjectChild.cpp ------------------------------------*- C++ -*-===// 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 "lldb/Core/ValueObjectChild.h" 10 11#include "lldb/Core/Value.h" 12#include "lldb/Symbol/CompilerType.h" 13#include "lldb/Target/ExecutionContext.h" 14#include "lldb/Target/Process.h" 15#include "lldb/Utility/Flags.h" 16#include "lldb/Utility/Scalar.h" 17#include "lldb/Utility/Status.h" 18#include "lldb/lldb-forward.h" 19 20#include <functional> 21#include <memory> 22#include <vector> 23 24#include <stdio.h> 25#include <string.h> 26 27using namespace lldb_private; 28 29ValueObjectChild::ValueObjectChild( 30 ValueObject &parent, const CompilerType &compiler_type, 31 ConstString name, uint64_t byte_size, int32_t byte_offset, 32 uint32_t bitfield_bit_size, uint32_t bitfield_bit_offset, 33 bool is_base_class, bool is_deref_of_parent, 34 AddressType child_ptr_or_ref_addr_type, uint64_t language_flags) 35 : ValueObject(parent), m_compiler_type(compiler_type), 36 m_byte_size(byte_size), m_byte_offset(byte_offset), 37 m_bitfield_bit_size(bitfield_bit_size), 38 m_bitfield_bit_offset(bitfield_bit_offset), 39 m_is_base_class(is_base_class), m_is_deref_of_parent(is_deref_of_parent), 40 m_can_update_with_invalid_exe_ctx() { 41 m_name = name; 42 SetAddressTypeOfChildren(child_ptr_or_ref_addr_type); 43 SetLanguageFlags(language_flags); 44} 45 46ValueObjectChild::~ValueObjectChild() {} 47 48lldb::ValueType ValueObjectChild::GetValueType() const { 49 return m_parent->GetValueType(); 50} 51 52size_t ValueObjectChild::CalculateNumChildren(uint32_t max) { 53 ExecutionContext exe_ctx(GetExecutionContextRef()); 54 auto children_count = GetCompilerType().GetNumChildren(true, &exe_ctx); 55 return children_count <= max ? children_count : max; 56} 57 58static void AdjustForBitfieldness(ConstString &name, 59 uint8_t bitfield_bit_size) { 60 if (name && bitfield_bit_size) { 61 const char *compiler_type_name = name.AsCString(); 62 if (compiler_type_name) { 63 std::vector<char> bitfield_type_name(strlen(compiler_type_name) + 32, 0); 64 ::snprintf(&bitfield_type_name.front(), bitfield_type_name.size(), 65 "%s:%u", compiler_type_name, bitfield_bit_size); 66 name.SetCString(&bitfield_type_name.front()); 67 } 68 } 69} 70 71ConstString ValueObjectChild::GetTypeName() { 72 if (m_type_name.IsEmpty()) { 73 m_type_name = GetCompilerType().GetConstTypeName(); 74 AdjustForBitfieldness(m_type_name, m_bitfield_bit_size); 75 } 76 return m_type_name; 77} 78 79ConstString ValueObjectChild::GetQualifiedTypeName() { 80 ConstString qualified_name = GetCompilerType().GetConstTypeName(); 81 AdjustForBitfieldness(qualified_name, m_bitfield_bit_size); 82 return qualified_name; 83} 84 85ConstString ValueObjectChild::GetDisplayTypeName() { 86 ConstString display_name = GetCompilerType().GetDisplayTypeName(); 87 AdjustForBitfieldness(display_name, m_bitfield_bit_size); 88 return display_name; 89} 90 91LazyBool ValueObjectChild::CanUpdateWithInvalidExecutionContext() { 92 if (m_can_update_with_invalid_exe_ctx.hasValue()) 93 return m_can_update_with_invalid_exe_ctx.getValue(); 94 if (m_parent) { 95 ValueObject *opinionated_parent = 96 m_parent->FollowParentChain([](ValueObject *valobj) -> bool { 97 return (valobj->CanUpdateWithInvalidExecutionContext() == 98 eLazyBoolCalculate); 99 }); 100 if (opinionated_parent) 101 return (m_can_update_with_invalid_exe_ctx = 102 opinionated_parent->CanUpdateWithInvalidExecutionContext()) 103 .getValue(); 104 } 105 return (m_can_update_with_invalid_exe_ctx = 106 this->ValueObject::CanUpdateWithInvalidExecutionContext()) 107 .getValue(); 108} 109 110bool ValueObjectChild::UpdateValue() { 111 m_error.Clear(); 112 SetValueIsValid(false); 113 ValueObject *parent = m_parent; 114 if (parent) { 115 if (parent->UpdateValueIfNeeded(false)) { 116 m_value.SetCompilerType(GetCompilerType()); 117 118 CompilerType parent_type(parent->GetCompilerType()); 119 // Copy the parent scalar value and the scalar value type 120 m_value.GetScalar() = parent->GetValue().GetScalar(); 121 Value::ValueType value_type = parent->GetValue().GetValueType(); 122 m_value.SetValueType(value_type); 123 124 Flags parent_type_flags(parent_type.GetTypeInfo()); 125 const bool is_instance_ptr_base = 126 ((m_is_base_class) && 127 (parent_type_flags.AnySet(lldb::eTypeInstanceIsPointer))); 128 129 if (parent->GetCompilerType().ShouldTreatScalarValueAsAddress()) { 130 lldb::addr_t addr = parent->GetPointerValue(); 131 m_value.GetScalar() = addr; 132 133 if (addr == LLDB_INVALID_ADDRESS) { 134 m_error.SetErrorString("parent address is invalid."); 135 } else if (addr == 0) { 136 m_error.SetErrorString("parent is NULL"); 137 } else { 138 m_value.GetScalar() += m_byte_offset; 139 AddressType addr_type = parent->GetAddressTypeOfChildren(); 140 141 switch (addr_type) { 142 case eAddressTypeFile: { 143 lldb::ProcessSP process_sp(GetProcessSP()); 144 if (process_sp && process_sp->IsAlive()) 145 m_value.SetValueType(Value::eValueTypeLoadAddress); 146 else 147 m_value.SetValueType(Value::eValueTypeFileAddress); 148 } break; 149 case eAddressTypeLoad: 150 m_value.SetValueType(is_instance_ptr_base 151 ? Value::eValueTypeScalar 152 : Value::eValueTypeLoadAddress); 153 break; 154 case eAddressTypeHost: 155 m_value.SetValueType(Value::eValueTypeHostAddress); 156 break; 157 case eAddressTypeInvalid: 158 // TODO: does this make sense? 159 m_value.SetValueType(Value::eValueTypeScalar); 160 break; 161 } 162 } 163 } else { 164 switch (value_type) { 165 case Value::eValueTypeLoadAddress: 166 case Value::eValueTypeFileAddress: 167 case Value::eValueTypeHostAddress: { 168 lldb::addr_t addr = 169 m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS); 170 if (addr == LLDB_INVALID_ADDRESS) { 171 m_error.SetErrorString("parent address is invalid."); 172 } else if (addr == 0) { 173 m_error.SetErrorString("parent is NULL"); 174 } else { 175 // Set this object's scalar value to the address of its value by 176 // adding its byte offset to the parent address 177 m_value.GetScalar() += GetByteOffset(); 178 179 // If a bitfield doesn't fit into the child_byte_size'd 180 // window at child_byte_offset, move the window forward 181 // until it fits. The problem here is that Value has no 182 // notion of bitfields and thus the Value's DataExtractor 183 // is sized like the bitfields CompilerType; a sequence of 184 // bitfields, however, can be larger than their underlying 185 // type. 186 if (m_bitfield_bit_offset) { 187 const bool thread_and_frame_only_if_stopped = true; 188 ExecutionContext exe_ctx(GetExecutionContextRef().Lock( 189 thread_and_frame_only_if_stopped)); 190 if (auto type_bit_size = GetCompilerType().GetBitSize( 191 exe_ctx.GetBestExecutionContextScope())) { 192 uint64_t bitfield_end = 193 m_bitfield_bit_size + m_bitfield_bit_offset; 194 if (bitfield_end > *type_bit_size) { 195 uint64_t overhang_bytes = 196 (bitfield_end - *type_bit_size + 7) / 8; 197 m_value.GetScalar() += overhang_bytes; 198 m_bitfield_bit_offset -= overhang_bytes * 8; 199 } 200 } 201 } 202 } 203 } break; 204 205 case Value::eValueTypeScalar: 206 // try to extract the child value from the parent's scalar value 207 { 208 Scalar scalar(m_value.GetScalar()); 209 if (m_bitfield_bit_size) 210 scalar.ExtractBitfield(m_bitfield_bit_size, 211 m_bitfield_bit_offset); 212 else 213 scalar.ExtractBitfield(8 * m_byte_size, 8 * m_byte_offset); 214 m_value.GetScalar() = scalar; 215 } 216 break; 217 default: 218 m_error.SetErrorString("parent has invalid value."); 219 break; 220 } 221 } 222 223 if (m_error.Success()) { 224 const bool thread_and_frame_only_if_stopped = true; 225 ExecutionContext exe_ctx( 226 GetExecutionContextRef().Lock(thread_and_frame_only_if_stopped)); 227 if (GetCompilerType().GetTypeInfo() & lldb::eTypeHasValue) { 228 Value &value = is_instance_ptr_base ? m_parent->GetValue() : m_value; 229 m_error = 230 value.GetValueAsData(&exe_ctx, m_data, GetModule().get()); 231 } else { 232 m_error.Clear(); // No value so nothing to read... 233 } 234 } 235 236 } else { 237 m_error.SetErrorStringWithFormat("parent failed to evaluate: %s", 238 parent->GetError().AsCString()); 239 } 240 } else { 241 m_error.SetErrorString("ValueObjectChild has a NULL parent ValueObject."); 242 } 243 244 return m_error.Success(); 245} 246 247bool ValueObjectChild::IsInScope() { 248 ValueObject *root(GetRoot()); 249 if (root) 250 return root->IsInScope(); 251 return false; 252} 253