xref: /openbsd-src/gnu/llvm/lldb/source/Core/ValueObjectDynamicValue.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
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