1 //===-- ValueObjectDynamicValue.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 "lldb/Core/ValueObjectDynamicValue.h" 10 #include "lldb/Core/Value.h" 11 #include "lldb/Core/ValueObject.h" 12 #include "lldb/Symbol/CompilerType.h" 13 #include "lldb/Symbol/Type.h" 14 #include "lldb/Target/ExecutionContext.h" 15 #include "lldb/Target/LanguageRuntime.h" 16 #include "lldb/Target/Process.h" 17 #include "lldb/Target/Target.h" 18 #include "lldb/Utility/DataExtractor.h" 19 #include "lldb/Utility/LLDBLog.h" 20 #include "lldb/Utility/Log.h" 21 #include "lldb/Utility/Scalar.h" 22 #include "lldb/Utility/Status.h" 23 #include "lldb/lldb-types.h" 24 25 #include <cstring> 26 #include <optional> 27 namespace lldb_private { 28 class Declaration; 29 } 30 31 using namespace lldb_private; 32 33 ValueObjectDynamicValue::ValueObjectDynamicValue( 34 ValueObject &parent, lldb::DynamicValueType use_dynamic) 35 : ValueObject(parent), m_address(), m_dynamic_type_info(), 36 m_use_dynamic(use_dynamic) { 37 SetName(parent.GetName()); 38 } 39 40 CompilerType ValueObjectDynamicValue::GetCompilerTypeImpl() { 41 const bool success = UpdateValueIfNeeded(false); 42 if (success) { 43 if (m_dynamic_type_info.HasType()) 44 return m_value.GetCompilerType(); 45 else 46 return m_parent->GetCompilerType(); 47 } 48 return m_parent->GetCompilerType(); 49 } 50 51 ConstString ValueObjectDynamicValue::GetTypeName() { 52 const bool success = UpdateValueIfNeeded(false); 53 if (success) { 54 if (m_dynamic_type_info.HasName()) 55 return m_dynamic_type_info.GetName(); 56 } 57 return m_parent->GetTypeName(); 58 } 59 60 TypeImpl ValueObjectDynamicValue::GetTypeImpl() { 61 const bool success = UpdateValueIfNeeded(false); 62 if (success && m_type_impl.IsValid()) { 63 return m_type_impl; 64 } 65 return m_parent->GetTypeImpl(); 66 } 67 68 ConstString ValueObjectDynamicValue::GetQualifiedTypeName() { 69 const bool success = UpdateValueIfNeeded(false); 70 if (success) { 71 if (m_dynamic_type_info.HasName()) 72 return m_dynamic_type_info.GetName(); 73 } 74 return m_parent->GetQualifiedTypeName(); 75 } 76 77 ConstString ValueObjectDynamicValue::GetDisplayTypeName() { 78 const bool success = UpdateValueIfNeeded(false); 79 if (success) { 80 if (m_dynamic_type_info.HasType()) 81 return GetCompilerType().GetDisplayTypeName(); 82 if (m_dynamic_type_info.HasName()) 83 return m_dynamic_type_info.GetName(); 84 } 85 return m_parent->GetDisplayTypeName(); 86 } 87 88 size_t ValueObjectDynamicValue::CalculateNumChildren(uint32_t max) { 89 const bool success = UpdateValueIfNeeded(false); 90 if (success && m_dynamic_type_info.HasType()) { 91 ExecutionContext exe_ctx(GetExecutionContextRef()); 92 auto children_count = GetCompilerType().GetNumChildren(true, &exe_ctx); 93 return children_count <= max ? children_count : max; 94 } else 95 return m_parent->GetNumChildren(max); 96 } 97 98 std::optional<uint64_t> ValueObjectDynamicValue::GetByteSize() { 99 const bool success = UpdateValueIfNeeded(false); 100 if (success && m_dynamic_type_info.HasType()) { 101 ExecutionContext exe_ctx(GetExecutionContextRef()); 102 return m_value.GetValueByteSize(nullptr, &exe_ctx); 103 } else 104 return m_parent->GetByteSize(); 105 } 106 107 lldb::ValueType ValueObjectDynamicValue::GetValueType() const { 108 return m_parent->GetValueType(); 109 } 110 111 bool ValueObjectDynamicValue::UpdateValue() { 112 SetValueIsValid(false); 113 m_error.Clear(); 114 115 if (!m_parent->UpdateValueIfNeeded(false)) { 116 // The dynamic value failed to get an error, pass the error along 117 if (m_error.Success() && m_parent->GetError().Fail()) 118 m_error = m_parent->GetError(); 119 return false; 120 } 121 122 // Setting our type_sp to NULL will route everything back through our parent 123 // which is equivalent to not using dynamic values. 124 if (m_use_dynamic == lldb::eNoDynamicValues) { 125 m_dynamic_type_info.Clear(); 126 return true; 127 } 128 129 ExecutionContext exe_ctx(GetExecutionContextRef()); 130 Target *target = exe_ctx.GetTargetPtr(); 131 if (target) { 132 m_data.SetByteOrder(target->GetArchitecture().GetByteOrder()); 133 m_data.SetAddressByteSize(target->GetArchitecture().GetAddressByteSize()); 134 } 135 136 // First make sure our Type and/or Address haven't changed: 137 Process *process = exe_ctx.GetProcessPtr(); 138 if (!process) 139 return false; 140 141 TypeAndOrName class_type_or_name; 142 Address dynamic_address; 143 bool found_dynamic_type = false; 144 Value::ValueType value_type; 145 146 LanguageRuntime *runtime = nullptr; 147 148 lldb::LanguageType known_type = m_parent->GetObjectRuntimeLanguage(); 149 if (known_type != lldb::eLanguageTypeUnknown && 150 known_type != lldb::eLanguageTypeC) { 151 runtime = process->GetLanguageRuntime(known_type); 152 if (auto *preferred_runtime = 153 runtime->GetPreferredLanguageRuntime(*m_parent)) { 154 // Try the preferred runtime first. 155 found_dynamic_type = preferred_runtime->GetDynamicTypeAndAddress( 156 *m_parent, m_use_dynamic, class_type_or_name, dynamic_address, 157 value_type); 158 if (found_dynamic_type) 159 // Set the operative `runtime` for later use in this function. 160 runtime = preferred_runtime; 161 } 162 if (!found_dynamic_type) 163 // Fallback to the runtime for `known_type`. 164 found_dynamic_type = runtime->GetDynamicTypeAndAddress( 165 *m_parent, m_use_dynamic, class_type_or_name, dynamic_address, 166 value_type); 167 } else { 168 runtime = process->GetLanguageRuntime(lldb::eLanguageTypeC_plus_plus); 169 if (runtime) 170 found_dynamic_type = runtime->GetDynamicTypeAndAddress( 171 *m_parent, m_use_dynamic, class_type_or_name, dynamic_address, 172 value_type); 173 174 if (!found_dynamic_type) { 175 runtime = process->GetLanguageRuntime(lldb::eLanguageTypeObjC); 176 if (runtime) 177 found_dynamic_type = runtime->GetDynamicTypeAndAddress( 178 *m_parent, m_use_dynamic, class_type_or_name, dynamic_address, 179 value_type); 180 } 181 } 182 183 // Getting the dynamic value may have run the program a bit, and so marked us 184 // as needing updating, but we really don't... 185 186 m_update_point.SetUpdated(); 187 188 if (runtime && found_dynamic_type) { 189 if (class_type_or_name.HasType()) { 190 m_type_impl = 191 TypeImpl(m_parent->GetCompilerType(), 192 runtime->FixUpDynamicType(class_type_or_name, *m_parent) 193 .GetCompilerType()); 194 } else { 195 m_type_impl.Clear(); 196 } 197 } else { 198 m_type_impl.Clear(); 199 } 200 201 // If we don't have a dynamic type, set ourselves to be invalid and return 202 // false. We used to try to produce a dynamic ValueObject that behaved "like" 203 // its parent, but that failed for ValueObjectConstResult, which is too 204 // complex a beast to try to emulate. If we return an invalid ValueObject, 205 // clients will end up getting the static value instead, which behaves 206 // correctly. 207 if (!found_dynamic_type) { 208 if (m_dynamic_type_info) 209 SetValueDidChange(true); 210 ClearDynamicTypeInformation(); 211 m_dynamic_type_info.Clear(); 212 m_error.SetErrorString("no dynamic type found"); 213 return false; 214 } 215 216 Value old_value(m_value); 217 218 Log *log = GetLog(LLDBLog::Types); 219 220 bool has_changed_type = false; 221 222 if (!m_dynamic_type_info) { 223 m_dynamic_type_info = class_type_or_name; 224 has_changed_type = true; 225 } else if (class_type_or_name != m_dynamic_type_info) { 226 // We are another type, we need to tear down our children... 227 m_dynamic_type_info = class_type_or_name; 228 SetValueDidChange(true); 229 has_changed_type = true; 230 } 231 232 if (has_changed_type) 233 ClearDynamicTypeInformation(); 234 235 if (!m_address.IsValid() || m_address != dynamic_address) { 236 if (m_address.IsValid()) 237 SetValueDidChange(true); 238 239 // We've moved, so we should be fine... 240 m_address = dynamic_address; 241 lldb::TargetSP target_sp(GetTargetSP()); 242 lldb::addr_t load_address = m_address.GetLoadAddress(target_sp.get()); 243 m_value.GetScalar() = load_address; 244 } 245 246 if (runtime) 247 m_dynamic_type_info = 248 runtime->FixUpDynamicType(m_dynamic_type_info, *m_parent); 249 250 m_value.SetCompilerType(m_dynamic_type_info.GetCompilerType()); 251 252 m_value.SetValueType(value_type); 253 254 if (has_changed_type && log) 255 LLDB_LOGF(log, "[%s %p] has a new dynamic type %s", GetName().GetCString(), 256 static_cast<void *>(this), GetTypeName().GetCString()); 257 258 if (m_address.IsValid() && m_dynamic_type_info) { 259 // The variable value is in the Scalar value inside the m_value. We can 260 // point our m_data right to it. 261 m_error = m_value.GetValueAsData(&exe_ctx, m_data, GetModule().get()); 262 if (m_error.Success()) { 263 if (!CanProvideValue()) { 264 // this value object represents an aggregate type whose children have 265 // values, but this object does not. So we say we are changed if our 266 // location has changed. 267 SetValueDidChange(m_value.GetValueType() != old_value.GetValueType() || 268 m_value.GetScalar() != old_value.GetScalar()); 269 } 270 271 SetValueIsValid(true); 272 return true; 273 } 274 } 275 276 // We get here if we've failed above... 277 SetValueIsValid(false); 278 return false; 279 } 280 281 bool ValueObjectDynamicValue::IsInScope() { return m_parent->IsInScope(); } 282 283 bool ValueObjectDynamicValue::SetValueFromCString(const char *value_str, 284 Status &error) { 285 if (!UpdateValueIfNeeded(false)) { 286 error.SetErrorString("unable to read value"); 287 return false; 288 } 289 290 uint64_t my_value = GetValueAsUnsigned(UINT64_MAX); 291 uint64_t parent_value = m_parent->GetValueAsUnsigned(UINT64_MAX); 292 293 if (my_value == UINT64_MAX || parent_value == UINT64_MAX) { 294 error.SetErrorString("unable to read value"); 295 return false; 296 } 297 298 // if we are at an offset from our parent, in order to set ourselves 299 // correctly we would need to change the new value so that it refers to the 300 // correct dynamic type. we choose not to deal with that - if anything more 301 // than a value overwrite is required, you should be using the expression 302 // parser instead of the value editing facility 303 if (my_value != parent_value) { 304 // but NULL'ing out a value should always be allowed 305 if (strcmp(value_str, "0")) { 306 error.SetErrorString( 307 "unable to modify dynamic value, use 'expression' command"); 308 return false; 309 } 310 } 311 312 bool ret_val = m_parent->SetValueFromCString(value_str, error); 313 SetNeedsUpdate(); 314 return ret_val; 315 } 316 317 bool ValueObjectDynamicValue::SetData(DataExtractor &data, Status &error) { 318 if (!UpdateValueIfNeeded(false)) { 319 error.SetErrorString("unable to read value"); 320 return false; 321 } 322 323 uint64_t my_value = GetValueAsUnsigned(UINT64_MAX); 324 uint64_t parent_value = m_parent->GetValueAsUnsigned(UINT64_MAX); 325 326 if (my_value == UINT64_MAX || parent_value == UINT64_MAX) { 327 error.SetErrorString("unable to read value"); 328 return false; 329 } 330 331 // if we are at an offset from our parent, in order to set ourselves 332 // correctly we would need to change the new value so that it refers to the 333 // correct dynamic type. we choose not to deal with that - if anything more 334 // than a value overwrite is required, you should be using the expression 335 // parser instead of the value editing facility 336 if (my_value != parent_value) { 337 // but NULL'ing out a value should always be allowed 338 lldb::offset_t offset = 0; 339 340 if (data.GetAddress(&offset) != 0) { 341 error.SetErrorString( 342 "unable to modify dynamic value, use 'expression' command"); 343 return false; 344 } 345 } 346 347 bool ret_val = m_parent->SetData(data, error); 348 SetNeedsUpdate(); 349 return ret_val; 350 } 351 352 void ValueObjectDynamicValue::SetPreferredDisplayLanguage( 353 lldb::LanguageType lang) { 354 this->ValueObject::SetPreferredDisplayLanguage(lang); 355 if (m_parent) 356 m_parent->SetPreferredDisplayLanguage(lang); 357 } 358 359 lldb::LanguageType ValueObjectDynamicValue::GetPreferredDisplayLanguage() { 360 if (m_preferred_display_language == lldb::eLanguageTypeUnknown) { 361 if (m_parent) 362 return m_parent->GetPreferredDisplayLanguage(); 363 return lldb::eLanguageTypeUnknown; 364 } else 365 return m_preferred_display_language; 366 } 367 368 bool ValueObjectDynamicValue::IsSyntheticChildrenGenerated() { 369 if (m_parent) 370 return m_parent->IsSyntheticChildrenGenerated(); 371 return false; 372 } 373 374 void ValueObjectDynamicValue::SetSyntheticChildrenGenerated(bool b) { 375 if (m_parent) 376 m_parent->SetSyntheticChildrenGenerated(b); 377 this->ValueObject::SetSyntheticChildrenGenerated(b); 378 } 379 380 bool ValueObjectDynamicValue::GetDeclaration(Declaration &decl) { 381 if (m_parent) 382 return m_parent->GetDeclaration(decl); 383 384 return ValueObject::GetDeclaration(decl); 385 } 386 387 uint64_t ValueObjectDynamicValue::GetLanguageFlags() { 388 if (m_parent) 389 return m_parent->GetLanguageFlags(); 390 return this->ValueObject::GetLanguageFlags(); 391 } 392 393 void ValueObjectDynamicValue::SetLanguageFlags(uint64_t flags) { 394 if (m_parent) 395 m_parent->SetLanguageFlags(flags); 396 else 397 this->ValueObject::SetLanguageFlags(flags); 398 } 399