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