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 (runtime) 153 found_dynamic_type = runtime->GetDynamicTypeAndAddress( 154 *m_parent, m_use_dynamic, class_type_or_name, dynamic_address, 155 value_type); 156 } else { 157 runtime = process->GetLanguageRuntime(lldb::eLanguageTypeC_plus_plus); 158 if (runtime) 159 found_dynamic_type = runtime->GetDynamicTypeAndAddress( 160 *m_parent, m_use_dynamic, class_type_or_name, dynamic_address, 161 value_type); 162 163 if (!found_dynamic_type) { 164 runtime = process->GetLanguageRuntime(lldb::eLanguageTypeObjC); 165 if (runtime) 166 found_dynamic_type = runtime->GetDynamicTypeAndAddress( 167 *m_parent, m_use_dynamic, class_type_or_name, dynamic_address, 168 value_type); 169 } 170 } 171 172 // Getting the dynamic value may have run the program a bit, and so marked us 173 // as needing updating, but we really don't... 174 175 m_update_point.SetUpdated(); 176 177 if (runtime && found_dynamic_type) { 178 if (class_type_or_name.HasType()) { 179 m_type_impl = 180 TypeImpl(m_parent->GetCompilerType(), 181 runtime->FixUpDynamicType(class_type_or_name, *m_parent) 182 .GetCompilerType()); 183 } else { 184 m_type_impl.Clear(); 185 } 186 } else { 187 m_type_impl.Clear(); 188 } 189 190 // If we don't have a dynamic type, then make ourselves just a echo of our 191 // parent. Or we could return false, and make ourselves an echo of our 192 // parent? 193 if (!found_dynamic_type) { 194 if (m_dynamic_type_info) 195 SetValueDidChange(true); 196 ClearDynamicTypeInformation(); 197 m_dynamic_type_info.Clear(); 198 m_value = m_parent->GetValue(); 199 m_error = m_value.GetValueAsData(&exe_ctx, m_data, GetModule().get()); 200 return m_error.Success(); 201 } 202 203 Value old_value(m_value); 204 205 Log *log = GetLog(LLDBLog::Types); 206 207 bool has_changed_type = false; 208 209 if (!m_dynamic_type_info) { 210 m_dynamic_type_info = class_type_or_name; 211 has_changed_type = true; 212 } else if (class_type_or_name != m_dynamic_type_info) { 213 // We are another type, we need to tear down our children... 214 m_dynamic_type_info = class_type_or_name; 215 SetValueDidChange(true); 216 has_changed_type = true; 217 } 218 219 if (has_changed_type) 220 ClearDynamicTypeInformation(); 221 222 if (!m_address.IsValid() || m_address != dynamic_address) { 223 if (m_address.IsValid()) 224 SetValueDidChange(true); 225 226 // We've moved, so we should be fine... 227 m_address = dynamic_address; 228 lldb::TargetSP target_sp(GetTargetSP()); 229 lldb::addr_t load_address = m_address.GetLoadAddress(target_sp.get()); 230 m_value.GetScalar() = load_address; 231 } 232 233 if (runtime) 234 m_dynamic_type_info = 235 runtime->FixUpDynamicType(m_dynamic_type_info, *m_parent); 236 237 m_value.SetCompilerType(m_dynamic_type_info.GetCompilerType()); 238 239 m_value.SetValueType(value_type); 240 241 if (has_changed_type && log) 242 LLDB_LOGF(log, "[%s %p] has a new dynamic type %s", GetName().GetCString(), 243 static_cast<void *>(this), GetTypeName().GetCString()); 244 245 if (m_address.IsValid() && m_dynamic_type_info) { 246 // The variable value is in the Scalar value inside the m_value. We can 247 // point our m_data right to it. 248 m_error = m_value.GetValueAsData(&exe_ctx, m_data, GetModule().get()); 249 if (m_error.Success()) { 250 if (!CanProvideValue()) { 251 // this value object represents an aggregate type whose children have 252 // values, but this object does not. So we say we are changed if our 253 // location has changed. 254 SetValueDidChange(m_value.GetValueType() != old_value.GetValueType() || 255 m_value.GetScalar() != old_value.GetScalar()); 256 } 257 258 SetValueIsValid(true); 259 return true; 260 } 261 } 262 263 // We get here if we've failed above... 264 SetValueIsValid(false); 265 return false; 266 } 267 268 bool ValueObjectDynamicValue::IsInScope() { return m_parent->IsInScope(); } 269 270 bool ValueObjectDynamicValue::SetValueFromCString(const char *value_str, 271 Status &error) { 272 if (!UpdateValueIfNeeded(false)) { 273 error.SetErrorString("unable to read value"); 274 return false; 275 } 276 277 uint64_t my_value = GetValueAsUnsigned(UINT64_MAX); 278 uint64_t parent_value = m_parent->GetValueAsUnsigned(UINT64_MAX); 279 280 if (my_value == UINT64_MAX || parent_value == UINT64_MAX) { 281 error.SetErrorString("unable to read value"); 282 return false; 283 } 284 285 // if we are at an offset from our parent, in order to set ourselves 286 // correctly we would need to change the new value so that it refers to the 287 // correct dynamic type. we choose not to deal with that - if anything more 288 // than a value overwrite is required, you should be using the expression 289 // parser instead of the value editing facility 290 if (my_value != parent_value) { 291 // but NULL'ing out a value should always be allowed 292 if (strcmp(value_str, "0")) { 293 error.SetErrorString( 294 "unable to modify dynamic value, use 'expression' command"); 295 return false; 296 } 297 } 298 299 bool ret_val = m_parent->SetValueFromCString(value_str, error); 300 SetNeedsUpdate(); 301 return ret_val; 302 } 303 304 bool ValueObjectDynamicValue::SetData(DataExtractor &data, Status &error) { 305 if (!UpdateValueIfNeeded(false)) { 306 error.SetErrorString("unable to read value"); 307 return false; 308 } 309 310 uint64_t my_value = GetValueAsUnsigned(UINT64_MAX); 311 uint64_t parent_value = m_parent->GetValueAsUnsigned(UINT64_MAX); 312 313 if (my_value == UINT64_MAX || parent_value == UINT64_MAX) { 314 error.SetErrorString("unable to read value"); 315 return false; 316 } 317 318 // if we are at an offset from our parent, in order to set ourselves 319 // correctly we would need to change the new value so that it refers to the 320 // correct dynamic type. we choose not to deal with that - if anything more 321 // than a value overwrite is required, you should be using the expression 322 // parser instead of the value editing facility 323 if (my_value != parent_value) { 324 // but NULL'ing out a value should always be allowed 325 lldb::offset_t offset = 0; 326 327 if (data.GetAddress(&offset) != 0) { 328 error.SetErrorString( 329 "unable to modify dynamic value, use 'expression' command"); 330 return false; 331 } 332 } 333 334 bool ret_val = m_parent->SetData(data, error); 335 SetNeedsUpdate(); 336 return ret_val; 337 } 338 339 void ValueObjectDynamicValue::SetPreferredDisplayLanguage( 340 lldb::LanguageType lang) { 341 this->ValueObject::SetPreferredDisplayLanguage(lang); 342 if (m_parent) 343 m_parent->SetPreferredDisplayLanguage(lang); 344 } 345 346 lldb::LanguageType ValueObjectDynamicValue::GetPreferredDisplayLanguage() { 347 if (m_preferred_display_language == lldb::eLanguageTypeUnknown) { 348 if (m_parent) 349 return m_parent->GetPreferredDisplayLanguage(); 350 return lldb::eLanguageTypeUnknown; 351 } else 352 return m_preferred_display_language; 353 } 354 355 bool ValueObjectDynamicValue::IsSyntheticChildrenGenerated() { 356 if (m_parent) 357 return m_parent->IsSyntheticChildrenGenerated(); 358 return false; 359 } 360 361 void ValueObjectDynamicValue::SetSyntheticChildrenGenerated(bool b) { 362 if (m_parent) 363 m_parent->SetSyntheticChildrenGenerated(b); 364 this->ValueObject::SetSyntheticChildrenGenerated(b); 365 } 366 367 bool ValueObjectDynamicValue::GetDeclaration(Declaration &decl) { 368 if (m_parent) 369 return m_parent->GetDeclaration(decl); 370 371 return ValueObject::GetDeclaration(decl); 372 } 373 374 uint64_t ValueObjectDynamicValue::GetLanguageFlags() { 375 if (m_parent) 376 return m_parent->GetLanguageFlags(); 377 return this->ValueObject::GetLanguageFlags(); 378 } 379 380 void ValueObjectDynamicValue::SetLanguageFlags(uint64_t flags) { 381 if (m_parent) 382 m_parent->SetLanguageFlags(flags); 383 else 384 this->ValueObject::SetLanguageFlags(flags); 385 } 386