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
ValueObjectDynamicValue(ValueObject & parent,lldb::DynamicValueType use_dynamic)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
GetCompilerTypeImpl()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
GetTypeName()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
GetTypeImpl()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
GetQualifiedTypeName()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
GetDisplayTypeName()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
CalculateNumChildren(uint32_t max)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
GetByteSize()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
GetValueType() const107 lldb::ValueType ValueObjectDynamicValue::GetValueType() const {
108 return m_parent->GetValueType();
109 }
110
UpdateValue()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
IsInScope()268 bool ValueObjectDynamicValue::IsInScope() { return m_parent->IsInScope(); }
269
SetValueFromCString(const char * value_str,Status & error)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
SetData(DataExtractor & data,Status & error)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
SetPreferredDisplayLanguage(lldb::LanguageType lang)339 void ValueObjectDynamicValue::SetPreferredDisplayLanguage(
340 lldb::LanguageType lang) {
341 this->ValueObject::SetPreferredDisplayLanguage(lang);
342 if (m_parent)
343 m_parent->SetPreferredDisplayLanguage(lang);
344 }
345
GetPreferredDisplayLanguage()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
IsSyntheticChildrenGenerated()355 bool ValueObjectDynamicValue::IsSyntheticChildrenGenerated() {
356 if (m_parent)
357 return m_parent->IsSyntheticChildrenGenerated();
358 return false;
359 }
360
SetSyntheticChildrenGenerated(bool b)361 void ValueObjectDynamicValue::SetSyntheticChildrenGenerated(bool b) {
362 if (m_parent)
363 m_parent->SetSyntheticChildrenGenerated(b);
364 this->ValueObject::SetSyntheticChildrenGenerated(b);
365 }
366
GetDeclaration(Declaration & decl)367 bool ValueObjectDynamicValue::GetDeclaration(Declaration &decl) {
368 if (m_parent)
369 return m_parent->GetDeclaration(decl);
370
371 return ValueObject::GetDeclaration(decl);
372 }
373
GetLanguageFlags()374 uint64_t ValueObjectDynamicValue::GetLanguageFlags() {
375 if (m_parent)
376 return m_parent->GetLanguageFlags();
377 return this->ValueObject::GetLanguageFlags();
378 }
379
SetLanguageFlags(uint64_t flags)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