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

source code of lldb/source/Core/ValueObjectDynamicValue.cpp