1321369Sdim//===-- ValueObjectDynamicValue.cpp ------------------------------*- C++-*-===//
2254721Semaste//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6254721Semaste//
7254721Semaste//===----------------------------------------------------------------------===//
8254721Semaste
9254721Semaste#include "lldb/Core/ValueObjectDynamicValue.h"
10254721Semaste#include "lldb/Core/Value.h"
11254721Semaste#include "lldb/Core/ValueObject.h"
12296417Sdim#include "lldb/Symbol/CompilerType.h"
13254721Semaste#include "lldb/Symbol/Type.h"
14254721Semaste#include "lldb/Target/ExecutionContext.h"
15254721Semaste#include "lldb/Target/LanguageRuntime.h"
16254721Semaste#include "lldb/Target/Process.h"
17254721Semaste#include "lldb/Target/Target.h"
18344779Sdim#include "lldb/Utility/DataExtractor.h"
19321369Sdim#include "lldb/Utility/Log.h"
20344779Sdim#include "lldb/Utility/Logging.h"
21344779Sdim#include "lldb/Utility/Scalar.h"
22344779Sdim#include "lldb/Utility/Status.h"
23344779Sdim#include "lldb/lldb-types.h"
24254721Semaste
25344779Sdim#include <string.h>
26321369Sdimnamespace lldb_private {
27321369Sdimclass Declaration;
28321369Sdim}
29321369Sdim
30254721Semasteusing namespace lldb_private;
31254721Semaste
32314564SdimValueObjectDynamicValue::ValueObjectDynamicValue(
33314564Sdim    ValueObject &parent, lldb::DynamicValueType use_dynamic)
34314564Sdim    : ValueObject(parent), m_address(), m_dynamic_type_info(),
35314564Sdim      m_use_dynamic(use_dynamic) {
36314564Sdim  SetName(parent.GetName());
37254721Semaste}
38254721Semaste
39314564SdimValueObjectDynamicValue::~ValueObjectDynamicValue() {
40314564Sdim  m_owning_valobj_sp.reset();
41254721Semaste}
42254721Semaste
43314564SdimCompilerType ValueObjectDynamicValue::GetCompilerTypeImpl() {
44314564Sdim  const bool success = UpdateValueIfNeeded(false);
45314564Sdim  if (success) {
46314564Sdim    if (m_dynamic_type_info.HasType())
47314564Sdim      return m_value.GetCompilerType();
48314564Sdim    else
49314564Sdim      return m_parent->GetCompilerType();
50314564Sdim  }
51314564Sdim  return m_parent->GetCompilerType();
52254721Semaste}
53254721Semaste
54314564SdimConstString ValueObjectDynamicValue::GetTypeName() {
55314564Sdim  const bool success = UpdateValueIfNeeded(false);
56314564Sdim  if (success) {
57314564Sdim    if (m_dynamic_type_info.HasName())
58314564Sdim      return m_dynamic_type_info.GetName();
59314564Sdim  }
60314564Sdim  return m_parent->GetTypeName();
61254721Semaste}
62254721Semaste
63314564SdimTypeImpl ValueObjectDynamicValue::GetTypeImpl() {
64314564Sdim  const bool success = UpdateValueIfNeeded(false);
65314564Sdim  if (success && m_type_impl.IsValid()) {
66314564Sdim    return m_type_impl;
67314564Sdim  }
68314564Sdim  return m_parent->GetTypeImpl();
69258054Semaste}
70258054Semaste
71314564SdimConstString ValueObjectDynamicValue::GetQualifiedTypeName() {
72314564Sdim  const bool success = UpdateValueIfNeeded(false);
73314564Sdim  if (success) {
74314564Sdim    if (m_dynamic_type_info.HasName())
75314564Sdim      return m_dynamic_type_info.GetName();
76314564Sdim  }
77314564Sdim  return m_parent->GetQualifiedTypeName();
78276479Sdim}
79276479Sdim
80314564SdimConstString ValueObjectDynamicValue::GetDisplayTypeName() {
81314564Sdim  const bool success = UpdateValueIfNeeded(false);
82314564Sdim  if (success) {
83314564Sdim    if (m_dynamic_type_info.HasType())
84314564Sdim      return GetCompilerType().GetDisplayTypeName();
85314564Sdim    if (m_dynamic_type_info.HasName())
86314564Sdim      return m_dynamic_type_info.GetName();
87314564Sdim  }
88314564Sdim  return m_parent->GetDisplayTypeName();
89254721Semaste}
90254721Semaste
91314564Sdimsize_t ValueObjectDynamicValue::CalculateNumChildren(uint32_t max) {
92314564Sdim  const bool success = UpdateValueIfNeeded(false);
93314564Sdim  if (success && m_dynamic_type_info.HasType()) {
94344779Sdim    ExecutionContext exe_ctx(GetExecutionContextRef());
95344779Sdim    auto children_count = GetCompilerType().GetNumChildren(true, &exe_ctx);
96314564Sdim    return children_count <= max ? children_count : max;
97314564Sdim  } else
98314564Sdim    return m_parent->GetNumChildren(max);
99254721Semaste}
100254721Semaste
101314564Sdimuint64_t ValueObjectDynamicValue::GetByteSize() {
102314564Sdim  const bool success = UpdateValueIfNeeded(false);
103314564Sdim  if (success && m_dynamic_type_info.HasType()) {
104314564Sdim    ExecutionContext exe_ctx(GetExecutionContextRef());
105314564Sdim    return m_value.GetValueByteSize(nullptr, &exe_ctx);
106314564Sdim  } else
107314564Sdim    return m_parent->GetByteSize();
108254721Semaste}
109254721Semaste
110314564Sdimlldb::ValueType ValueObjectDynamicValue::GetValueType() const {
111314564Sdim  return m_parent->GetValueType();
112254721Semaste}
113254721Semaste
114314564Sdimbool ValueObjectDynamicValue::UpdateValue() {
115314564Sdim  SetValueIsValid(false);
116314564Sdim  m_error.Clear();
117254721Semaste
118314564Sdim  if (!m_parent->UpdateValueIfNeeded(false)) {
119314564Sdim    // The dynamic value failed to get an error, pass the error along
120314564Sdim    if (m_error.Success() && m_parent->GetError().Fail())
121314564Sdim      m_error = m_parent->GetError();
122314564Sdim    return false;
123314564Sdim  }
124276479Sdim
125341825Sdim  // Setting our type_sp to NULL will route everything back through our parent
126341825Sdim  // which is equivalent to not using dynamic values.
127314564Sdim  if (m_use_dynamic == lldb::eNoDynamicValues) {
128314564Sdim    m_dynamic_type_info.Clear();
129314564Sdim    return true;
130314564Sdim  }
131276479Sdim
132314564Sdim  ExecutionContext exe_ctx(GetExecutionContextRef());
133314564Sdim  Target *target = exe_ctx.GetTargetPtr();
134314564Sdim  if (target) {
135314564Sdim    m_data.SetByteOrder(target->GetArchitecture().GetByteOrder());
136314564Sdim    m_data.SetAddressByteSize(target->GetArchitecture().GetAddressByteSize());
137314564Sdim  }
138276479Sdim
139314564Sdim  // First make sure our Type and/or Address haven't changed:
140314564Sdim  Process *process = exe_ctx.GetProcessPtr();
141314564Sdim  if (!process)
142314564Sdim    return false;
143276479Sdim
144314564Sdim  TypeAndOrName class_type_or_name;
145314564Sdim  Address dynamic_address;
146314564Sdim  bool found_dynamic_type = false;
147314564Sdim  Value::ValueType value_type;
148276479Sdim
149314564Sdim  LanguageRuntime *runtime = nullptr;
150276479Sdim
151314564Sdim  lldb::LanguageType known_type = m_parent->GetObjectRuntimeLanguage();
152314564Sdim  if (known_type != lldb::eLanguageTypeUnknown &&
153314564Sdim      known_type != lldb::eLanguageTypeC) {
154314564Sdim    runtime = process->GetLanguageRuntime(known_type);
155314564Sdim    if (runtime)
156314564Sdim      found_dynamic_type = runtime->GetDynamicTypeAndAddress(
157314564Sdim          *m_parent, m_use_dynamic, class_type_or_name, dynamic_address,
158314564Sdim          value_type);
159314564Sdim  } else {
160314564Sdim    runtime = process->GetLanguageRuntime(lldb::eLanguageTypeC_plus_plus);
161314564Sdim    if (runtime)
162314564Sdim      found_dynamic_type = runtime->GetDynamicTypeAndAddress(
163314564Sdim          *m_parent, m_use_dynamic, class_type_or_name, dynamic_address,
164314564Sdim          value_type);
165314564Sdim
166314564Sdim    if (!found_dynamic_type) {
167314564Sdim      runtime = process->GetLanguageRuntime(lldb::eLanguageTypeObjC);
168314564Sdim      if (runtime)
169314564Sdim        found_dynamic_type = runtime->GetDynamicTypeAndAddress(
170314564Sdim            *m_parent, m_use_dynamic, class_type_or_name, dynamic_address,
171314564Sdim            value_type);
172254721Semaste    }
173314564Sdim  }
174276479Sdim
175314564Sdim  // Getting the dynamic value may have run the program a bit, and so marked us
176341825Sdim  // as needing updating, but we really don't...
177276479Sdim
178314564Sdim  m_update_point.SetUpdated();
179258054Semaste
180314564Sdim  if (runtime && found_dynamic_type) {
181314564Sdim    if (class_type_or_name.HasType()) {
182314564Sdim      m_type_impl =
183314564Sdim          TypeImpl(m_parent->GetCompilerType(),
184314564Sdim                   runtime->FixUpDynamicType(class_type_or_name, *m_parent)
185314564Sdim                       .GetCompilerType());
186314564Sdim    } else {
187314564Sdim      m_type_impl.Clear();
188258054Semaste    }
189314564Sdim  } else {
190314564Sdim    m_type_impl.Clear();
191314564Sdim  }
192276479Sdim
193314564Sdim  // If we don't have a dynamic type, then make ourselves just a echo of our
194341825Sdim  // parent. Or we could return false, and make ourselves an echo of our
195341825Sdim  // parent?
196314564Sdim  if (!found_dynamic_type) {
197314564Sdim    if (m_dynamic_type_info)
198314564Sdim      SetValueDidChange(true);
199314564Sdim    ClearDynamicTypeInformation();
200314564Sdim    m_dynamic_type_info.Clear();
201314564Sdim    m_value = m_parent->GetValue();
202360784Sdim    m_error = m_value.GetValueAsData(&exe_ctx, m_data, GetModule().get());
203314564Sdim    return m_error.Success();
204314564Sdim  }
205276479Sdim
206314564Sdim  Value old_value(m_value);
207254721Semaste
208314564Sdim  Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_TYPES));
209276479Sdim
210314564Sdim  bool has_changed_type = false;
211276479Sdim
212314564Sdim  if (!m_dynamic_type_info) {
213314564Sdim    m_dynamic_type_info = class_type_or_name;
214314564Sdim    has_changed_type = true;
215314564Sdim  } else if (class_type_or_name != m_dynamic_type_info) {
216314564Sdim    // We are another type, we need to tear down our children...
217314564Sdim    m_dynamic_type_info = class_type_or_name;
218314564Sdim    SetValueDidChange(true);
219314564Sdim    has_changed_type = true;
220314564Sdim  }
221276479Sdim
222314564Sdim  if (has_changed_type)
223314564Sdim    ClearDynamicTypeInformation();
224276479Sdim
225314564Sdim  if (!m_address.IsValid() || m_address != dynamic_address) {
226314564Sdim    if (m_address.IsValid())
227314564Sdim      SetValueDidChange(true);
228276479Sdim
229314564Sdim    // We've moved, so we should be fine...
230314564Sdim    m_address = dynamic_address;
231314564Sdim    lldb::TargetSP target_sp(GetTargetSP());
232314564Sdim    lldb::addr_t load_address = m_address.GetLoadAddress(target_sp.get());
233314564Sdim    m_value.GetScalar() = load_address;
234314564Sdim  }
235276479Sdim
236314564Sdim  if (runtime)
237314564Sdim    m_dynamic_type_info =
238314564Sdim        runtime->FixUpDynamicType(m_dynamic_type_info, *m_parent);
239276479Sdim
240314564Sdim  // m_value.SetContext (Value::eContextTypeClangType, corrected_type);
241314564Sdim  m_value.SetCompilerType(m_dynamic_type_info.GetCompilerType());
242276479Sdim
243314564Sdim  m_value.SetValueType(value_type);
244254721Semaste
245314564Sdim  if (has_changed_type && log)
246360784Sdim    LLDB_LOGF(log, "[%s %p] has a new dynamic type %s", GetName().GetCString(),
247360784Sdim              static_cast<void *>(this), GetTypeName().GetCString());
248276479Sdim
249314564Sdim  if (m_address.IsValid() && m_dynamic_type_info) {
250341825Sdim    // The variable value is in the Scalar value inside the m_value. We can
251341825Sdim    // point our m_data right to it.
252360784Sdim    m_error = m_value.GetValueAsData(&exe_ctx, m_data, GetModule().get());
253314564Sdim    if (m_error.Success()) {
254314564Sdim      if (!CanProvideValue()) {
255341825Sdim        // this value object represents an aggregate type whose children have
256341825Sdim        // values, but this object does not. So we say we are changed if our
257341825Sdim        // location has changed.
258314564Sdim        SetValueDidChange(m_value.GetValueType() != old_value.GetValueType() ||
259314564Sdim                          m_value.GetScalar() != old_value.GetScalar());
260314564Sdim      }
261254721Semaste
262314564Sdim      SetValueIsValid(true);
263314564Sdim      return true;
264254721Semaste    }
265314564Sdim  }
266276479Sdim
267314564Sdim  // We get here if we've failed above...
268314564Sdim  SetValueIsValid(false);
269314564Sdim  return false;
270254721Semaste}
271254721Semaste
272314564Sdimbool ValueObjectDynamicValue::IsInScope() { return m_parent->IsInScope(); }
273254721Semaste
274314564Sdimbool ValueObjectDynamicValue::SetValueFromCString(const char *value_str,
275321369Sdim                                                  Status &error) {
276314564Sdim  if (!UpdateValueIfNeeded(false)) {
277314564Sdim    error.SetErrorString("unable to read value");
278314564Sdim    return false;
279314564Sdim  }
280254721Semaste
281314564Sdim  uint64_t my_value = GetValueAsUnsigned(UINT64_MAX);
282314564Sdim  uint64_t parent_value = m_parent->GetValueAsUnsigned(UINT64_MAX);
283254721Semaste
284314564Sdim  if (my_value == UINT64_MAX || parent_value == UINT64_MAX) {
285314564Sdim    error.SetErrorString("unable to read value");
286314564Sdim    return false;
287314564Sdim  }
288314564Sdim
289341825Sdim  // if we are at an offset from our parent, in order to set ourselves
290341825Sdim  // correctly we would need to change the new value so that it refers to the
291341825Sdim  // correct dynamic type. we choose not to deal with that - if anything more
292341825Sdim  // than a value overwrite is required, you should be using the expression
293341825Sdim  // parser instead of the value editing facility
294314564Sdim  if (my_value != parent_value) {
295314564Sdim    // but NULL'ing out a value should always be allowed
296314564Sdim    if (strcmp(value_str, "0")) {
297314564Sdim      error.SetErrorString(
298314564Sdim          "unable to modify dynamic value, use 'expression' command");
299314564Sdim      return false;
300254721Semaste    }
301314564Sdim  }
302314564Sdim
303314564Sdim  bool ret_val = m_parent->SetValueFromCString(value_str, error);
304314564Sdim  SetNeedsUpdate();
305314564Sdim  return ret_val;
306254721Semaste}
307254721Semaste
308321369Sdimbool ValueObjectDynamicValue::SetData(DataExtractor &data, Status &error) {
309314564Sdim  if (!UpdateValueIfNeeded(false)) {
310314564Sdim    error.SetErrorString("unable to read value");
311314564Sdim    return false;
312314564Sdim  }
313314564Sdim
314314564Sdim  uint64_t my_value = GetValueAsUnsigned(UINT64_MAX);
315314564Sdim  uint64_t parent_value = m_parent->GetValueAsUnsigned(UINT64_MAX);
316314564Sdim
317314564Sdim  if (my_value == UINT64_MAX || parent_value == UINT64_MAX) {
318314564Sdim    error.SetErrorString("unable to read value");
319314564Sdim    return false;
320314564Sdim  }
321314564Sdim
322341825Sdim  // if we are at an offset from our parent, in order to set ourselves
323341825Sdim  // correctly we would need to change the new value so that it refers to the
324341825Sdim  // correct dynamic type. we choose not to deal with that - if anything more
325341825Sdim  // than a value overwrite is required, you should be using the expression
326341825Sdim  // parser instead of the value editing facility
327314564Sdim  if (my_value != parent_value) {
328314564Sdim    // but NULL'ing out a value should always be allowed
329314564Sdim    lldb::offset_t offset = 0;
330314564Sdim
331314564Sdim    if (data.GetPointer(&offset) != 0) {
332314564Sdim      error.SetErrorString(
333314564Sdim          "unable to modify dynamic value, use 'expression' command");
334314564Sdim      return false;
335254721Semaste    }
336314564Sdim  }
337296417Sdim
338314564Sdim  bool ret_val = m_parent->SetData(data, error);
339314564Sdim  SetNeedsUpdate();
340314564Sdim  return ret_val;
341296417Sdim}
342296417Sdim
343314564Sdimvoid ValueObjectDynamicValue::SetPreferredDisplayLanguage(
344314564Sdim    lldb::LanguageType lang) {
345314564Sdim  this->ValueObject::SetPreferredDisplayLanguage(lang);
346314564Sdim  if (m_parent)
347314564Sdim    m_parent->SetPreferredDisplayLanguage(lang);
348296417Sdim}
349296417Sdim
350314564Sdimlldb::LanguageType ValueObjectDynamicValue::GetPreferredDisplayLanguage() {
351314564Sdim  if (m_preferred_display_language == lldb::eLanguageTypeUnknown) {
352309124Sdim    if (m_parent)
353314564Sdim      return m_parent->GetPreferredDisplayLanguage();
354314564Sdim    return lldb::eLanguageTypeUnknown;
355314564Sdim  } else
356314564Sdim    return m_preferred_display_language;
357309124Sdim}
358309124Sdim
359314564Sdimbool ValueObjectDynamicValue::IsSyntheticChildrenGenerated() {
360314564Sdim  if (m_parent)
361314564Sdim    return m_parent->IsSyntheticChildrenGenerated();
362314564Sdim  return false;
363309124Sdim}
364309124Sdim
365314564Sdimvoid ValueObjectDynamicValue::SetSyntheticChildrenGenerated(bool b) {
366314564Sdim  if (m_parent)
367314564Sdim    m_parent->SetSyntheticChildrenGenerated(b);
368314564Sdim  this->ValueObject::SetSyntheticChildrenGenerated(b);
369314564Sdim}
370296417Sdim
371314564Sdimbool ValueObjectDynamicValue::GetDeclaration(Declaration &decl) {
372314564Sdim  if (m_parent)
373314564Sdim    return m_parent->GetDeclaration(decl);
374314564Sdim
375314564Sdim  return ValueObject::GetDeclaration(decl);
376296417Sdim}
377296417Sdim
378314564Sdimuint64_t ValueObjectDynamicValue::GetLanguageFlags() {
379314564Sdim  if (m_parent)
380314564Sdim    return m_parent->GetLanguageFlags();
381314564Sdim  return this->ValueObject::GetLanguageFlags();
382296417Sdim}
383296417Sdim
384314564Sdimvoid ValueObjectDynamicValue::SetLanguageFlags(uint64_t flags) {
385314564Sdim  if (m_parent)
386314564Sdim    m_parent->SetLanguageFlags(flags);
387314564Sdim  else
388314564Sdim    this->ValueObject::SetLanguageFlags(flags);
389296417Sdim}
390