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