1 //===-- ValueObjectDynamicValue.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/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/Log.h" 20 #include "lldb/Utility/Logging.h" 21 #include "lldb/Utility/Scalar.h" 22 #include "lldb/Utility/Status.h" 23 #include "lldb/lldb-types.h" 24 25 #include <string.h> 26 namespace lldb_private { 27 class Declaration; 28 } 29 30 using namespace lldb_private; 31 32 ValueObjectDynamicValue::ValueObjectDynamicValue( 33 ValueObject &parent, lldb::DynamicValueType use_dynamic) 34 : ValueObject(parent), m_address(), m_dynamic_type_info(), 35 m_use_dynamic(use_dynamic) { 36 SetName(parent.GetName()); 37 } 38 39 ValueObjectDynamicValue::~ValueObjectDynamicValue() { 40 m_owning_valobj_sp.reset(); 41 } 42 43 CompilerType ValueObjectDynamicValue::GetCompilerTypeImpl() { 44 const bool success = UpdateValueIfNeeded(false); 45 if (success) { 46 if (m_dynamic_type_info.HasType()) 47 return m_value.GetCompilerType(); 48 else 49 return m_parent->GetCompilerType(); 50 } 51 return m_parent->GetCompilerType(); 52 } 53 54 ConstString ValueObjectDynamicValue::GetTypeName() { 55 const bool success = UpdateValueIfNeeded(false); 56 if (success) { 57 if (m_dynamic_type_info.HasName()) 58 return m_dynamic_type_info.GetName(); 59 } 60 return m_parent->GetTypeName(); 61 } 62 63 TypeImpl ValueObjectDynamicValue::GetTypeImpl() { 64 const bool success = UpdateValueIfNeeded(false); 65 if (success && m_type_impl.IsValid()) { 66 return m_type_impl; 67 } 68 return m_parent->GetTypeImpl(); 69 } 70 71 ConstString ValueObjectDynamicValue::GetQualifiedTypeName() { 72 const bool success = UpdateValueIfNeeded(false); 73 if (success) { 74 if (m_dynamic_type_info.HasName()) 75 return m_dynamic_type_info.GetName(); 76 } 77 return m_parent->GetQualifiedTypeName(); 78 } 79 80 ConstString ValueObjectDynamicValue::GetDisplayTypeName() { 81 const bool success = UpdateValueIfNeeded(false); 82 if (success) { 83 if (m_dynamic_type_info.HasType()) 84 return GetCompilerType().GetDisplayTypeName(); 85 if (m_dynamic_type_info.HasName()) 86 return m_dynamic_type_info.GetName(); 87 } 88 return m_parent->GetDisplayTypeName(); 89 } 90 91 size_t ValueObjectDynamicValue::CalculateNumChildren(uint32_t max) { 92 const bool success = UpdateValueIfNeeded(false); 93 if (success && m_dynamic_type_info.HasType()) { 94 ExecutionContext exe_ctx(GetExecutionContextRef()); 95 auto children_count = GetCompilerType().GetNumChildren(true, &exe_ctx); 96 return children_count <= max ? children_count : max; 97 } else 98 return m_parent->GetNumChildren(max); 99 } 100 101 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 (runtime) 156 found_dynamic_type = runtime->GetDynamicTypeAndAddress( 157 *m_parent, m_use_dynamic, class_type_or_name, dynamic_address, 158 value_type); 159 } else { 160 runtime = process->GetLanguageRuntime(lldb::eLanguageTypeC_plus_plus); 161 if (runtime) 162 found_dynamic_type = runtime->GetDynamicTypeAndAddress( 163 *m_parent, m_use_dynamic, class_type_or_name, dynamic_address, 164 value_type); 165 166 if (!found_dynamic_type) { 167 runtime = process->GetLanguageRuntime(lldb::eLanguageTypeObjC); 168 if (runtime) 169 found_dynamic_type = runtime->GetDynamicTypeAndAddress( 170 *m_parent, m_use_dynamic, class_type_or_name, dynamic_address, 171 value_type); 172 } 173 } 174 175 // Getting the dynamic value may have run the program a bit, and so marked us 176 // as needing updating, but we really don't... 177 178 m_update_point.SetUpdated(); 179 180 if (runtime && found_dynamic_type) { 181 if (class_type_or_name.HasType()) { 182 m_type_impl = 183 TypeImpl(m_parent->GetCompilerType(), 184 runtime->FixUpDynamicType(class_type_or_name, *m_parent) 185 .GetCompilerType()); 186 } else { 187 m_type_impl.Clear(); 188 } 189 } else { 190 m_type_impl.Clear(); 191 } 192 193 // If we don't have a dynamic type, then make ourselves just a echo of our 194 // parent. Or we could return false, and make ourselves an echo of our 195 // parent? 196 if (!found_dynamic_type) { 197 if (m_dynamic_type_info) 198 SetValueDidChange(true); 199 ClearDynamicTypeInformation(); 200 m_dynamic_type_info.Clear(); 201 m_value = m_parent->GetValue(); 202 m_error = m_value.GetValueAsData(&exe_ctx, m_data, GetModule().get()); 203 return m_error.Success(); 204 } 205 206 Value old_value(m_value); 207 208 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES)); 209 210 bool has_changed_type = false; 211 212 if (!m_dynamic_type_info) { 213 m_dynamic_type_info = class_type_or_name; 214 has_changed_type = true; 215 } else if (class_type_or_name != m_dynamic_type_info) { 216 // We are another type, we need to tear down our children... 217 m_dynamic_type_info = class_type_or_name; 218 SetValueDidChange(true); 219 has_changed_type = true; 220 } 221 222 if (has_changed_type) 223 ClearDynamicTypeInformation(); 224 225 if (!m_address.IsValid() || m_address != dynamic_address) { 226 if (m_address.IsValid()) 227 SetValueDidChange(true); 228 229 // We've moved, so we should be fine... 230 m_address = dynamic_address; 231 lldb::TargetSP target_sp(GetTargetSP()); 232 lldb::addr_t load_address = m_address.GetLoadAddress(target_sp.get()); 233 m_value.GetScalar() = load_address; 234 } 235 236 if (runtime) 237 m_dynamic_type_info = 238 runtime->FixUpDynamicType(m_dynamic_type_info, *m_parent); 239 240 // m_value.SetContext (Value::eContextTypeClangType, corrected_type); 241 m_value.SetCompilerType(m_dynamic_type_info.GetCompilerType()); 242 243 m_value.SetValueType(value_type); 244 245 if (has_changed_type && log) 246 LLDB_LOGF(log, "[%s %p] has a new dynamic type %s", GetName().GetCString(), 247 static_cast<void *>(this), GetTypeName().GetCString()); 248 249 if (m_address.IsValid() && m_dynamic_type_info) { 250 // The variable value is in the Scalar value inside the m_value. We can 251 // point our m_data right to it. 252 m_error = m_value.GetValueAsData(&exe_ctx, m_data, GetModule().get()); 253 if (m_error.Success()) { 254 if (!CanProvideValue()) { 255 // this value object represents an aggregate type whose children have 256 // values, but this object does not. So we say we are changed if our 257 // location has changed. 258 SetValueDidChange(m_value.GetValueType() != old_value.GetValueType() || 259 m_value.GetScalar() != old_value.GetScalar()); 260 } 261 262 SetValueIsValid(true); 263 return true; 264 } 265 } 266 267 // We get here if we've failed above... 268 SetValueIsValid(false); 269 return false; 270 } 271 272 bool ValueObjectDynamicValue::IsInScope() { return m_parent->IsInScope(); } 273 274 bool ValueObjectDynamicValue::SetValueFromCString(const char *value_str, 275 Status &error) { 276 if (!UpdateValueIfNeeded(false)) { 277 error.SetErrorString("unable to read value"); 278 return false; 279 } 280 281 uint64_t my_value = GetValueAsUnsigned(UINT64_MAX); 282 uint64_t parent_value = m_parent->GetValueAsUnsigned(UINT64_MAX); 283 284 if (my_value == UINT64_MAX || parent_value == UINT64_MAX) { 285 error.SetErrorString("unable to read value"); 286 return false; 287 } 288 289 // if we are at an offset from our parent, in order to set ourselves 290 // correctly we would need to change the new value so that it refers to the 291 // correct dynamic type. we choose not to deal with that - if anything more 292 // than a value overwrite is required, you should be using the expression 293 // parser instead of the value editing facility 294 if (my_value != parent_value) { 295 // but NULL'ing out a value should always be allowed 296 if (strcmp(value_str, "0")) { 297 error.SetErrorString( 298 "unable to modify dynamic value, use 'expression' command"); 299 return false; 300 } 301 } 302 303 bool ret_val = m_parent->SetValueFromCString(value_str, error); 304 SetNeedsUpdate(); 305 return ret_val; 306 } 307 308 bool ValueObjectDynamicValue::SetData(DataExtractor &data, Status &error) { 309 if (!UpdateValueIfNeeded(false)) { 310 error.SetErrorString("unable to read value"); 311 return false; 312 } 313 314 uint64_t my_value = GetValueAsUnsigned(UINT64_MAX); 315 uint64_t parent_value = m_parent->GetValueAsUnsigned(UINT64_MAX); 316 317 if (my_value == UINT64_MAX || parent_value == UINT64_MAX) { 318 error.SetErrorString("unable to read value"); 319 return false; 320 } 321 322 // if we are at an offset from our parent, in order to set ourselves 323 // correctly we would need to change the new value so that it refers to the 324 // correct dynamic type. we choose not to deal with that - if anything more 325 // than a value overwrite is required, you should be using the expression 326 // parser instead of the value editing facility 327 if (my_value != parent_value) { 328 // but NULL'ing out a value should always be allowed 329 lldb::offset_t offset = 0; 330 331 if (data.GetPointer(&offset) != 0) { 332 error.SetErrorString( 333 "unable to modify dynamic value, use 'expression' command"); 334 return false; 335 } 336 } 337 338 bool ret_val = m_parent->SetData(data, error); 339 SetNeedsUpdate(); 340 return ret_val; 341 } 342 343 void ValueObjectDynamicValue::SetPreferredDisplayLanguage( 344 lldb::LanguageType lang) { 345 this->ValueObject::SetPreferredDisplayLanguage(lang); 346 if (m_parent) 347 m_parent->SetPreferredDisplayLanguage(lang); 348 } 349 350 lldb::LanguageType ValueObjectDynamicValue::GetPreferredDisplayLanguage() { 351 if (m_preferred_display_language == lldb::eLanguageTypeUnknown) { 352 if (m_parent) 353 return m_parent->GetPreferredDisplayLanguage(); 354 return lldb::eLanguageTypeUnknown; 355 } else 356 return m_preferred_display_language; 357 } 358 359 bool ValueObjectDynamicValue::IsSyntheticChildrenGenerated() { 360 if (m_parent) 361 return m_parent->IsSyntheticChildrenGenerated(); 362 return false; 363 } 364 365 void ValueObjectDynamicValue::SetSyntheticChildrenGenerated(bool b) { 366 if (m_parent) 367 m_parent->SetSyntheticChildrenGenerated(b); 368 this->ValueObject::SetSyntheticChildrenGenerated(b); 369 } 370 371 bool ValueObjectDynamicValue::GetDeclaration(Declaration &decl) { 372 if (m_parent) 373 return m_parent->GetDeclaration(decl); 374 375 return ValueObject::GetDeclaration(decl); 376 } 377 378 uint64_t ValueObjectDynamicValue::GetLanguageFlags() { 379 if (m_parent) 380 return m_parent->GetLanguageFlags(); 381 return this->ValueObject::GetLanguageFlags(); 382 } 383 384 void ValueObjectDynamicValue::SetLanguageFlags(uint64_t flags) { 385 if (m_parent) 386 m_parent->SetLanguageFlags(flags); 387 else 388 this->ValueObject::SetLanguageFlags(flags); 389 } 390