1 //===-- ValueObjectDynamicValue.cpp ---------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "lldb/ValueObject/ValueObjectDynamicValue.h"
10 #include "lldb/Core/Value.h"
11 #include "lldb/Symbol/CompilerType.h"
12 #include "lldb/Symbol/Type.h"
13 #include "lldb/Target/ExecutionContext.h"
14 #include "lldb/Target/LanguageRuntime.h"
15 #include "lldb/Target/Process.h"
16 #include "lldb/Target/Target.h"
17 #include "lldb/Utility/DataExtractor.h"
18 #include "lldb/Utility/LLDBLog.h"
19 #include "lldb/Utility/Log.h"
20 #include "lldb/Utility/Scalar.h"
21 #include "lldb/Utility/Status.h"
22 #include "lldb/ValueObject/ValueObject.h"
23 #include "lldb/lldb-types.h"
27 namespace lldb_private
{
31 using namespace lldb_private
;
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());
40 CompilerType
ValueObjectDynamicValue::GetCompilerTypeImpl() {
41 const bool success
= UpdateValueIfNeeded(false);
43 if (m_dynamic_type_info
.HasType())
44 return m_value
.GetCompilerType();
46 return m_parent
->GetCompilerType();
48 return m_parent
->GetCompilerType();
51 ConstString
ValueObjectDynamicValue::GetTypeName() {
52 const bool success
= UpdateValueIfNeeded(false);
54 if (m_dynamic_type_info
.HasName())
55 return m_dynamic_type_info
.GetName();
57 return m_parent
->GetTypeName();
60 TypeImpl
ValueObjectDynamicValue::GetTypeImpl() {
61 const bool success
= UpdateValueIfNeeded(false);
62 if (success
&& m_type_impl
.IsValid()) {
65 return m_parent
->GetTypeImpl();
68 ConstString
ValueObjectDynamicValue::GetQualifiedTypeName() {
69 const bool success
= UpdateValueIfNeeded(false);
71 if (m_dynamic_type_info
.HasName())
72 return m_dynamic_type_info
.GetName();
74 return m_parent
->GetQualifiedTypeName();
77 ConstString
ValueObjectDynamicValue::GetDisplayTypeName() {
78 const bool success
= UpdateValueIfNeeded(false);
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();
85 return m_parent
->GetDisplayTypeName();
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
);
95 return children_count
;
96 return *children_count
<= max
? *children_count
: max
;
98 return m_parent
->GetNumChildren(max
);
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
);
107 return m_parent
->GetByteSize();
110 lldb::ValueType
ValueObjectDynamicValue::GetValueType() const {
111 return m_parent
->GetValueType();
114 bool ValueObjectDynamicValue::UpdateValue() {
115 SetValueIsValid(false);
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().Clone();
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();
132 ExecutionContext
exe_ctx(GetExecutionContextRef());
133 Target
*target
= exe_ctx
.GetTargetPtr();
135 m_data
.SetByteOrder(target
->GetArchitecture().GetByteOrder());
136 m_data
.SetAddressByteSize(target
->GetArchitecture().GetAddressByteSize());
139 // First make sure our Type and/or Address haven't changed:
140 Process
*process
= exe_ctx
.GetProcessPtr();
144 TypeAndOrName class_type_or_name
;
145 Address dynamic_address
;
146 bool found_dynamic_type
= false;
147 Value::ValueType value_type
;
149 LanguageRuntime
*runtime
= nullptr;
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
,
161 if (found_dynamic_type
)
162 // Set the operative `runtime` for later use in this function.
163 runtime
= preferred_runtime
;
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
,
171 runtime
= process
->GetLanguageRuntime(lldb::eLanguageTypeC_plus_plus
);
173 found_dynamic_type
= runtime
->GetDynamicTypeAndAddress(
174 *m_parent
, m_use_dynamic
, class_type_or_name
, dynamic_address
,
177 if (!found_dynamic_type
) {
178 runtime
= process
->GetLanguageRuntime(lldb::eLanguageTypeObjC
);
180 found_dynamic_type
= runtime
->GetDynamicTypeAndAddress(
181 *m_parent
, m_use_dynamic
, class_type_or_name
, dynamic_address
,
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...
189 m_update_point
.SetUpdated();
191 if (runtime
&& found_dynamic_type
) {
192 if (class_type_or_name
.HasType()) {
194 TypeImpl(m_parent
->GetCompilerType(),
195 runtime
->FixUpDynamicType(class_type_or_name
, *m_parent
)
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
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
= Status::FromErrorString("no dynamic type found");
219 Value
old_value(m_value
);
221 Log
*log
= GetLog(LLDBLog::Types
);
223 bool has_changed_type
= false;
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;
235 if (has_changed_type
)
236 ClearDynamicTypeInformation();
238 if (!m_address
.IsValid() || m_address
!= dynamic_address
) {
239 if (m_address
.IsValid())
240 SetValueDidChange(true);
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
;
250 m_dynamic_type_info
=
251 runtime
->FixUpDynamicType(m_dynamic_type_info
, *m_parent
);
253 m_value
.SetCompilerType(m_dynamic_type_info
.GetCompilerType());
255 m_value
.SetValueType(value_type
);
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());
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());
274 SetValueIsValid(true);
279 // We get here if we've failed above...
280 SetValueIsValid(false);
284 bool ValueObjectDynamicValue::IsInScope() { return m_parent
->IsInScope(); }
286 bool ValueObjectDynamicValue::SetValueFromCString(const char *value_str
,
288 if (!UpdateValueIfNeeded(false)) {
289 error
= Status::FromErrorString("unable to read value");
293 uint64_t my_value
= GetValueAsUnsigned(UINT64_MAX
);
294 uint64_t parent_value
= m_parent
->GetValueAsUnsigned(UINT64_MAX
);
296 if (my_value
== UINT64_MAX
|| parent_value
== UINT64_MAX
) {
297 error
= Status::FromErrorString("unable to read value");
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
= Status::FromErrorString(
310 "unable to modify dynamic value, use 'expression' command");
315 bool ret_val
= m_parent
->SetValueFromCString(value_str
, error
);
320 bool ValueObjectDynamicValue::SetData(DataExtractor
&data
, Status
&error
) {
321 if (!UpdateValueIfNeeded(false)) {
322 error
= Status::FromErrorString("unable to read value");
326 uint64_t my_value
= GetValueAsUnsigned(UINT64_MAX
);
327 uint64_t parent_value
= m_parent
->GetValueAsUnsigned(UINT64_MAX
);
329 if (my_value
== UINT64_MAX
|| parent_value
== UINT64_MAX
) {
330 error
= Status::FromErrorString("unable to read value");
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;
343 if (data
.GetAddress(&offset
) != 0) {
344 error
= Status::FromErrorString(
345 "unable to modify dynamic value, use 'expression' command");
350 bool ret_val
= m_parent
->SetData(data
, error
);
355 void ValueObjectDynamicValue::SetPreferredDisplayLanguage(
356 lldb::LanguageType lang
) {
357 this->ValueObject::SetPreferredDisplayLanguage(lang
);
359 m_parent
->SetPreferredDisplayLanguage(lang
);
362 lldb::LanguageType
ValueObjectDynamicValue::GetPreferredDisplayLanguage() {
363 if (m_preferred_display_language
== lldb::eLanguageTypeUnknown
) {
365 return m_parent
->GetPreferredDisplayLanguage();
366 return lldb::eLanguageTypeUnknown
;
368 return m_preferred_display_language
;
371 bool ValueObjectDynamicValue::IsSyntheticChildrenGenerated() {
373 return m_parent
->IsSyntheticChildrenGenerated();
377 void ValueObjectDynamicValue::SetSyntheticChildrenGenerated(bool b
) {
379 m_parent
->SetSyntheticChildrenGenerated(b
);
380 this->ValueObject::SetSyntheticChildrenGenerated(b
);
383 bool ValueObjectDynamicValue::GetDeclaration(Declaration
&decl
) {
385 return m_parent
->GetDeclaration(decl
);
387 return ValueObject::GetDeclaration(decl
);
390 uint64_t ValueObjectDynamicValue::GetLanguageFlags() {
392 return m_parent
->GetLanguageFlags();
393 return this->ValueObject::GetLanguageFlags();
396 void ValueObjectDynamicValue::SetLanguageFlags(uint64_t flags
) {
398 m_parent
->SetLanguageFlags(flags
);
400 this->ValueObject::SetLanguageFlags(flags
);