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/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
ValueObjectDynamicValue(ValueObject & parent,lldb::DynamicValueType use_dynamic)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
~ValueObjectDynamicValue()39 ValueObjectDynamicValue::~ValueObjectDynamicValue() {
40 m_owning_valobj_sp.reset();
41 }
42
GetCompilerTypeImpl()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
GetTypeName()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
GetTypeImpl()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
GetQualifiedTypeName()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
GetDisplayTypeName()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
CalculateNumChildren(uint32_t max)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
GetByteSize()101 llvm::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);
106 } else
107 return m_parent->GetByteSize();
108 }
109
GetValueType() const110 lldb::ValueType ValueObjectDynamicValue::GetValueType() const {
111 return m_parent->GetValueType();
112 }
113
UpdateValue()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.SetCompilerType(m_dynamic_type_info.GetCompilerType());
241
242 m_value.SetValueType(value_type);
243
244 if (has_changed_type && log)
245 LLDB_LOGF(log, "[%s %p] has a new dynamic type %s", GetName().GetCString(),
246 static_cast<void *>(this), GetTypeName().GetCString());
247
248 if (m_address.IsValid() && m_dynamic_type_info) {
249 // The variable value is in the Scalar value inside the m_value. We can
250 // point our m_data right to it.
251 m_error = m_value.GetValueAsData(&exe_ctx, m_data, GetModule().get());
252 if (m_error.Success()) {
253 if (!CanProvideValue()) {
254 // this value object represents an aggregate type whose children have
255 // values, but this object does not. So we say we are changed if our
256 // location has changed.
257 SetValueDidChange(m_value.GetValueType() != old_value.GetValueType() ||
258 m_value.GetScalar() != old_value.GetScalar());
259 }
260
261 SetValueIsValid(true);
262 return true;
263 }
264 }
265
266 // We get here if we've failed above...
267 SetValueIsValid(false);
268 return false;
269 }
270
IsInScope()271 bool ValueObjectDynamicValue::IsInScope() { return m_parent->IsInScope(); }
272
SetValueFromCString(const char * value_str,Status & error)273 bool ValueObjectDynamicValue::SetValueFromCString(const char *value_str,
274 Status &error) {
275 if (!UpdateValueIfNeeded(false)) {
276 error.SetErrorString("unable to read value");
277 return false;
278 }
279
280 uint64_t my_value = GetValueAsUnsigned(UINT64_MAX);
281 uint64_t parent_value = m_parent->GetValueAsUnsigned(UINT64_MAX);
282
283 if (my_value == UINT64_MAX || parent_value == UINT64_MAX) {
284 error.SetErrorString("unable to read value");
285 return false;
286 }
287
288 // if we are at an offset from our parent, in order to set ourselves
289 // correctly we would need to change the new value so that it refers to the
290 // correct dynamic type. we choose not to deal with that - if anything more
291 // than a value overwrite is required, you should be using the expression
292 // parser instead of the value editing facility
293 if (my_value != parent_value) {
294 // but NULL'ing out a value should always be allowed
295 if (strcmp(value_str, "0")) {
296 error.SetErrorString(
297 "unable to modify dynamic value, use 'expression' command");
298 return false;
299 }
300 }
301
302 bool ret_val = m_parent->SetValueFromCString(value_str, error);
303 SetNeedsUpdate();
304 return ret_val;
305 }
306
SetData(DataExtractor & data,Status & error)307 bool ValueObjectDynamicValue::SetData(DataExtractor &data, Status &error) {
308 if (!UpdateValueIfNeeded(false)) {
309 error.SetErrorString("unable to read value");
310 return false;
311 }
312
313 uint64_t my_value = GetValueAsUnsigned(UINT64_MAX);
314 uint64_t parent_value = m_parent->GetValueAsUnsigned(UINT64_MAX);
315
316 if (my_value == UINT64_MAX || parent_value == UINT64_MAX) {
317 error.SetErrorString("unable to read value");
318 return false;
319 }
320
321 // if we are at an offset from our parent, in order to set ourselves
322 // correctly we would need to change the new value so that it refers to the
323 // correct dynamic type. we choose not to deal with that - if anything more
324 // than a value overwrite is required, you should be using the expression
325 // parser instead of the value editing facility
326 if (my_value != parent_value) {
327 // but NULL'ing out a value should always be allowed
328 lldb::offset_t offset = 0;
329
330 if (data.GetAddress(&offset) != 0) {
331 error.SetErrorString(
332 "unable to modify dynamic value, use 'expression' command");
333 return false;
334 }
335 }
336
337 bool ret_val = m_parent->SetData(data, error);
338 SetNeedsUpdate();
339 return ret_val;
340 }
341
SetPreferredDisplayLanguage(lldb::LanguageType lang)342 void ValueObjectDynamicValue::SetPreferredDisplayLanguage(
343 lldb::LanguageType lang) {
344 this->ValueObject::SetPreferredDisplayLanguage(lang);
345 if (m_parent)
346 m_parent->SetPreferredDisplayLanguage(lang);
347 }
348
GetPreferredDisplayLanguage()349 lldb::LanguageType ValueObjectDynamicValue::GetPreferredDisplayLanguage() {
350 if (m_preferred_display_language == lldb::eLanguageTypeUnknown) {
351 if (m_parent)
352 return m_parent->GetPreferredDisplayLanguage();
353 return lldb::eLanguageTypeUnknown;
354 } else
355 return m_preferred_display_language;
356 }
357
IsSyntheticChildrenGenerated()358 bool ValueObjectDynamicValue::IsSyntheticChildrenGenerated() {
359 if (m_parent)
360 return m_parent->IsSyntheticChildrenGenerated();
361 return false;
362 }
363
SetSyntheticChildrenGenerated(bool b)364 void ValueObjectDynamicValue::SetSyntheticChildrenGenerated(bool b) {
365 if (m_parent)
366 m_parent->SetSyntheticChildrenGenerated(b);
367 this->ValueObject::SetSyntheticChildrenGenerated(b);
368 }
369
GetDeclaration(Declaration & decl)370 bool ValueObjectDynamicValue::GetDeclaration(Declaration &decl) {
371 if (m_parent)
372 return m_parent->GetDeclaration(decl);
373
374 return ValueObject::GetDeclaration(decl);
375 }
376
GetLanguageFlags()377 uint64_t ValueObjectDynamicValue::GetLanguageFlags() {
378 if (m_parent)
379 return m_parent->GetLanguageFlags();
380 return this->ValueObject::GetLanguageFlags();
381 }
382
SetLanguageFlags(uint64_t flags)383 void ValueObjectDynamicValue::SetLanguageFlags(uint64_t flags) {
384 if (m_parent)
385 m_parent->SetLanguageFlags(flags);
386 else
387 this->ValueObject::SetLanguageFlags(flags);
388 }
389