1dda28197Spatrick //===-- ValueObject.cpp ---------------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick
9061da546Spatrick #include "lldb/Core/ValueObject.h"
10061da546Spatrick
11061da546Spatrick #include "lldb/Core/Address.h"
12be691f3bSpatrick #include "lldb/Core/Declaration.h"
13061da546Spatrick #include "lldb/Core/Module.h"
14061da546Spatrick #include "lldb/Core/ValueObjectCast.h"
15061da546Spatrick #include "lldb/Core/ValueObjectChild.h"
16061da546Spatrick #include "lldb/Core/ValueObjectConstResult.h"
17061da546Spatrick #include "lldb/Core/ValueObjectDynamicValue.h"
18061da546Spatrick #include "lldb/Core/ValueObjectMemory.h"
19061da546Spatrick #include "lldb/Core/ValueObjectSyntheticFilter.h"
20061da546Spatrick #include "lldb/DataFormatters/DataVisualization.h"
21061da546Spatrick #include "lldb/DataFormatters/DumpValueObjectOptions.h"
22061da546Spatrick #include "lldb/DataFormatters/FormatManager.h"
23061da546Spatrick #include "lldb/DataFormatters/StringPrinter.h"
24061da546Spatrick #include "lldb/DataFormatters/TypeFormat.h"
25061da546Spatrick #include "lldb/DataFormatters/TypeSummary.h"
26061da546Spatrick #include "lldb/DataFormatters/ValueObjectPrinter.h"
27061da546Spatrick #include "lldb/Expression/ExpressionVariable.h"
28061da546Spatrick #include "lldb/Host/Config.h"
29061da546Spatrick #include "lldb/Symbol/CompileUnit.h"
30061da546Spatrick #include "lldb/Symbol/CompilerType.h"
31061da546Spatrick #include "lldb/Symbol/SymbolContext.h"
32061da546Spatrick #include "lldb/Symbol/Type.h"
33061da546Spatrick #include "lldb/Symbol/Variable.h"
34061da546Spatrick #include "lldb/Target/ExecutionContext.h"
35061da546Spatrick #include "lldb/Target/Language.h"
36061da546Spatrick #include "lldb/Target/LanguageRuntime.h"
37061da546Spatrick #include "lldb/Target/Process.h"
38061da546Spatrick #include "lldb/Target/StackFrame.h"
39061da546Spatrick #include "lldb/Target/Target.h"
40061da546Spatrick #include "lldb/Target/Thread.h"
41061da546Spatrick #include "lldb/Target/ThreadList.h"
42061da546Spatrick #include "lldb/Utility/DataBuffer.h"
43061da546Spatrick #include "lldb/Utility/DataBufferHeap.h"
44061da546Spatrick #include "lldb/Utility/Flags.h"
45*f6aab3d8Srobert #include "lldb/Utility/LLDBLog.h"
46061da546Spatrick #include "lldb/Utility/Log.h"
47061da546Spatrick #include "lldb/Utility/Scalar.h"
48061da546Spatrick #include "lldb/Utility/Stream.h"
49061da546Spatrick #include "lldb/Utility/StreamString.h"
50061da546Spatrick #include "lldb/lldb-private-types.h"
51061da546Spatrick
52061da546Spatrick #include "llvm/Support/Compiler.h"
53061da546Spatrick
54061da546Spatrick #include <algorithm>
55061da546Spatrick #include <cstdint>
56061da546Spatrick #include <cstdlib>
57061da546Spatrick #include <memory>
58*f6aab3d8Srobert #include <optional>
59061da546Spatrick #include <tuple>
60061da546Spatrick
61be691f3bSpatrick #include <cassert>
62be691f3bSpatrick #include <cinttypes>
63be691f3bSpatrick #include <cstdio>
64be691f3bSpatrick #include <cstring>
65be691f3bSpatrick
66be691f3bSpatrick #include <lldb/Core/ValueObject.h>
67061da546Spatrick
68061da546Spatrick namespace lldb_private {
69061da546Spatrick class ExecutionContextScope;
70061da546Spatrick }
71061da546Spatrick namespace lldb_private {
72061da546Spatrick class SymbolContextScope;
73061da546Spatrick }
74061da546Spatrick
75061da546Spatrick using namespace lldb;
76061da546Spatrick using namespace lldb_private;
77061da546Spatrick
78061da546Spatrick static user_id_t g_value_obj_uid = 0;
79061da546Spatrick
80061da546Spatrick // ValueObject constructor
ValueObject(ValueObject & parent)81061da546Spatrick ValueObject::ValueObject(ValueObject &parent)
82be691f3bSpatrick : m_parent(&parent), m_update_point(parent.GetUpdatePoint()),
83be691f3bSpatrick m_manager(parent.GetManager()), m_id(++g_value_obj_uid) {
84be691f3bSpatrick m_flags.m_is_synthetic_children_generated =
85be691f3bSpatrick parent.m_flags.m_is_synthetic_children_generated;
86061da546Spatrick m_data.SetByteOrder(parent.GetDataExtractor().GetByteOrder());
87061da546Spatrick m_data.SetAddressByteSize(parent.GetDataExtractor().GetAddressByteSize());
88061da546Spatrick m_manager->ManageObject(this);
89061da546Spatrick }
90061da546Spatrick
91061da546Spatrick // ValueObject constructor
ValueObject(ExecutionContextScope * exe_scope,ValueObjectManager & manager,AddressType child_ptr_or_ref_addr_type)92061da546Spatrick ValueObject::ValueObject(ExecutionContextScope *exe_scope,
93dda28197Spatrick ValueObjectManager &manager,
94061da546Spatrick AddressType child_ptr_or_ref_addr_type)
95be691f3bSpatrick : m_update_point(exe_scope), m_manager(&manager),
96061da546Spatrick m_address_type_of_ptr_or_ref_children(child_ptr_or_ref_addr_type),
97be691f3bSpatrick m_id(++g_value_obj_uid) {
98061da546Spatrick if (exe_scope) {
99061da546Spatrick TargetSP target_sp(exe_scope->CalculateTarget());
100061da546Spatrick if (target_sp) {
101061da546Spatrick const ArchSpec &arch = target_sp->GetArchitecture();
102061da546Spatrick m_data.SetByteOrder(arch.GetByteOrder());
103061da546Spatrick m_data.SetAddressByteSize(arch.GetAddressByteSize());
104061da546Spatrick }
105061da546Spatrick }
106061da546Spatrick m_manager->ManageObject(this);
107061da546Spatrick }
108061da546Spatrick
109061da546Spatrick // Destructor
110be691f3bSpatrick ValueObject::~ValueObject() = default;
111061da546Spatrick
UpdateValueIfNeeded(bool update_format)112061da546Spatrick bool ValueObject::UpdateValueIfNeeded(bool update_format) {
113061da546Spatrick
114061da546Spatrick bool did_change_formats = false;
115061da546Spatrick
116061da546Spatrick if (update_format)
117061da546Spatrick did_change_formats = UpdateFormatsIfNeeded();
118061da546Spatrick
119061da546Spatrick // If this is a constant value, then our success is predicated on whether we
120061da546Spatrick // have an error or not
121061da546Spatrick if (GetIsConstant()) {
122061da546Spatrick // if you are constant, things might still have changed behind your back
123061da546Spatrick // (e.g. you are a frozen object and things have changed deeper than you
124061da546Spatrick // cared to freeze-dry yourself) in this case, your value has not changed,
125061da546Spatrick // but "computed" entries might have, so you might now have a different
126061da546Spatrick // summary, or a different object description. clear these so we will
127061da546Spatrick // recompute them
128061da546Spatrick if (update_format && !did_change_formats)
129061da546Spatrick ClearUserVisibleData(eClearUserVisibleDataItemsSummary |
130061da546Spatrick eClearUserVisibleDataItemsDescription);
131061da546Spatrick return m_error.Success();
132061da546Spatrick }
133061da546Spatrick
134061da546Spatrick bool first_update = IsChecksumEmpty();
135061da546Spatrick
136061da546Spatrick if (NeedsUpdating()) {
137061da546Spatrick m_update_point.SetUpdated();
138061da546Spatrick
139061da546Spatrick // Save the old value using swap to avoid a string copy which also will
140061da546Spatrick // clear our m_value_str
141061da546Spatrick if (m_value_str.empty()) {
142be691f3bSpatrick m_flags.m_old_value_valid = false;
143061da546Spatrick } else {
144be691f3bSpatrick m_flags.m_old_value_valid = true;
145061da546Spatrick m_old_value_str.swap(m_value_str);
146061da546Spatrick ClearUserVisibleData(eClearUserVisibleDataItemsValue);
147061da546Spatrick }
148061da546Spatrick
149061da546Spatrick ClearUserVisibleData();
150061da546Spatrick
151061da546Spatrick if (IsInScope()) {
152061da546Spatrick const bool value_was_valid = GetValueIsValid();
153061da546Spatrick SetValueDidChange(false);
154061da546Spatrick
155061da546Spatrick m_error.Clear();
156061da546Spatrick
157061da546Spatrick // Call the pure virtual function to update the value
158061da546Spatrick
159061da546Spatrick bool need_compare_checksums = false;
160061da546Spatrick llvm::SmallVector<uint8_t, 16> old_checksum;
161061da546Spatrick
162061da546Spatrick if (!first_update && CanProvideValue()) {
163061da546Spatrick need_compare_checksums = true;
164061da546Spatrick old_checksum.resize(m_value_checksum.size());
165061da546Spatrick std::copy(m_value_checksum.begin(), m_value_checksum.end(),
166061da546Spatrick old_checksum.begin());
167061da546Spatrick }
168061da546Spatrick
169061da546Spatrick bool success = UpdateValue();
170061da546Spatrick
171061da546Spatrick SetValueIsValid(success);
172061da546Spatrick
173061da546Spatrick if (success) {
174061da546Spatrick UpdateChildrenAddressType();
175061da546Spatrick const uint64_t max_checksum_size = 128;
176061da546Spatrick m_data.Checksum(m_value_checksum, max_checksum_size);
177061da546Spatrick } else {
178061da546Spatrick need_compare_checksums = false;
179061da546Spatrick m_value_checksum.clear();
180061da546Spatrick }
181061da546Spatrick
182061da546Spatrick assert(!need_compare_checksums ||
183061da546Spatrick (!old_checksum.empty() && !m_value_checksum.empty()));
184061da546Spatrick
185061da546Spatrick if (first_update)
186061da546Spatrick SetValueDidChange(false);
187be691f3bSpatrick else if (!m_flags.m_value_did_change && !success) {
188061da546Spatrick // The value wasn't gotten successfully, so we mark this as changed if
189061da546Spatrick // the value used to be valid and now isn't
190061da546Spatrick SetValueDidChange(value_was_valid);
191061da546Spatrick } else if (need_compare_checksums) {
192061da546Spatrick SetValueDidChange(memcmp(&old_checksum[0], &m_value_checksum[0],
193061da546Spatrick m_value_checksum.size()));
194061da546Spatrick }
195061da546Spatrick
196061da546Spatrick } else {
197061da546Spatrick m_error.SetErrorString("out of scope");
198061da546Spatrick }
199061da546Spatrick }
200061da546Spatrick return m_error.Success();
201061da546Spatrick }
202061da546Spatrick
UpdateFormatsIfNeeded()203061da546Spatrick bool ValueObject::UpdateFormatsIfNeeded() {
204*f6aab3d8Srobert Log *log = GetLog(LLDBLog::DataFormatters);
205061da546Spatrick LLDB_LOGF(log,
206061da546Spatrick "[%s %p] checking for FormatManager revisions. ValueObject "
207061da546Spatrick "rev: %d - Global rev: %d",
208061da546Spatrick GetName().GetCString(), static_cast<void *>(this),
209061da546Spatrick m_last_format_mgr_revision,
210061da546Spatrick DataVisualization::GetCurrentRevision());
211061da546Spatrick
212061da546Spatrick bool any_change = false;
213061da546Spatrick
214061da546Spatrick if ((m_last_format_mgr_revision != DataVisualization::GetCurrentRevision())) {
215061da546Spatrick m_last_format_mgr_revision = DataVisualization::GetCurrentRevision();
216061da546Spatrick any_change = true;
217061da546Spatrick
218061da546Spatrick SetValueFormat(DataVisualization::GetFormat(*this, eNoDynamicValues));
219061da546Spatrick SetSummaryFormat(
220061da546Spatrick DataVisualization::GetSummaryFormat(*this, GetDynamicValueType()));
221061da546Spatrick #if LLDB_ENABLE_PYTHON
222061da546Spatrick SetSyntheticChildren(
223061da546Spatrick DataVisualization::GetSyntheticChildren(*this, GetDynamicValueType()));
224061da546Spatrick #endif
225061da546Spatrick }
226061da546Spatrick
227061da546Spatrick return any_change;
228061da546Spatrick }
229061da546Spatrick
SetNeedsUpdate()230061da546Spatrick void ValueObject::SetNeedsUpdate() {
231061da546Spatrick m_update_point.SetNeedsUpdate();
232061da546Spatrick // We have to clear the value string here so ConstResult children will notice
233061da546Spatrick // if their values are changed by hand (i.e. with SetValueAsCString).
234061da546Spatrick ClearUserVisibleData(eClearUserVisibleDataItemsValue);
235061da546Spatrick }
236061da546Spatrick
ClearDynamicTypeInformation()237061da546Spatrick void ValueObject::ClearDynamicTypeInformation() {
238be691f3bSpatrick m_flags.m_children_count_valid = false;
239be691f3bSpatrick m_flags.m_did_calculate_complete_objc_class_type = false;
240061da546Spatrick m_last_format_mgr_revision = 0;
241061da546Spatrick m_override_type = CompilerType();
242061da546Spatrick SetValueFormat(lldb::TypeFormatImplSP());
243061da546Spatrick SetSummaryFormat(lldb::TypeSummaryImplSP());
244061da546Spatrick SetSyntheticChildren(lldb::SyntheticChildrenSP());
245061da546Spatrick }
246061da546Spatrick
MaybeCalculateCompleteType()247061da546Spatrick CompilerType ValueObject::MaybeCalculateCompleteType() {
248061da546Spatrick CompilerType compiler_type(GetCompilerTypeImpl());
249061da546Spatrick
250be691f3bSpatrick if (m_flags.m_did_calculate_complete_objc_class_type) {
251061da546Spatrick if (m_override_type.IsValid())
252061da546Spatrick return m_override_type;
253061da546Spatrick else
254061da546Spatrick return compiler_type;
255061da546Spatrick }
256061da546Spatrick
257be691f3bSpatrick m_flags.m_did_calculate_complete_objc_class_type = true;
258061da546Spatrick
259061da546Spatrick ProcessSP process_sp(
260061da546Spatrick GetUpdatePoint().GetExecutionContextRef().GetProcessSP());
261061da546Spatrick
262061da546Spatrick if (!process_sp)
263061da546Spatrick return compiler_type;
264061da546Spatrick
265061da546Spatrick if (auto *runtime =
266061da546Spatrick process_sp->GetLanguageRuntime(GetObjectRuntimeLanguage())) {
267*f6aab3d8Srobert if (std::optional<CompilerType> complete_type =
268061da546Spatrick runtime->GetRuntimeType(compiler_type)) {
269*f6aab3d8Srobert m_override_type = *complete_type;
270061da546Spatrick if (m_override_type.IsValid())
271061da546Spatrick return m_override_type;
272061da546Spatrick }
273061da546Spatrick }
274061da546Spatrick return compiler_type;
275061da546Spatrick }
276061da546Spatrick
277061da546Spatrick
278061da546Spatrick
GetDataExtractor()279061da546Spatrick DataExtractor &ValueObject::GetDataExtractor() {
280061da546Spatrick UpdateValueIfNeeded(false);
281061da546Spatrick return m_data;
282061da546Spatrick }
283061da546Spatrick
GetError()284061da546Spatrick const Status &ValueObject::GetError() {
285061da546Spatrick UpdateValueIfNeeded(false);
286061da546Spatrick return m_error;
287061da546Spatrick }
288061da546Spatrick
GetLocationAsCStringImpl(const Value & value,const DataExtractor & data)289061da546Spatrick const char *ValueObject::GetLocationAsCStringImpl(const Value &value,
290061da546Spatrick const DataExtractor &data) {
291061da546Spatrick if (UpdateValueIfNeeded(false)) {
292061da546Spatrick if (m_location_str.empty()) {
293061da546Spatrick StreamString sstr;
294061da546Spatrick
295061da546Spatrick Value::ValueType value_type = value.GetValueType();
296061da546Spatrick
297061da546Spatrick switch (value_type) {
298be691f3bSpatrick case Value::ValueType::Invalid:
299be691f3bSpatrick m_location_str = "invalid";
300be691f3bSpatrick break;
301be691f3bSpatrick case Value::ValueType::Scalar:
302be691f3bSpatrick if (value.GetContextType() == Value::ContextType::RegisterInfo) {
303061da546Spatrick RegisterInfo *reg_info = value.GetRegisterInfo();
304061da546Spatrick if (reg_info) {
305061da546Spatrick if (reg_info->name)
306061da546Spatrick m_location_str = reg_info->name;
307061da546Spatrick else if (reg_info->alt_name)
308061da546Spatrick m_location_str = reg_info->alt_name;
309061da546Spatrick if (m_location_str.empty())
310061da546Spatrick m_location_str = (reg_info->encoding == lldb::eEncodingVector)
311061da546Spatrick ? "vector"
312061da546Spatrick : "scalar";
313061da546Spatrick }
314061da546Spatrick }
315061da546Spatrick if (m_location_str.empty())
316be691f3bSpatrick m_location_str = "scalar";
317061da546Spatrick break;
318061da546Spatrick
319be691f3bSpatrick case Value::ValueType::LoadAddress:
320be691f3bSpatrick case Value::ValueType::FileAddress:
321be691f3bSpatrick case Value::ValueType::HostAddress: {
322061da546Spatrick uint32_t addr_nibble_size = data.GetAddressByteSize() * 2;
323061da546Spatrick sstr.Printf("0x%*.*llx", addr_nibble_size, addr_nibble_size,
324061da546Spatrick value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS));
325dda28197Spatrick m_location_str = std::string(sstr.GetString());
326061da546Spatrick } break;
327061da546Spatrick }
328061da546Spatrick }
329061da546Spatrick }
330061da546Spatrick return m_location_str.c_str();
331061da546Spatrick }
332061da546Spatrick
ResolveValue(Scalar & scalar)333061da546Spatrick bool ValueObject::ResolveValue(Scalar &scalar) {
334061da546Spatrick if (UpdateValueIfNeeded(
335061da546Spatrick false)) // make sure that you are up to date before returning anything
336061da546Spatrick {
337061da546Spatrick ExecutionContext exe_ctx(GetExecutionContextRef());
338061da546Spatrick Value tmp_value(m_value);
339061da546Spatrick scalar = tmp_value.ResolveValue(&exe_ctx);
340061da546Spatrick if (scalar.IsValid()) {
341061da546Spatrick const uint32_t bitfield_bit_size = GetBitfieldBitSize();
342061da546Spatrick if (bitfield_bit_size)
343061da546Spatrick return scalar.ExtractBitfield(bitfield_bit_size,
344061da546Spatrick GetBitfieldBitOffset());
345061da546Spatrick return true;
346061da546Spatrick }
347061da546Spatrick }
348061da546Spatrick return false;
349061da546Spatrick }
350061da546Spatrick
IsLogicalTrue(Status & error)351061da546Spatrick bool ValueObject::IsLogicalTrue(Status &error) {
352061da546Spatrick if (Language *language = Language::FindPlugin(GetObjectRuntimeLanguage())) {
353061da546Spatrick LazyBool is_logical_true = language->IsLogicalTrue(*this, error);
354061da546Spatrick switch (is_logical_true) {
355061da546Spatrick case eLazyBoolYes:
356061da546Spatrick case eLazyBoolNo:
357061da546Spatrick return (is_logical_true == true);
358061da546Spatrick case eLazyBoolCalculate:
359061da546Spatrick break;
360061da546Spatrick }
361061da546Spatrick }
362061da546Spatrick
363061da546Spatrick Scalar scalar_value;
364061da546Spatrick
365061da546Spatrick if (!ResolveValue(scalar_value)) {
366061da546Spatrick error.SetErrorString("failed to get a scalar result");
367061da546Spatrick return false;
368061da546Spatrick }
369061da546Spatrick
370061da546Spatrick bool ret;
371061da546Spatrick ret = scalar_value.ULongLong(1) != 0;
372061da546Spatrick error.Clear();
373061da546Spatrick return ret;
374061da546Spatrick }
375061da546Spatrick
GetChildAtIndex(size_t idx,bool can_create)376061da546Spatrick ValueObjectSP ValueObject::GetChildAtIndex(size_t idx, bool can_create) {
377061da546Spatrick ValueObjectSP child_sp;
378061da546Spatrick // We may need to update our value if we are dynamic
379061da546Spatrick if (IsPossibleDynamicType())
380061da546Spatrick UpdateValueIfNeeded(false);
381061da546Spatrick if (idx < GetNumChildren()) {
382061da546Spatrick // Check if we have already made the child value object?
383061da546Spatrick if (can_create && !m_children.HasChildAtIndex(idx)) {
384061da546Spatrick // No we haven't created the child at this index, so lets have our
385061da546Spatrick // subclass do it and cache the result for quick future access.
386061da546Spatrick m_children.SetChildAtIndex(idx, CreateChildAtIndex(idx, false, 0));
387061da546Spatrick }
388061da546Spatrick
389061da546Spatrick ValueObject *child = m_children.GetChildAtIndex(idx);
390061da546Spatrick if (child != nullptr)
391061da546Spatrick return child->GetSP();
392061da546Spatrick }
393061da546Spatrick return child_sp;
394061da546Spatrick }
395061da546Spatrick
396061da546Spatrick lldb::ValueObjectSP
GetChildAtIndexPath(llvm::ArrayRef<size_t> idxs,size_t * index_of_error)397061da546Spatrick ValueObject::GetChildAtIndexPath(llvm::ArrayRef<size_t> idxs,
398061da546Spatrick size_t *index_of_error) {
399061da546Spatrick if (idxs.size() == 0)
400061da546Spatrick return GetSP();
401061da546Spatrick ValueObjectSP root(GetSP());
402061da546Spatrick for (size_t idx : idxs) {
403061da546Spatrick root = root->GetChildAtIndex(idx, true);
404061da546Spatrick if (!root) {
405061da546Spatrick if (index_of_error)
406061da546Spatrick *index_of_error = idx;
407061da546Spatrick return root;
408061da546Spatrick }
409061da546Spatrick }
410061da546Spatrick return root;
411061da546Spatrick }
412061da546Spatrick
GetChildAtIndexPath(llvm::ArrayRef<std::pair<size_t,bool>> idxs,size_t * index_of_error)413061da546Spatrick lldb::ValueObjectSP ValueObject::GetChildAtIndexPath(
414061da546Spatrick llvm::ArrayRef<std::pair<size_t, bool>> idxs, size_t *index_of_error) {
415061da546Spatrick if (idxs.size() == 0)
416061da546Spatrick return GetSP();
417061da546Spatrick ValueObjectSP root(GetSP());
418061da546Spatrick for (std::pair<size_t, bool> idx : idxs) {
419061da546Spatrick root = root->GetChildAtIndex(idx.first, idx.second);
420061da546Spatrick if (!root) {
421061da546Spatrick if (index_of_error)
422061da546Spatrick *index_of_error = idx.first;
423061da546Spatrick return root;
424061da546Spatrick }
425061da546Spatrick }
426061da546Spatrick return root;
427061da546Spatrick }
428061da546Spatrick
429061da546Spatrick lldb::ValueObjectSP
GetChildAtNamePath(llvm::ArrayRef<ConstString> names,ConstString * name_of_error)430061da546Spatrick ValueObject::GetChildAtNamePath(llvm::ArrayRef<ConstString> names,
431061da546Spatrick ConstString *name_of_error) {
432061da546Spatrick if (names.size() == 0)
433061da546Spatrick return GetSP();
434061da546Spatrick ValueObjectSP root(GetSP());
435061da546Spatrick for (ConstString name : names) {
436061da546Spatrick root = root->GetChildMemberWithName(name, true);
437061da546Spatrick if (!root) {
438061da546Spatrick if (name_of_error)
439061da546Spatrick *name_of_error = name;
440061da546Spatrick return root;
441061da546Spatrick }
442061da546Spatrick }
443061da546Spatrick return root;
444061da546Spatrick }
445061da546Spatrick
GetChildAtNamePath(llvm::ArrayRef<std::pair<ConstString,bool>> names,ConstString * name_of_error)446061da546Spatrick lldb::ValueObjectSP ValueObject::GetChildAtNamePath(
447061da546Spatrick llvm::ArrayRef<std::pair<ConstString, bool>> names,
448061da546Spatrick ConstString *name_of_error) {
449061da546Spatrick if (names.size() == 0)
450061da546Spatrick return GetSP();
451061da546Spatrick ValueObjectSP root(GetSP());
452061da546Spatrick for (std::pair<ConstString, bool> name : names) {
453061da546Spatrick root = root->GetChildMemberWithName(name.first, name.second);
454061da546Spatrick if (!root) {
455061da546Spatrick if (name_of_error)
456061da546Spatrick *name_of_error = name.first;
457061da546Spatrick return root;
458061da546Spatrick }
459061da546Spatrick }
460061da546Spatrick return root;
461061da546Spatrick }
462061da546Spatrick
GetIndexOfChildWithName(ConstString name)463061da546Spatrick size_t ValueObject::GetIndexOfChildWithName(ConstString name) {
464061da546Spatrick bool omit_empty_base_classes = true;
465061da546Spatrick return GetCompilerType().GetIndexOfChildWithName(name.GetCString(),
466061da546Spatrick omit_empty_base_classes);
467061da546Spatrick }
468061da546Spatrick
GetChildMemberWithName(ConstString name,bool can_create)469061da546Spatrick ValueObjectSP ValueObject::GetChildMemberWithName(ConstString name,
470061da546Spatrick bool can_create) {
471dda28197Spatrick // We may need to update our value if we are dynamic.
472061da546Spatrick if (IsPossibleDynamicType())
473061da546Spatrick UpdateValueIfNeeded(false);
474061da546Spatrick
475dda28197Spatrick // When getting a child by name, it could be buried inside some base classes
476dda28197Spatrick // (which really aren't part of the expression path), so we need a vector of
477dda28197Spatrick // indexes that can get us down to the correct child.
478061da546Spatrick std::vector<uint32_t> child_indexes;
479061da546Spatrick bool omit_empty_base_classes = true;
480061da546Spatrick
481061da546Spatrick if (!GetCompilerType().IsValid())
482061da546Spatrick return ValueObjectSP();
483061da546Spatrick
484061da546Spatrick const size_t num_child_indexes =
485061da546Spatrick GetCompilerType().GetIndexOfChildMemberWithName(
486061da546Spatrick name.GetCString(), omit_empty_base_classes, child_indexes);
487dda28197Spatrick if (num_child_indexes == 0)
488dda28197Spatrick return nullptr;
489061da546Spatrick
490dda28197Spatrick ValueObjectSP child_sp = GetSP();
491dda28197Spatrick for (uint32_t idx : child_indexes)
492dda28197Spatrick if (child_sp)
493dda28197Spatrick child_sp = child_sp->GetChildAtIndex(idx, can_create);
494061da546Spatrick return child_sp;
495061da546Spatrick }
496061da546Spatrick
GetNumChildren(uint32_t max)497061da546Spatrick size_t ValueObject::GetNumChildren(uint32_t max) {
498061da546Spatrick UpdateValueIfNeeded();
499061da546Spatrick
500061da546Spatrick if (max < UINT32_MAX) {
501be691f3bSpatrick if (m_flags.m_children_count_valid) {
502061da546Spatrick size_t children_count = m_children.GetChildrenCount();
503061da546Spatrick return children_count <= max ? children_count : max;
504061da546Spatrick } else
505061da546Spatrick return CalculateNumChildren(max);
506061da546Spatrick }
507061da546Spatrick
508be691f3bSpatrick if (!m_flags.m_children_count_valid) {
509061da546Spatrick SetNumChildren(CalculateNumChildren());
510061da546Spatrick }
511061da546Spatrick return m_children.GetChildrenCount();
512061da546Spatrick }
513061da546Spatrick
MightHaveChildren()514061da546Spatrick bool ValueObject::MightHaveChildren() {
515061da546Spatrick bool has_children = false;
516061da546Spatrick const uint32_t type_info = GetTypeInfo();
517061da546Spatrick if (type_info) {
518061da546Spatrick if (type_info & (eTypeHasChildren | eTypeIsPointer | eTypeIsReference))
519061da546Spatrick has_children = true;
520061da546Spatrick } else {
521061da546Spatrick has_children = GetNumChildren() > 0;
522061da546Spatrick }
523061da546Spatrick return has_children;
524061da546Spatrick }
525061da546Spatrick
526061da546Spatrick // Should only be called by ValueObject::GetNumChildren()
SetNumChildren(size_t num_children)527061da546Spatrick void ValueObject::SetNumChildren(size_t num_children) {
528be691f3bSpatrick m_flags.m_children_count_valid = true;
529061da546Spatrick m_children.SetChildrenCount(num_children);
530061da546Spatrick }
531061da546Spatrick
CreateChildAtIndex(size_t idx,bool synthetic_array_member,int32_t synthetic_index)532061da546Spatrick ValueObject *ValueObject::CreateChildAtIndex(size_t idx,
533061da546Spatrick bool synthetic_array_member,
534061da546Spatrick int32_t synthetic_index) {
535061da546Spatrick ValueObject *valobj = nullptr;
536061da546Spatrick
537061da546Spatrick bool omit_empty_base_classes = true;
538061da546Spatrick bool ignore_array_bounds = synthetic_array_member;
539061da546Spatrick std::string child_name_str;
540061da546Spatrick uint32_t child_byte_size = 0;
541061da546Spatrick int32_t child_byte_offset = 0;
542061da546Spatrick uint32_t child_bitfield_bit_size = 0;
543061da546Spatrick uint32_t child_bitfield_bit_offset = 0;
544061da546Spatrick bool child_is_base_class = false;
545061da546Spatrick bool child_is_deref_of_parent = false;
546061da546Spatrick uint64_t language_flags = 0;
547061da546Spatrick
548061da546Spatrick const bool transparent_pointers = !synthetic_array_member;
549061da546Spatrick CompilerType child_compiler_type;
550061da546Spatrick
551061da546Spatrick ExecutionContext exe_ctx(GetExecutionContextRef());
552061da546Spatrick
553061da546Spatrick child_compiler_type = GetCompilerType().GetChildCompilerTypeAtIndex(
554061da546Spatrick &exe_ctx, idx, transparent_pointers, omit_empty_base_classes,
555061da546Spatrick ignore_array_bounds, child_name_str, child_byte_size, child_byte_offset,
556061da546Spatrick child_bitfield_bit_size, child_bitfield_bit_offset, child_is_base_class,
557061da546Spatrick child_is_deref_of_parent, this, language_flags);
558061da546Spatrick if (child_compiler_type) {
559061da546Spatrick if (synthetic_index)
560061da546Spatrick child_byte_offset += child_byte_size * synthetic_index;
561061da546Spatrick
562061da546Spatrick ConstString child_name;
563061da546Spatrick if (!child_name_str.empty())
564061da546Spatrick child_name.SetCString(child_name_str.c_str());
565061da546Spatrick
566061da546Spatrick valobj = new ValueObjectChild(
567061da546Spatrick *this, child_compiler_type, child_name, child_byte_size,
568061da546Spatrick child_byte_offset, child_bitfield_bit_size, child_bitfield_bit_offset,
569061da546Spatrick child_is_base_class, child_is_deref_of_parent, eAddressTypeInvalid,
570061da546Spatrick language_flags);
571061da546Spatrick }
572061da546Spatrick
573dda28197Spatrick // In case of an incomplete type, try to use the ValueObject's
574dda28197Spatrick // synthetic value to create the child ValueObject.
575dda28197Spatrick if (!valobj && synthetic_array_member) {
576dda28197Spatrick if (ValueObjectSP synth_valobj_sp = GetSyntheticValue()) {
577dda28197Spatrick valobj = synth_valobj_sp
578dda28197Spatrick ->GetChildAtIndex(synthetic_index, synthetic_array_member)
579dda28197Spatrick .get();
580dda28197Spatrick }
581dda28197Spatrick }
582dda28197Spatrick
583061da546Spatrick return valobj;
584061da546Spatrick }
585061da546Spatrick
GetSummaryAsCString(TypeSummaryImpl * summary_ptr,std::string & destination,lldb::LanguageType lang)586061da546Spatrick bool ValueObject::GetSummaryAsCString(TypeSummaryImpl *summary_ptr,
587061da546Spatrick std::string &destination,
588061da546Spatrick lldb::LanguageType lang) {
589061da546Spatrick return GetSummaryAsCString(summary_ptr, destination,
590061da546Spatrick TypeSummaryOptions().SetLanguage(lang));
591061da546Spatrick }
592061da546Spatrick
GetSummaryAsCString(TypeSummaryImpl * summary_ptr,std::string & destination,const TypeSummaryOptions & options)593061da546Spatrick bool ValueObject::GetSummaryAsCString(TypeSummaryImpl *summary_ptr,
594061da546Spatrick std::string &destination,
595061da546Spatrick const TypeSummaryOptions &options) {
596061da546Spatrick destination.clear();
597061da546Spatrick
598*f6aab3d8Srobert // If we have a forcefully completed type, don't try and show a summary from
599*f6aab3d8Srobert // a valid summary string or function because the type is not complete and
600*f6aab3d8Srobert // no member variables or member functions will be available.
601*f6aab3d8Srobert if (GetCompilerType().IsForcefullyCompleted()) {
602*f6aab3d8Srobert destination = "<incomplete type>";
603*f6aab3d8Srobert return true;
604*f6aab3d8Srobert }
605*f6aab3d8Srobert
606061da546Spatrick // ideally we would like to bail out if passing NULL, but if we do so we end
607061da546Spatrick // up not providing the summary for function pointers anymore
608be691f3bSpatrick if (/*summary_ptr == NULL ||*/ m_flags.m_is_getting_summary)
609061da546Spatrick return false;
610061da546Spatrick
611be691f3bSpatrick m_flags.m_is_getting_summary = true;
612061da546Spatrick
613061da546Spatrick TypeSummaryOptions actual_options(options);
614061da546Spatrick
615061da546Spatrick if (actual_options.GetLanguage() == lldb::eLanguageTypeUnknown)
616061da546Spatrick actual_options.SetLanguage(GetPreferredDisplayLanguage());
617061da546Spatrick
618061da546Spatrick // this is a hot path in code and we prefer to avoid setting this string all
619061da546Spatrick // too often also clearing out other information that we might care to see in
620061da546Spatrick // a crash log. might be useful in very specific situations though.
621061da546Spatrick /*Host::SetCrashDescriptionWithFormat("Trying to fetch a summary for %s %s.
622061da546Spatrick Summary provider's description is %s",
623061da546Spatrick GetTypeName().GetCString(),
624061da546Spatrick GetName().GetCString(),
625061da546Spatrick summary_ptr->GetDescription().c_str());*/
626061da546Spatrick
627061da546Spatrick if (UpdateValueIfNeeded(false) && summary_ptr) {
628061da546Spatrick if (HasSyntheticValue())
629061da546Spatrick m_synthetic_value->UpdateValueIfNeeded(); // the summary might depend on
630061da546Spatrick // the synthetic children being
631061da546Spatrick // up-to-date (e.g. ${svar%#})
632061da546Spatrick summary_ptr->FormatObject(this, destination, actual_options);
633061da546Spatrick }
634be691f3bSpatrick m_flags.m_is_getting_summary = false;
635061da546Spatrick return !destination.empty();
636061da546Spatrick }
637061da546Spatrick
GetSummaryAsCString(lldb::LanguageType lang)638061da546Spatrick const char *ValueObject::GetSummaryAsCString(lldb::LanguageType lang) {
639061da546Spatrick if (UpdateValueIfNeeded(true) && m_summary_str.empty()) {
640061da546Spatrick TypeSummaryOptions summary_options;
641061da546Spatrick summary_options.SetLanguage(lang);
642061da546Spatrick GetSummaryAsCString(GetSummaryFormat().get(), m_summary_str,
643061da546Spatrick summary_options);
644061da546Spatrick }
645061da546Spatrick if (m_summary_str.empty())
646061da546Spatrick return nullptr;
647061da546Spatrick return m_summary_str.c_str();
648061da546Spatrick }
649061da546Spatrick
GetSummaryAsCString(std::string & destination,const TypeSummaryOptions & options)650061da546Spatrick bool ValueObject::GetSummaryAsCString(std::string &destination,
651061da546Spatrick const TypeSummaryOptions &options) {
652061da546Spatrick return GetSummaryAsCString(GetSummaryFormat().get(), destination, options);
653061da546Spatrick }
654061da546Spatrick
IsCStringContainer(bool check_pointer)655061da546Spatrick bool ValueObject::IsCStringContainer(bool check_pointer) {
656061da546Spatrick CompilerType pointee_or_element_compiler_type;
657061da546Spatrick const Flags type_flags(GetTypeInfo(&pointee_or_element_compiler_type));
658061da546Spatrick bool is_char_arr_ptr(type_flags.AnySet(eTypeIsArray | eTypeIsPointer) &&
659061da546Spatrick pointee_or_element_compiler_type.IsCharType());
660061da546Spatrick if (!is_char_arr_ptr)
661061da546Spatrick return false;
662061da546Spatrick if (!check_pointer)
663061da546Spatrick return true;
664061da546Spatrick if (type_flags.Test(eTypeIsArray))
665061da546Spatrick return true;
666061da546Spatrick addr_t cstr_address = LLDB_INVALID_ADDRESS;
667061da546Spatrick AddressType cstr_address_type = eAddressTypeInvalid;
668dda28197Spatrick cstr_address = GetPointerValue(&cstr_address_type);
669061da546Spatrick return (cstr_address != LLDB_INVALID_ADDRESS);
670061da546Spatrick }
671061da546Spatrick
GetPointeeData(DataExtractor & data,uint32_t item_idx,uint32_t item_count)672061da546Spatrick size_t ValueObject::GetPointeeData(DataExtractor &data, uint32_t item_idx,
673061da546Spatrick uint32_t item_count) {
674061da546Spatrick CompilerType pointee_or_element_compiler_type;
675061da546Spatrick const uint32_t type_info = GetTypeInfo(&pointee_or_element_compiler_type);
676061da546Spatrick const bool is_pointer_type = type_info & eTypeIsPointer;
677061da546Spatrick const bool is_array_type = type_info & eTypeIsArray;
678061da546Spatrick if (!(is_pointer_type || is_array_type))
679061da546Spatrick return 0;
680061da546Spatrick
681061da546Spatrick if (item_count == 0)
682061da546Spatrick return 0;
683061da546Spatrick
684061da546Spatrick ExecutionContext exe_ctx(GetExecutionContextRef());
685061da546Spatrick
686*f6aab3d8Srobert std::optional<uint64_t> item_type_size =
687061da546Spatrick pointee_or_element_compiler_type.GetByteSize(
688061da546Spatrick exe_ctx.GetBestExecutionContextScope());
689061da546Spatrick if (!item_type_size)
690061da546Spatrick return 0;
691061da546Spatrick const uint64_t bytes = item_count * *item_type_size;
692061da546Spatrick const uint64_t offset = item_idx * *item_type_size;
693061da546Spatrick
694061da546Spatrick if (item_idx == 0 && item_count == 1) // simply a deref
695061da546Spatrick {
696061da546Spatrick if (is_pointer_type) {
697061da546Spatrick Status error;
698061da546Spatrick ValueObjectSP pointee_sp = Dereference(error);
699061da546Spatrick if (error.Fail() || pointee_sp.get() == nullptr)
700061da546Spatrick return 0;
701061da546Spatrick return pointee_sp->GetData(data, error);
702061da546Spatrick } else {
703061da546Spatrick ValueObjectSP child_sp = GetChildAtIndex(0, true);
704061da546Spatrick if (child_sp.get() == nullptr)
705061da546Spatrick return 0;
706061da546Spatrick Status error;
707061da546Spatrick return child_sp->GetData(data, error);
708061da546Spatrick }
709061da546Spatrick return true;
710061da546Spatrick } else /* (items > 1) */
711061da546Spatrick {
712061da546Spatrick Status error;
713061da546Spatrick lldb_private::DataBufferHeap *heap_buf_ptr = nullptr;
714061da546Spatrick lldb::DataBufferSP data_sp(heap_buf_ptr =
715061da546Spatrick new lldb_private::DataBufferHeap());
716061da546Spatrick
717061da546Spatrick AddressType addr_type;
718061da546Spatrick lldb::addr_t addr = is_pointer_type ? GetPointerValue(&addr_type)
719061da546Spatrick : GetAddressOf(true, &addr_type);
720061da546Spatrick
721061da546Spatrick switch (addr_type) {
722061da546Spatrick case eAddressTypeFile: {
723061da546Spatrick ModuleSP module_sp(GetModule());
724061da546Spatrick if (module_sp) {
725061da546Spatrick addr = addr + offset;
726061da546Spatrick Address so_addr;
727061da546Spatrick module_sp->ResolveFileAddress(addr, so_addr);
728061da546Spatrick ExecutionContext exe_ctx(GetExecutionContextRef());
729061da546Spatrick Target *target = exe_ctx.GetTargetPtr();
730061da546Spatrick if (target) {
731061da546Spatrick heap_buf_ptr->SetByteSize(bytes);
732061da546Spatrick size_t bytes_read = target->ReadMemory(
733be691f3bSpatrick so_addr, heap_buf_ptr->GetBytes(), bytes, error, true);
734061da546Spatrick if (error.Success()) {
735061da546Spatrick data.SetData(data_sp);
736061da546Spatrick return bytes_read;
737061da546Spatrick }
738061da546Spatrick }
739061da546Spatrick }
740061da546Spatrick } break;
741061da546Spatrick case eAddressTypeLoad: {
742061da546Spatrick ExecutionContext exe_ctx(GetExecutionContextRef());
743061da546Spatrick Process *process = exe_ctx.GetProcessPtr();
744061da546Spatrick if (process) {
745061da546Spatrick heap_buf_ptr->SetByteSize(bytes);
746061da546Spatrick size_t bytes_read = process->ReadMemory(
747061da546Spatrick addr + offset, heap_buf_ptr->GetBytes(), bytes, error);
748061da546Spatrick if (error.Success() || bytes_read > 0) {
749061da546Spatrick data.SetData(data_sp);
750061da546Spatrick return bytes_read;
751061da546Spatrick }
752061da546Spatrick }
753061da546Spatrick } break;
754061da546Spatrick case eAddressTypeHost: {
755061da546Spatrick auto max_bytes =
756061da546Spatrick GetCompilerType().GetByteSize(exe_ctx.GetBestExecutionContextScope());
757061da546Spatrick if (max_bytes && *max_bytes > offset) {
758061da546Spatrick size_t bytes_read = std::min<uint64_t>(*max_bytes - offset, bytes);
759061da546Spatrick addr = m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
760061da546Spatrick if (addr == 0 || addr == LLDB_INVALID_ADDRESS)
761061da546Spatrick break;
762061da546Spatrick heap_buf_ptr->CopyData((uint8_t *)(addr + offset), bytes_read);
763061da546Spatrick data.SetData(data_sp);
764061da546Spatrick return bytes_read;
765061da546Spatrick }
766061da546Spatrick } break;
767061da546Spatrick case eAddressTypeInvalid:
768061da546Spatrick break;
769061da546Spatrick }
770061da546Spatrick }
771061da546Spatrick return 0;
772061da546Spatrick }
773061da546Spatrick
GetData(DataExtractor & data,Status & error)774061da546Spatrick uint64_t ValueObject::GetData(DataExtractor &data, Status &error) {
775061da546Spatrick UpdateValueIfNeeded(false);
776061da546Spatrick ExecutionContext exe_ctx(GetExecutionContextRef());
777061da546Spatrick error = m_value.GetValueAsData(&exe_ctx, data, GetModule().get());
778061da546Spatrick if (error.Fail()) {
779061da546Spatrick if (m_data.GetByteSize()) {
780061da546Spatrick data = m_data;
781061da546Spatrick error.Clear();
782061da546Spatrick return data.GetByteSize();
783061da546Spatrick } else {
784061da546Spatrick return 0;
785061da546Spatrick }
786061da546Spatrick }
787061da546Spatrick data.SetAddressByteSize(m_data.GetAddressByteSize());
788061da546Spatrick data.SetByteOrder(m_data.GetByteOrder());
789061da546Spatrick return data.GetByteSize();
790061da546Spatrick }
791061da546Spatrick
SetData(DataExtractor & data,Status & error)792061da546Spatrick bool ValueObject::SetData(DataExtractor &data, Status &error) {
793061da546Spatrick error.Clear();
794061da546Spatrick // Make sure our value is up to date first so that our location and location
795061da546Spatrick // type is valid.
796061da546Spatrick if (!UpdateValueIfNeeded(false)) {
797061da546Spatrick error.SetErrorString("unable to read value");
798061da546Spatrick return false;
799061da546Spatrick }
800061da546Spatrick
801061da546Spatrick uint64_t count = 0;
802061da546Spatrick const Encoding encoding = GetCompilerType().GetEncoding(count);
803061da546Spatrick
804*f6aab3d8Srobert const size_t byte_size = GetByteSize().value_or(0);
805061da546Spatrick
806061da546Spatrick Value::ValueType value_type = m_value.GetValueType();
807061da546Spatrick
808061da546Spatrick switch (value_type) {
809be691f3bSpatrick case Value::ValueType::Invalid:
810be691f3bSpatrick error.SetErrorString("invalid location");
811be691f3bSpatrick return false;
812be691f3bSpatrick case Value::ValueType::Scalar: {
813061da546Spatrick Status set_error =
814061da546Spatrick m_value.GetScalar().SetValueFromData(data, encoding, byte_size);
815061da546Spatrick
816061da546Spatrick if (!set_error.Success()) {
817061da546Spatrick error.SetErrorStringWithFormat("unable to set scalar value: %s",
818061da546Spatrick set_error.AsCString());
819061da546Spatrick return false;
820061da546Spatrick }
821061da546Spatrick } break;
822be691f3bSpatrick case Value::ValueType::LoadAddress: {
823061da546Spatrick // If it is a load address, then the scalar value is the storage location
824061da546Spatrick // of the data, and we have to shove this value down to that load location.
825061da546Spatrick ExecutionContext exe_ctx(GetExecutionContextRef());
826061da546Spatrick Process *process = exe_ctx.GetProcessPtr();
827061da546Spatrick if (process) {
828061da546Spatrick addr_t target_addr = m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
829061da546Spatrick size_t bytes_written = process->WriteMemory(
830061da546Spatrick target_addr, data.GetDataStart(), byte_size, error);
831061da546Spatrick if (!error.Success())
832061da546Spatrick return false;
833061da546Spatrick if (bytes_written != byte_size) {
834061da546Spatrick error.SetErrorString("unable to write value to memory");
835061da546Spatrick return false;
836061da546Spatrick }
837061da546Spatrick }
838061da546Spatrick } break;
839be691f3bSpatrick case Value::ValueType::HostAddress: {
840061da546Spatrick // If it is a host address, then we stuff the scalar as a DataBuffer into
841061da546Spatrick // the Value's data.
842061da546Spatrick DataBufferSP buffer_sp(new DataBufferHeap(byte_size, 0));
843061da546Spatrick m_data.SetData(buffer_sp, 0);
844061da546Spatrick data.CopyByteOrderedData(0, byte_size,
845061da546Spatrick const_cast<uint8_t *>(m_data.GetDataStart()),
846061da546Spatrick byte_size, m_data.GetByteOrder());
847061da546Spatrick m_value.GetScalar() = (uintptr_t)m_data.GetDataStart();
848061da546Spatrick } break;
849be691f3bSpatrick case Value::ValueType::FileAddress:
850061da546Spatrick break;
851061da546Spatrick }
852061da546Spatrick
853061da546Spatrick // If we have reached this point, then we have successfully changed the
854061da546Spatrick // value.
855061da546Spatrick SetNeedsUpdate();
856061da546Spatrick return true;
857061da546Spatrick }
858061da546Spatrick
CopyStringDataToBufferSP(const StreamString & source,lldb::WritableDataBufferSP & destination)859061da546Spatrick static bool CopyStringDataToBufferSP(const StreamString &source,
860*f6aab3d8Srobert lldb::WritableDataBufferSP &destination) {
861*f6aab3d8Srobert llvm::StringRef src = source.GetString();
862*f6aab3d8Srobert src = src.rtrim('\0');
863*f6aab3d8Srobert destination = std::make_shared<DataBufferHeap>(src.size(), 0);
864*f6aab3d8Srobert memcpy(destination->GetBytes(), src.data(), src.size());
865061da546Spatrick return true;
866061da546Spatrick }
867061da546Spatrick
868061da546Spatrick std::pair<size_t, bool>
ReadPointedString(lldb::WritableDataBufferSP & buffer_sp,Status & error,uint32_t max_length,bool honor_array,Format item_format)869*f6aab3d8Srobert ValueObject::ReadPointedString(lldb::WritableDataBufferSP &buffer_sp,
870*f6aab3d8Srobert Status &error, uint32_t max_length,
871*f6aab3d8Srobert bool honor_array, Format item_format) {
872061da546Spatrick bool was_capped = false;
873061da546Spatrick StreamString s;
874061da546Spatrick ExecutionContext exe_ctx(GetExecutionContextRef());
875061da546Spatrick Target *target = exe_ctx.GetTargetPtr();
876061da546Spatrick
877061da546Spatrick if (!target) {
878061da546Spatrick s << "<no target to read from>";
879061da546Spatrick error.SetErrorString("no target to read from");
880061da546Spatrick CopyStringDataToBufferSP(s, buffer_sp);
881061da546Spatrick return {0, was_capped};
882061da546Spatrick }
883061da546Spatrick
884061da546Spatrick if (max_length == 0)
885061da546Spatrick max_length = target->GetMaximumSizeOfStringSummary();
886061da546Spatrick
887061da546Spatrick size_t bytes_read = 0;
888061da546Spatrick size_t total_bytes_read = 0;
889061da546Spatrick
890061da546Spatrick CompilerType compiler_type = GetCompilerType();
891061da546Spatrick CompilerType elem_or_pointee_compiler_type;
892061da546Spatrick const Flags type_flags(GetTypeInfo(&elem_or_pointee_compiler_type));
893061da546Spatrick if (type_flags.AnySet(eTypeIsArray | eTypeIsPointer) &&
894061da546Spatrick elem_or_pointee_compiler_type.IsCharType()) {
895061da546Spatrick addr_t cstr_address = LLDB_INVALID_ADDRESS;
896061da546Spatrick AddressType cstr_address_type = eAddressTypeInvalid;
897061da546Spatrick
898061da546Spatrick size_t cstr_len = 0;
899061da546Spatrick bool capped_data = false;
900061da546Spatrick const bool is_array = type_flags.Test(eTypeIsArray);
901061da546Spatrick if (is_array) {
902061da546Spatrick // We have an array
903061da546Spatrick uint64_t array_size = 0;
904be691f3bSpatrick if (compiler_type.IsArrayType(nullptr, &array_size)) {
905061da546Spatrick cstr_len = array_size;
906061da546Spatrick if (cstr_len > max_length) {
907061da546Spatrick capped_data = true;
908061da546Spatrick cstr_len = max_length;
909061da546Spatrick }
910061da546Spatrick }
911061da546Spatrick cstr_address = GetAddressOf(true, &cstr_address_type);
912061da546Spatrick } else {
913061da546Spatrick // We have a pointer
914061da546Spatrick cstr_address = GetPointerValue(&cstr_address_type);
915061da546Spatrick }
916061da546Spatrick
917061da546Spatrick if (cstr_address == 0 || cstr_address == LLDB_INVALID_ADDRESS) {
918061da546Spatrick if (cstr_address_type == eAddressTypeHost && is_array) {
919061da546Spatrick const char *cstr = GetDataExtractor().PeekCStr(0);
920061da546Spatrick if (cstr == nullptr) {
921061da546Spatrick s << "<invalid address>";
922061da546Spatrick error.SetErrorString("invalid address");
923061da546Spatrick CopyStringDataToBufferSP(s, buffer_sp);
924061da546Spatrick return {0, was_capped};
925061da546Spatrick }
926*f6aab3d8Srobert s << llvm::StringRef(cstr, cstr_len);
927*f6aab3d8Srobert CopyStringDataToBufferSP(s, buffer_sp);
928061da546Spatrick return {cstr_len, was_capped};
929061da546Spatrick } else {
930061da546Spatrick s << "<invalid address>";
931061da546Spatrick error.SetErrorString("invalid address");
932061da546Spatrick CopyStringDataToBufferSP(s, buffer_sp);
933061da546Spatrick return {0, was_capped};
934061da546Spatrick }
935061da546Spatrick }
936061da546Spatrick
937061da546Spatrick Address cstr_so_addr(cstr_address);
938061da546Spatrick DataExtractor data;
939061da546Spatrick if (cstr_len > 0 && honor_array) {
940061da546Spatrick // I am using GetPointeeData() here to abstract the fact that some
941061da546Spatrick // ValueObjects are actually frozen pointers in the host but the pointed-
942061da546Spatrick // to data lives in the debuggee, and GetPointeeData() automatically
943061da546Spatrick // takes care of this
944061da546Spatrick GetPointeeData(data, 0, cstr_len);
945061da546Spatrick
946061da546Spatrick if ((bytes_read = data.GetByteSize()) > 0) {
947061da546Spatrick total_bytes_read = bytes_read;
948061da546Spatrick for (size_t offset = 0; offset < bytes_read; offset++)
949061da546Spatrick s.Printf("%c", *data.PeekData(offset, 1));
950061da546Spatrick if (capped_data)
951061da546Spatrick was_capped = true;
952061da546Spatrick }
953061da546Spatrick } else {
954061da546Spatrick cstr_len = max_length;
955061da546Spatrick const size_t k_max_buf_size = 64;
956061da546Spatrick
957061da546Spatrick size_t offset = 0;
958061da546Spatrick
959061da546Spatrick int cstr_len_displayed = -1;
960061da546Spatrick bool capped_cstr = false;
961061da546Spatrick // I am using GetPointeeData() here to abstract the fact that some
962061da546Spatrick // ValueObjects are actually frozen pointers in the host but the pointed-
963061da546Spatrick // to data lives in the debuggee, and GetPointeeData() automatically
964061da546Spatrick // takes care of this
965061da546Spatrick while ((bytes_read = GetPointeeData(data, offset, k_max_buf_size)) > 0) {
966061da546Spatrick total_bytes_read += bytes_read;
967061da546Spatrick const char *cstr = data.PeekCStr(0);
968061da546Spatrick size_t len = strnlen(cstr, k_max_buf_size);
969061da546Spatrick if (cstr_len_displayed < 0)
970061da546Spatrick cstr_len_displayed = len;
971061da546Spatrick
972061da546Spatrick if (len == 0)
973061da546Spatrick break;
974061da546Spatrick cstr_len_displayed += len;
975061da546Spatrick if (len > bytes_read)
976061da546Spatrick len = bytes_read;
977061da546Spatrick if (len > cstr_len)
978061da546Spatrick len = cstr_len;
979061da546Spatrick
980061da546Spatrick for (size_t offset = 0; offset < bytes_read; offset++)
981061da546Spatrick s.Printf("%c", *data.PeekData(offset, 1));
982061da546Spatrick
983061da546Spatrick if (len < k_max_buf_size)
984061da546Spatrick break;
985061da546Spatrick
986061da546Spatrick if (len >= cstr_len) {
987061da546Spatrick capped_cstr = true;
988061da546Spatrick break;
989061da546Spatrick }
990061da546Spatrick
991061da546Spatrick cstr_len -= len;
992061da546Spatrick offset += len;
993061da546Spatrick }
994061da546Spatrick
995061da546Spatrick if (cstr_len_displayed >= 0) {
996061da546Spatrick if (capped_cstr)
997061da546Spatrick was_capped = true;
998061da546Spatrick }
999061da546Spatrick }
1000061da546Spatrick } else {
1001061da546Spatrick error.SetErrorString("not a string object");
1002061da546Spatrick s << "<not a string object>";
1003061da546Spatrick }
1004061da546Spatrick CopyStringDataToBufferSP(s, buffer_sp);
1005061da546Spatrick return {total_bytes_read, was_capped};
1006061da546Spatrick }
1007061da546Spatrick
GetObjectDescription()1008061da546Spatrick const char *ValueObject::GetObjectDescription() {
1009061da546Spatrick if (!UpdateValueIfNeeded(true))
1010061da546Spatrick return nullptr;
1011061da546Spatrick
1012061da546Spatrick // Return cached value.
1013061da546Spatrick if (!m_object_desc_str.empty())
1014061da546Spatrick return m_object_desc_str.c_str();
1015061da546Spatrick
1016061da546Spatrick ExecutionContext exe_ctx(GetExecutionContextRef());
1017061da546Spatrick Process *process = exe_ctx.GetProcessPtr();
1018061da546Spatrick if (!process)
1019061da546Spatrick return nullptr;
1020061da546Spatrick
1021061da546Spatrick // Returns the object description produced by one language runtime.
1022061da546Spatrick auto get_object_description = [&](LanguageType language) -> const char * {
1023061da546Spatrick if (LanguageRuntime *runtime = process->GetLanguageRuntime(language)) {
1024061da546Spatrick StreamString s;
1025061da546Spatrick if (runtime->GetObjectDescription(s, *this)) {
1026dda28197Spatrick m_object_desc_str.append(std::string(s.GetString()));
1027061da546Spatrick return m_object_desc_str.c_str();
1028061da546Spatrick }
1029061da546Spatrick }
1030061da546Spatrick return nullptr;
1031061da546Spatrick };
1032061da546Spatrick
1033061da546Spatrick // Try the native language runtime first.
1034061da546Spatrick LanguageType native_language = GetObjectRuntimeLanguage();
1035061da546Spatrick if (const char *desc = get_object_description(native_language))
1036061da546Spatrick return desc;
1037061da546Spatrick
1038061da546Spatrick // Try the Objective-C language runtime. This fallback is necessary
1039061da546Spatrick // for Objective-C++ and mixed Objective-C / C++ programs.
1040061da546Spatrick if (Language::LanguageIsCFamily(native_language))
1041061da546Spatrick return get_object_description(eLanguageTypeObjC);
1042061da546Spatrick return nullptr;
1043061da546Spatrick }
1044061da546Spatrick
GetValueAsCString(const lldb_private::TypeFormatImpl & format,std::string & destination)1045061da546Spatrick bool ValueObject::GetValueAsCString(const lldb_private::TypeFormatImpl &format,
1046061da546Spatrick std::string &destination) {
1047061da546Spatrick if (UpdateValueIfNeeded(false))
1048061da546Spatrick return format.FormatObject(this, destination);
1049061da546Spatrick else
1050061da546Spatrick return false;
1051061da546Spatrick }
1052061da546Spatrick
GetValueAsCString(lldb::Format format,std::string & destination)1053061da546Spatrick bool ValueObject::GetValueAsCString(lldb::Format format,
1054061da546Spatrick std::string &destination) {
1055061da546Spatrick return GetValueAsCString(TypeFormatImpl_Format(format), destination);
1056061da546Spatrick }
1057061da546Spatrick
GetValueAsCString()1058061da546Spatrick const char *ValueObject::GetValueAsCString() {
1059061da546Spatrick if (UpdateValueIfNeeded(true)) {
1060061da546Spatrick lldb::TypeFormatImplSP format_sp;
1061061da546Spatrick lldb::Format my_format = GetFormat();
1062061da546Spatrick if (my_format == lldb::eFormatDefault) {
1063061da546Spatrick if (m_type_format_sp)
1064061da546Spatrick format_sp = m_type_format_sp;
1065061da546Spatrick else {
1066be691f3bSpatrick if (m_flags.m_is_bitfield_for_scalar)
1067061da546Spatrick my_format = eFormatUnsigned;
1068061da546Spatrick else {
1069be691f3bSpatrick if (m_value.GetContextType() == Value::ContextType::RegisterInfo) {
1070061da546Spatrick const RegisterInfo *reg_info = m_value.GetRegisterInfo();
1071061da546Spatrick if (reg_info)
1072061da546Spatrick my_format = reg_info->format;
1073061da546Spatrick } else {
1074061da546Spatrick my_format = GetValue().GetCompilerType().GetFormat();
1075061da546Spatrick }
1076061da546Spatrick }
1077061da546Spatrick }
1078061da546Spatrick }
1079061da546Spatrick if (my_format != m_last_format || m_value_str.empty()) {
1080061da546Spatrick m_last_format = my_format;
1081061da546Spatrick if (!format_sp)
1082061da546Spatrick format_sp = std::make_shared<TypeFormatImpl_Format>(my_format);
1083061da546Spatrick if (GetValueAsCString(*format_sp.get(), m_value_str)) {
1084be691f3bSpatrick if (!m_flags.m_value_did_change && m_flags.m_old_value_valid) {
1085061da546Spatrick // The value was gotten successfully, so we consider the value as
1086061da546Spatrick // changed if the value string differs
1087061da546Spatrick SetValueDidChange(m_old_value_str != m_value_str);
1088061da546Spatrick }
1089061da546Spatrick }
1090061da546Spatrick }
1091061da546Spatrick }
1092061da546Spatrick if (m_value_str.empty())
1093061da546Spatrick return nullptr;
1094061da546Spatrick return m_value_str.c_str();
1095061da546Spatrick }
1096061da546Spatrick
1097061da546Spatrick // if > 8bytes, 0 is returned. this method should mostly be used to read
1098061da546Spatrick // address values out of pointers
GetValueAsUnsigned(uint64_t fail_value,bool * success)1099061da546Spatrick uint64_t ValueObject::GetValueAsUnsigned(uint64_t fail_value, bool *success) {
1100061da546Spatrick // If our byte size is zero this is an aggregate type that has children
1101061da546Spatrick if (CanProvideValue()) {
1102061da546Spatrick Scalar scalar;
1103061da546Spatrick if (ResolveValue(scalar)) {
1104061da546Spatrick if (success)
1105061da546Spatrick *success = true;
1106dda28197Spatrick scalar.MakeUnsigned();
1107061da546Spatrick return scalar.ULongLong(fail_value);
1108061da546Spatrick }
1109061da546Spatrick // fallthrough, otherwise...
1110061da546Spatrick }
1111061da546Spatrick
1112061da546Spatrick if (success)
1113061da546Spatrick *success = false;
1114061da546Spatrick return fail_value;
1115061da546Spatrick }
1116061da546Spatrick
GetValueAsSigned(int64_t fail_value,bool * success)1117061da546Spatrick int64_t ValueObject::GetValueAsSigned(int64_t fail_value, bool *success) {
1118061da546Spatrick // If our byte size is zero this is an aggregate type that has children
1119061da546Spatrick if (CanProvideValue()) {
1120061da546Spatrick Scalar scalar;
1121061da546Spatrick if (ResolveValue(scalar)) {
1122061da546Spatrick if (success)
1123061da546Spatrick *success = true;
1124dda28197Spatrick scalar.MakeSigned();
1125061da546Spatrick return scalar.SLongLong(fail_value);
1126061da546Spatrick }
1127061da546Spatrick // fallthrough, otherwise...
1128061da546Spatrick }
1129061da546Spatrick
1130061da546Spatrick if (success)
1131061da546Spatrick *success = false;
1132061da546Spatrick return fail_value;
1133061da546Spatrick }
1134061da546Spatrick
1135061da546Spatrick // if any more "special cases" are added to
1136061da546Spatrick // ValueObject::DumpPrintableRepresentation() please keep this call up to date
1137061da546Spatrick // by returning true for your new special cases. We will eventually move to
1138061da546Spatrick // checking this call result before trying to display special cases
HasSpecialPrintableRepresentation(ValueObjectRepresentationStyle val_obj_display,Format custom_format)1139061da546Spatrick bool ValueObject::HasSpecialPrintableRepresentation(
1140061da546Spatrick ValueObjectRepresentationStyle val_obj_display, Format custom_format) {
1141061da546Spatrick Flags flags(GetTypeInfo());
1142061da546Spatrick if (flags.AnySet(eTypeIsArray | eTypeIsPointer) &&
1143061da546Spatrick val_obj_display == ValueObject::eValueObjectRepresentationStyleValue) {
1144061da546Spatrick if (IsCStringContainer(true) &&
1145061da546Spatrick (custom_format == eFormatCString || custom_format == eFormatCharArray ||
1146061da546Spatrick custom_format == eFormatChar || custom_format == eFormatVectorOfChar))
1147061da546Spatrick return true;
1148061da546Spatrick
1149061da546Spatrick if (flags.Test(eTypeIsArray)) {
1150061da546Spatrick if ((custom_format == eFormatBytes) ||
1151061da546Spatrick (custom_format == eFormatBytesWithASCII))
1152061da546Spatrick return true;
1153061da546Spatrick
1154061da546Spatrick if ((custom_format == eFormatVectorOfChar) ||
1155061da546Spatrick (custom_format == eFormatVectorOfFloat32) ||
1156061da546Spatrick (custom_format == eFormatVectorOfFloat64) ||
1157061da546Spatrick (custom_format == eFormatVectorOfSInt16) ||
1158061da546Spatrick (custom_format == eFormatVectorOfSInt32) ||
1159061da546Spatrick (custom_format == eFormatVectorOfSInt64) ||
1160061da546Spatrick (custom_format == eFormatVectorOfSInt8) ||
1161061da546Spatrick (custom_format == eFormatVectorOfUInt128) ||
1162061da546Spatrick (custom_format == eFormatVectorOfUInt16) ||
1163061da546Spatrick (custom_format == eFormatVectorOfUInt32) ||
1164061da546Spatrick (custom_format == eFormatVectorOfUInt64) ||
1165061da546Spatrick (custom_format == eFormatVectorOfUInt8))
1166061da546Spatrick return true;
1167061da546Spatrick }
1168061da546Spatrick }
1169061da546Spatrick return false;
1170061da546Spatrick }
1171061da546Spatrick
DumpPrintableRepresentation(Stream & s,ValueObjectRepresentationStyle val_obj_display,Format custom_format,PrintableRepresentationSpecialCases special,bool do_dump_error)1172061da546Spatrick bool ValueObject::DumpPrintableRepresentation(
1173061da546Spatrick Stream &s, ValueObjectRepresentationStyle val_obj_display,
1174061da546Spatrick Format custom_format, PrintableRepresentationSpecialCases special,
1175061da546Spatrick bool do_dump_error) {
1176061da546Spatrick
1177061da546Spatrick Flags flags(GetTypeInfo());
1178061da546Spatrick
1179061da546Spatrick bool allow_special =
1180061da546Spatrick (special == ValueObject::PrintableRepresentationSpecialCases::eAllow);
1181061da546Spatrick const bool only_special = false;
1182061da546Spatrick
1183061da546Spatrick if (allow_special) {
1184061da546Spatrick if (flags.AnySet(eTypeIsArray | eTypeIsPointer) &&
1185061da546Spatrick val_obj_display == ValueObject::eValueObjectRepresentationStyleValue) {
1186061da546Spatrick // when being asked to get a printable display an array or pointer type
1187061da546Spatrick // directly, try to "do the right thing"
1188061da546Spatrick
1189061da546Spatrick if (IsCStringContainer(true) &&
1190061da546Spatrick (custom_format == eFormatCString ||
1191061da546Spatrick custom_format == eFormatCharArray || custom_format == eFormatChar ||
1192061da546Spatrick custom_format ==
1193061da546Spatrick eFormatVectorOfChar)) // print char[] & char* directly
1194061da546Spatrick {
1195061da546Spatrick Status error;
1196*f6aab3d8Srobert lldb::WritableDataBufferSP buffer_sp;
1197061da546Spatrick std::pair<size_t, bool> read_string = ReadPointedString(
1198061da546Spatrick buffer_sp, error, 0, (custom_format == eFormatVectorOfChar) ||
1199061da546Spatrick (custom_format == eFormatCharArray));
1200061da546Spatrick lldb_private::formatters::StringPrinter::
1201061da546Spatrick ReadBufferAndDumpToStreamOptions options(*this);
1202061da546Spatrick options.SetData(DataExtractor(
1203061da546Spatrick buffer_sp, lldb::eByteOrderInvalid,
1204061da546Spatrick 8)); // none of this matters for a string - pass some defaults
1205061da546Spatrick options.SetStream(&s);
1206061da546Spatrick options.SetPrefixToken(nullptr);
1207061da546Spatrick options.SetQuote('"');
1208061da546Spatrick options.SetSourceSize(buffer_sp->GetByteSize());
1209061da546Spatrick options.SetIsTruncated(read_string.second);
1210*f6aab3d8Srobert options.SetBinaryZeroIsTerminator(custom_format != eFormatVectorOfChar);
1211061da546Spatrick formatters::StringPrinter::ReadBufferAndDumpToStream<
1212061da546Spatrick lldb_private::formatters::StringPrinter::StringElementType::ASCII>(
1213061da546Spatrick options);
1214061da546Spatrick return !error.Fail();
1215061da546Spatrick }
1216061da546Spatrick
1217061da546Spatrick if (custom_format == eFormatEnum)
1218061da546Spatrick return false;
1219061da546Spatrick
1220061da546Spatrick // this only works for arrays, because I have no way to know when the
1221061da546Spatrick // pointed memory ends, and no special \0 end of data marker
1222061da546Spatrick if (flags.Test(eTypeIsArray)) {
1223061da546Spatrick if ((custom_format == eFormatBytes) ||
1224061da546Spatrick (custom_format == eFormatBytesWithASCII)) {
1225061da546Spatrick const size_t count = GetNumChildren();
1226061da546Spatrick
1227061da546Spatrick s << '[';
1228061da546Spatrick for (size_t low = 0; low < count; low++) {
1229061da546Spatrick
1230061da546Spatrick if (low)
1231061da546Spatrick s << ',';
1232061da546Spatrick
1233061da546Spatrick ValueObjectSP child = GetChildAtIndex(low, true);
1234061da546Spatrick if (!child.get()) {
1235061da546Spatrick s << "<invalid child>";
1236061da546Spatrick continue;
1237061da546Spatrick }
1238061da546Spatrick child->DumpPrintableRepresentation(
1239061da546Spatrick s, ValueObject::eValueObjectRepresentationStyleValue,
1240061da546Spatrick custom_format);
1241061da546Spatrick }
1242061da546Spatrick
1243061da546Spatrick s << ']';
1244061da546Spatrick
1245061da546Spatrick return true;
1246061da546Spatrick }
1247061da546Spatrick
1248061da546Spatrick if ((custom_format == eFormatVectorOfChar) ||
1249061da546Spatrick (custom_format == eFormatVectorOfFloat32) ||
1250061da546Spatrick (custom_format == eFormatVectorOfFloat64) ||
1251061da546Spatrick (custom_format == eFormatVectorOfSInt16) ||
1252061da546Spatrick (custom_format == eFormatVectorOfSInt32) ||
1253061da546Spatrick (custom_format == eFormatVectorOfSInt64) ||
1254061da546Spatrick (custom_format == eFormatVectorOfSInt8) ||
1255061da546Spatrick (custom_format == eFormatVectorOfUInt128) ||
1256061da546Spatrick (custom_format == eFormatVectorOfUInt16) ||
1257061da546Spatrick (custom_format == eFormatVectorOfUInt32) ||
1258061da546Spatrick (custom_format == eFormatVectorOfUInt64) ||
1259061da546Spatrick (custom_format == eFormatVectorOfUInt8)) // arrays of bytes, bytes
1260061da546Spatrick // with ASCII or any vector
1261061da546Spatrick // format should be printed
1262061da546Spatrick // directly
1263061da546Spatrick {
1264061da546Spatrick const size_t count = GetNumChildren();
1265061da546Spatrick
1266061da546Spatrick Format format = FormatManager::GetSingleItemFormat(custom_format);
1267061da546Spatrick
1268061da546Spatrick s << '[';
1269061da546Spatrick for (size_t low = 0; low < count; low++) {
1270061da546Spatrick
1271061da546Spatrick if (low)
1272061da546Spatrick s << ',';
1273061da546Spatrick
1274061da546Spatrick ValueObjectSP child = GetChildAtIndex(low, true);
1275061da546Spatrick if (!child.get()) {
1276061da546Spatrick s << "<invalid child>";
1277061da546Spatrick continue;
1278061da546Spatrick }
1279061da546Spatrick child->DumpPrintableRepresentation(
1280061da546Spatrick s, ValueObject::eValueObjectRepresentationStyleValue, format);
1281061da546Spatrick }
1282061da546Spatrick
1283061da546Spatrick s << ']';
1284061da546Spatrick
1285061da546Spatrick return true;
1286061da546Spatrick }
1287061da546Spatrick }
1288061da546Spatrick
1289061da546Spatrick if ((custom_format == eFormatBoolean) ||
1290061da546Spatrick (custom_format == eFormatBinary) || (custom_format == eFormatChar) ||
1291061da546Spatrick (custom_format == eFormatCharPrintable) ||
1292061da546Spatrick (custom_format == eFormatComplexFloat) ||
1293061da546Spatrick (custom_format == eFormatDecimal) || (custom_format == eFormatHex) ||
1294061da546Spatrick (custom_format == eFormatHexUppercase) ||
1295061da546Spatrick (custom_format == eFormatFloat) || (custom_format == eFormatOctal) ||
1296061da546Spatrick (custom_format == eFormatOSType) ||
1297061da546Spatrick (custom_format == eFormatUnicode16) ||
1298061da546Spatrick (custom_format == eFormatUnicode32) ||
1299061da546Spatrick (custom_format == eFormatUnsigned) ||
1300061da546Spatrick (custom_format == eFormatPointer) ||
1301061da546Spatrick (custom_format == eFormatComplexInteger) ||
1302061da546Spatrick (custom_format == eFormatComplex) ||
1303061da546Spatrick (custom_format == eFormatDefault)) // use the [] operator
1304061da546Spatrick return false;
1305061da546Spatrick }
1306061da546Spatrick }
1307061da546Spatrick
1308061da546Spatrick if (only_special)
1309061da546Spatrick return false;
1310061da546Spatrick
1311061da546Spatrick bool var_success = false;
1312061da546Spatrick
1313061da546Spatrick {
1314061da546Spatrick llvm::StringRef str;
1315061da546Spatrick
1316061da546Spatrick // this is a local stream that we are using to ensure that the data pointed
1317061da546Spatrick // to by cstr survives long enough for us to copy it to its destination -
1318061da546Spatrick // it is necessary to have this temporary storage area for cases where our
1319061da546Spatrick // desired output is not backed by some other longer-term storage
1320061da546Spatrick StreamString strm;
1321061da546Spatrick
1322061da546Spatrick if (custom_format != eFormatInvalid)
1323061da546Spatrick SetFormat(custom_format);
1324061da546Spatrick
1325061da546Spatrick switch (val_obj_display) {
1326061da546Spatrick case eValueObjectRepresentationStyleValue:
1327061da546Spatrick str = GetValueAsCString();
1328061da546Spatrick break;
1329061da546Spatrick
1330061da546Spatrick case eValueObjectRepresentationStyleSummary:
1331061da546Spatrick str = GetSummaryAsCString();
1332061da546Spatrick break;
1333061da546Spatrick
1334061da546Spatrick case eValueObjectRepresentationStyleLanguageSpecific:
1335061da546Spatrick str = GetObjectDescription();
1336061da546Spatrick break;
1337061da546Spatrick
1338061da546Spatrick case eValueObjectRepresentationStyleLocation:
1339061da546Spatrick str = GetLocationAsCString();
1340061da546Spatrick break;
1341061da546Spatrick
1342061da546Spatrick case eValueObjectRepresentationStyleChildrenCount:
1343061da546Spatrick strm.Printf("%" PRIu64 "", (uint64_t)GetNumChildren());
1344061da546Spatrick str = strm.GetString();
1345061da546Spatrick break;
1346061da546Spatrick
1347061da546Spatrick case eValueObjectRepresentationStyleType:
1348061da546Spatrick str = GetTypeName().GetStringRef();
1349061da546Spatrick break;
1350061da546Spatrick
1351061da546Spatrick case eValueObjectRepresentationStyleName:
1352061da546Spatrick str = GetName().GetStringRef();
1353061da546Spatrick break;
1354061da546Spatrick
1355061da546Spatrick case eValueObjectRepresentationStyleExpressionPath:
1356dda28197Spatrick GetExpressionPath(strm);
1357061da546Spatrick str = strm.GetString();
1358061da546Spatrick break;
1359061da546Spatrick }
1360061da546Spatrick
1361061da546Spatrick if (str.empty()) {
1362061da546Spatrick if (val_obj_display == eValueObjectRepresentationStyleValue)
1363061da546Spatrick str = GetSummaryAsCString();
1364061da546Spatrick else if (val_obj_display == eValueObjectRepresentationStyleSummary) {
1365061da546Spatrick if (!CanProvideValue()) {
1366061da546Spatrick strm.Printf("%s @ %s", GetTypeName().AsCString(),
1367061da546Spatrick GetLocationAsCString());
1368061da546Spatrick str = strm.GetString();
1369061da546Spatrick } else
1370061da546Spatrick str = GetValueAsCString();
1371061da546Spatrick }
1372061da546Spatrick }
1373061da546Spatrick
1374061da546Spatrick if (!str.empty())
1375061da546Spatrick s << str;
1376061da546Spatrick else {
1377061da546Spatrick if (m_error.Fail()) {
1378061da546Spatrick if (do_dump_error)
1379061da546Spatrick s.Printf("<%s>", m_error.AsCString());
1380061da546Spatrick else
1381061da546Spatrick return false;
1382061da546Spatrick } else if (val_obj_display == eValueObjectRepresentationStyleSummary)
1383061da546Spatrick s.PutCString("<no summary available>");
1384061da546Spatrick else if (val_obj_display == eValueObjectRepresentationStyleValue)
1385061da546Spatrick s.PutCString("<no value available>");
1386061da546Spatrick else if (val_obj_display ==
1387061da546Spatrick eValueObjectRepresentationStyleLanguageSpecific)
1388061da546Spatrick s.PutCString("<not a valid Objective-C object>"); // edit this if we
1389061da546Spatrick // have other runtimes
1390061da546Spatrick // that support a
1391061da546Spatrick // description
1392061da546Spatrick else
1393061da546Spatrick s.PutCString("<no printable representation>");
1394061da546Spatrick }
1395061da546Spatrick
1396061da546Spatrick // we should only return false here if we could not do *anything* even if
1397061da546Spatrick // we have an error message as output, that's a success from our callers'
1398061da546Spatrick // perspective, so return true
1399061da546Spatrick var_success = true;
1400061da546Spatrick
1401061da546Spatrick if (custom_format != eFormatInvalid)
1402061da546Spatrick SetFormat(eFormatDefault);
1403061da546Spatrick }
1404061da546Spatrick
1405061da546Spatrick return var_success;
1406061da546Spatrick }
1407061da546Spatrick
GetAddressOf(bool scalar_is_load_address,AddressType * address_type)1408061da546Spatrick addr_t ValueObject::GetAddressOf(bool scalar_is_load_address,
1409061da546Spatrick AddressType *address_type) {
1410061da546Spatrick // Can't take address of a bitfield
1411061da546Spatrick if (IsBitfield())
1412061da546Spatrick return LLDB_INVALID_ADDRESS;
1413061da546Spatrick
1414061da546Spatrick if (!UpdateValueIfNeeded(false))
1415061da546Spatrick return LLDB_INVALID_ADDRESS;
1416061da546Spatrick
1417061da546Spatrick switch (m_value.GetValueType()) {
1418be691f3bSpatrick case Value::ValueType::Invalid:
1419be691f3bSpatrick return LLDB_INVALID_ADDRESS;
1420be691f3bSpatrick case Value::ValueType::Scalar:
1421061da546Spatrick if (scalar_is_load_address) {
1422061da546Spatrick if (address_type)
1423061da546Spatrick *address_type = eAddressTypeLoad;
1424061da546Spatrick return m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
1425061da546Spatrick }
1426061da546Spatrick break;
1427061da546Spatrick
1428be691f3bSpatrick case Value::ValueType::LoadAddress:
1429be691f3bSpatrick case Value::ValueType::FileAddress: {
1430061da546Spatrick if (address_type)
1431061da546Spatrick *address_type = m_value.GetValueAddressType();
1432061da546Spatrick return m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
1433061da546Spatrick } break;
1434be691f3bSpatrick case Value::ValueType::HostAddress: {
1435061da546Spatrick if (address_type)
1436061da546Spatrick *address_type = m_value.GetValueAddressType();
1437061da546Spatrick return LLDB_INVALID_ADDRESS;
1438061da546Spatrick } break;
1439061da546Spatrick }
1440061da546Spatrick if (address_type)
1441061da546Spatrick *address_type = eAddressTypeInvalid;
1442061da546Spatrick return LLDB_INVALID_ADDRESS;
1443061da546Spatrick }
1444061da546Spatrick
GetPointerValue(AddressType * address_type)1445061da546Spatrick addr_t ValueObject::GetPointerValue(AddressType *address_type) {
1446061da546Spatrick addr_t address = LLDB_INVALID_ADDRESS;
1447061da546Spatrick if (address_type)
1448061da546Spatrick *address_type = eAddressTypeInvalid;
1449061da546Spatrick
1450061da546Spatrick if (!UpdateValueIfNeeded(false))
1451061da546Spatrick return address;
1452061da546Spatrick
1453061da546Spatrick switch (m_value.GetValueType()) {
1454be691f3bSpatrick case Value::ValueType::Invalid:
1455be691f3bSpatrick return LLDB_INVALID_ADDRESS;
1456be691f3bSpatrick case Value::ValueType::Scalar:
1457061da546Spatrick address = m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
1458061da546Spatrick break;
1459061da546Spatrick
1460be691f3bSpatrick case Value::ValueType::HostAddress:
1461be691f3bSpatrick case Value::ValueType::LoadAddress:
1462be691f3bSpatrick case Value::ValueType::FileAddress: {
1463061da546Spatrick lldb::offset_t data_offset = 0;
1464dda28197Spatrick address = m_data.GetAddress(&data_offset);
1465061da546Spatrick } break;
1466061da546Spatrick }
1467061da546Spatrick
1468061da546Spatrick if (address_type)
1469061da546Spatrick *address_type = GetAddressTypeOfChildren();
1470061da546Spatrick
1471061da546Spatrick return address;
1472061da546Spatrick }
1473061da546Spatrick
SetValueFromCString(const char * value_str,Status & error)1474061da546Spatrick bool ValueObject::SetValueFromCString(const char *value_str, Status &error) {
1475061da546Spatrick error.Clear();
1476061da546Spatrick // Make sure our value is up to date first so that our location and location
1477061da546Spatrick // type is valid.
1478061da546Spatrick if (!UpdateValueIfNeeded(false)) {
1479061da546Spatrick error.SetErrorString("unable to read value");
1480061da546Spatrick return false;
1481061da546Spatrick }
1482061da546Spatrick
1483061da546Spatrick uint64_t count = 0;
1484061da546Spatrick const Encoding encoding = GetCompilerType().GetEncoding(count);
1485061da546Spatrick
1486*f6aab3d8Srobert const size_t byte_size = GetByteSize().value_or(0);
1487061da546Spatrick
1488061da546Spatrick Value::ValueType value_type = m_value.GetValueType();
1489061da546Spatrick
1490be691f3bSpatrick if (value_type == Value::ValueType::Scalar) {
1491061da546Spatrick // If the value is already a scalar, then let the scalar change itself:
1492061da546Spatrick m_value.GetScalar().SetValueFromCString(value_str, encoding, byte_size);
1493061da546Spatrick } else if (byte_size <= 16) {
1494061da546Spatrick // If the value fits in a scalar, then make a new scalar and again let the
1495061da546Spatrick // scalar code do the conversion, then figure out where to put the new
1496061da546Spatrick // value.
1497061da546Spatrick Scalar new_scalar;
1498061da546Spatrick error = new_scalar.SetValueFromCString(value_str, encoding, byte_size);
1499061da546Spatrick if (error.Success()) {
1500061da546Spatrick switch (value_type) {
1501be691f3bSpatrick case Value::ValueType::LoadAddress: {
1502061da546Spatrick // If it is a load address, then the scalar value is the storage
1503061da546Spatrick // location of the data, and we have to shove this value down to that
1504061da546Spatrick // load location.
1505061da546Spatrick ExecutionContext exe_ctx(GetExecutionContextRef());
1506061da546Spatrick Process *process = exe_ctx.GetProcessPtr();
1507061da546Spatrick if (process) {
1508061da546Spatrick addr_t target_addr =
1509061da546Spatrick m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
1510061da546Spatrick size_t bytes_written = process->WriteScalarToMemory(
1511061da546Spatrick target_addr, new_scalar, byte_size, error);
1512061da546Spatrick if (!error.Success())
1513061da546Spatrick return false;
1514061da546Spatrick if (bytes_written != byte_size) {
1515061da546Spatrick error.SetErrorString("unable to write value to memory");
1516061da546Spatrick return false;
1517061da546Spatrick }
1518061da546Spatrick }
1519061da546Spatrick } break;
1520be691f3bSpatrick case Value::ValueType::HostAddress: {
1521061da546Spatrick // If it is a host address, then we stuff the scalar as a DataBuffer
1522061da546Spatrick // into the Value's data.
1523061da546Spatrick DataExtractor new_data;
1524061da546Spatrick new_data.SetByteOrder(m_data.GetByteOrder());
1525061da546Spatrick
1526061da546Spatrick DataBufferSP buffer_sp(new DataBufferHeap(byte_size, 0));
1527061da546Spatrick m_data.SetData(buffer_sp, 0);
1528061da546Spatrick bool success = new_scalar.GetData(new_data);
1529061da546Spatrick if (success) {
1530061da546Spatrick new_data.CopyByteOrderedData(
1531061da546Spatrick 0, byte_size, const_cast<uint8_t *>(m_data.GetDataStart()),
1532061da546Spatrick byte_size, m_data.GetByteOrder());
1533061da546Spatrick }
1534061da546Spatrick m_value.GetScalar() = (uintptr_t)m_data.GetDataStart();
1535061da546Spatrick
1536061da546Spatrick } break;
1537be691f3bSpatrick case Value::ValueType::Invalid:
1538be691f3bSpatrick error.SetErrorString("invalid location");
1539be691f3bSpatrick return false;
1540be691f3bSpatrick case Value::ValueType::FileAddress:
1541be691f3bSpatrick case Value::ValueType::Scalar:
1542061da546Spatrick break;
1543061da546Spatrick }
1544061da546Spatrick } else {
1545061da546Spatrick return false;
1546061da546Spatrick }
1547061da546Spatrick } else {
1548061da546Spatrick // We don't support setting things bigger than a scalar at present.
1549061da546Spatrick error.SetErrorString("unable to write aggregate data type");
1550061da546Spatrick return false;
1551061da546Spatrick }
1552061da546Spatrick
1553061da546Spatrick // If we have reached this point, then we have successfully changed the
1554061da546Spatrick // value.
1555061da546Spatrick SetNeedsUpdate();
1556061da546Spatrick return true;
1557061da546Spatrick }
1558061da546Spatrick
GetDeclaration(Declaration & decl)1559061da546Spatrick bool ValueObject::GetDeclaration(Declaration &decl) {
1560061da546Spatrick decl.Clear();
1561061da546Spatrick return false;
1562061da546Spatrick }
1563061da546Spatrick
AddSyntheticChild(ConstString key,ValueObject * valobj)1564061da546Spatrick void ValueObject::AddSyntheticChild(ConstString key,
1565061da546Spatrick ValueObject *valobj) {
1566061da546Spatrick m_synthetic_children[key] = valobj;
1567061da546Spatrick }
1568061da546Spatrick
GetSyntheticChild(ConstString key) const1569061da546Spatrick ValueObjectSP ValueObject::GetSyntheticChild(ConstString key) const {
1570061da546Spatrick ValueObjectSP synthetic_child_sp;
1571061da546Spatrick std::map<ConstString, ValueObject *>::const_iterator pos =
1572061da546Spatrick m_synthetic_children.find(key);
1573061da546Spatrick if (pos != m_synthetic_children.end())
1574061da546Spatrick synthetic_child_sp = pos->second->GetSP();
1575061da546Spatrick return synthetic_child_sp;
1576061da546Spatrick }
1577061da546Spatrick
IsPossibleDynamicType()1578061da546Spatrick bool ValueObject::IsPossibleDynamicType() {
1579061da546Spatrick ExecutionContext exe_ctx(GetExecutionContextRef());
1580061da546Spatrick Process *process = exe_ctx.GetProcessPtr();
1581061da546Spatrick if (process)
1582061da546Spatrick return process->IsPossibleDynamicValue(*this);
1583061da546Spatrick else
1584061da546Spatrick return GetCompilerType().IsPossibleDynamicType(nullptr, true, true);
1585061da546Spatrick }
1586061da546Spatrick
IsRuntimeSupportValue()1587061da546Spatrick bool ValueObject::IsRuntimeSupportValue() {
1588061da546Spatrick Process *process(GetProcessSP().get());
1589061da546Spatrick if (!process)
1590061da546Spatrick return false;
1591061da546Spatrick
1592be691f3bSpatrick // We trust that the compiler did the right thing and marked runtime support
1593061da546Spatrick // values as artificial.
1594061da546Spatrick if (!GetVariable() || !GetVariable()->IsArtificial())
1595061da546Spatrick return false;
1596061da546Spatrick
1597061da546Spatrick if (auto *runtime = process->GetLanguageRuntime(GetVariable()->GetLanguage()))
1598dda28197Spatrick if (runtime->IsAllowedRuntimeValue(GetName()))
1599061da546Spatrick return false;
1600061da546Spatrick
1601061da546Spatrick return true;
1602061da546Spatrick }
1603061da546Spatrick
IsNilReference()1604061da546Spatrick bool ValueObject::IsNilReference() {
1605061da546Spatrick if (Language *language = Language::FindPlugin(GetObjectRuntimeLanguage())) {
1606061da546Spatrick return language->IsNilReference(*this);
1607061da546Spatrick }
1608061da546Spatrick return false;
1609061da546Spatrick }
1610061da546Spatrick
IsUninitializedReference()1611061da546Spatrick bool ValueObject::IsUninitializedReference() {
1612061da546Spatrick if (Language *language = Language::FindPlugin(GetObjectRuntimeLanguage())) {
1613061da546Spatrick return language->IsUninitializedReference(*this);
1614061da546Spatrick }
1615061da546Spatrick return false;
1616061da546Spatrick }
1617061da546Spatrick
1618061da546Spatrick // This allows you to create an array member using and index that doesn't not
1619061da546Spatrick // fall in the normal bounds of the array. Many times structure can be defined
1620061da546Spatrick // as: struct Collection {
1621061da546Spatrick // uint32_t item_count;
1622061da546Spatrick // Item item_array[0];
1623061da546Spatrick // };
1624061da546Spatrick // The size of the "item_array" is 1, but many times in practice there are more
1625061da546Spatrick // items in "item_array".
1626061da546Spatrick
GetSyntheticArrayMember(size_t index,bool can_create)1627061da546Spatrick ValueObjectSP ValueObject::GetSyntheticArrayMember(size_t index,
1628061da546Spatrick bool can_create) {
1629061da546Spatrick ValueObjectSP synthetic_child_sp;
1630061da546Spatrick if (IsPointerType() || IsArrayType()) {
1631be691f3bSpatrick std::string index_str = llvm::formatv("[{0}]", index);
1632061da546Spatrick ConstString index_const_str(index_str);
1633061da546Spatrick // Check if we have already created a synthetic array member in this valid
1634061da546Spatrick // object. If we have we will re-use it.
1635061da546Spatrick synthetic_child_sp = GetSyntheticChild(index_const_str);
1636061da546Spatrick if (!synthetic_child_sp) {
1637061da546Spatrick ValueObject *synthetic_child;
1638061da546Spatrick // We haven't made a synthetic array member for INDEX yet, so lets make
1639061da546Spatrick // one and cache it for any future reference.
1640061da546Spatrick synthetic_child = CreateChildAtIndex(0, true, index);
1641061da546Spatrick
1642061da546Spatrick // Cache the value if we got one back...
1643061da546Spatrick if (synthetic_child) {
1644061da546Spatrick AddSyntheticChild(index_const_str, synthetic_child);
1645061da546Spatrick synthetic_child_sp = synthetic_child->GetSP();
1646061da546Spatrick synthetic_child_sp->SetName(ConstString(index_str));
1647be691f3bSpatrick synthetic_child_sp->m_flags.m_is_array_item_for_pointer = true;
1648061da546Spatrick }
1649061da546Spatrick }
1650061da546Spatrick }
1651061da546Spatrick return synthetic_child_sp;
1652061da546Spatrick }
1653061da546Spatrick
GetSyntheticBitFieldChild(uint32_t from,uint32_t to,bool can_create)1654061da546Spatrick ValueObjectSP ValueObject::GetSyntheticBitFieldChild(uint32_t from, uint32_t to,
1655061da546Spatrick bool can_create) {
1656061da546Spatrick ValueObjectSP synthetic_child_sp;
1657061da546Spatrick if (IsScalarType()) {
1658be691f3bSpatrick std::string index_str = llvm::formatv("[{0}-{1}]", from, to);
1659061da546Spatrick ConstString index_const_str(index_str);
1660061da546Spatrick // Check if we have already created a synthetic array member in this valid
1661061da546Spatrick // object. If we have we will re-use it.
1662061da546Spatrick synthetic_child_sp = GetSyntheticChild(index_const_str);
1663061da546Spatrick if (!synthetic_child_sp) {
1664061da546Spatrick uint32_t bit_field_size = to - from + 1;
1665061da546Spatrick uint32_t bit_field_offset = from;
1666061da546Spatrick if (GetDataExtractor().GetByteOrder() == eByteOrderBig)
1667061da546Spatrick bit_field_offset =
1668*f6aab3d8Srobert GetByteSize().value_or(0) * 8 - bit_field_size - bit_field_offset;
1669061da546Spatrick // We haven't made a synthetic array member for INDEX yet, so lets make
1670061da546Spatrick // one and cache it for any future reference.
1671061da546Spatrick ValueObjectChild *synthetic_child = new ValueObjectChild(
1672*f6aab3d8Srobert *this, GetCompilerType(), index_const_str, GetByteSize().value_or(0),
1673*f6aab3d8Srobert 0, bit_field_size, bit_field_offset, false, false,
1674*f6aab3d8Srobert eAddressTypeInvalid, 0);
1675061da546Spatrick
1676061da546Spatrick // Cache the value if we got one back...
1677061da546Spatrick if (synthetic_child) {
1678061da546Spatrick AddSyntheticChild(index_const_str, synthetic_child);
1679061da546Spatrick synthetic_child_sp = synthetic_child->GetSP();
1680061da546Spatrick synthetic_child_sp->SetName(ConstString(index_str));
1681be691f3bSpatrick synthetic_child_sp->m_flags.m_is_bitfield_for_scalar = true;
1682061da546Spatrick }
1683061da546Spatrick }
1684061da546Spatrick }
1685061da546Spatrick return synthetic_child_sp;
1686061da546Spatrick }
1687061da546Spatrick
GetSyntheticChildAtOffset(uint32_t offset,const CompilerType & type,bool can_create,ConstString name_const_str)1688061da546Spatrick ValueObjectSP ValueObject::GetSyntheticChildAtOffset(
1689061da546Spatrick uint32_t offset, const CompilerType &type, bool can_create,
1690061da546Spatrick ConstString name_const_str) {
1691061da546Spatrick
1692061da546Spatrick ValueObjectSP synthetic_child_sp;
1693061da546Spatrick
1694061da546Spatrick if (name_const_str.IsEmpty()) {
1695be691f3bSpatrick name_const_str.SetString("@" + std::to_string(offset));
1696061da546Spatrick }
1697061da546Spatrick
1698061da546Spatrick // Check if we have already created a synthetic array member in this valid
1699061da546Spatrick // object. If we have we will re-use it.
1700061da546Spatrick synthetic_child_sp = GetSyntheticChild(name_const_str);
1701061da546Spatrick
1702061da546Spatrick if (synthetic_child_sp.get())
1703061da546Spatrick return synthetic_child_sp;
1704061da546Spatrick
1705061da546Spatrick if (!can_create)
1706061da546Spatrick return {};
1707061da546Spatrick
1708061da546Spatrick ExecutionContext exe_ctx(GetExecutionContextRef());
1709*f6aab3d8Srobert std::optional<uint64_t> size =
1710061da546Spatrick type.GetByteSize(exe_ctx.GetBestExecutionContextScope());
1711061da546Spatrick if (!size)
1712061da546Spatrick return {};
1713061da546Spatrick ValueObjectChild *synthetic_child =
1714061da546Spatrick new ValueObjectChild(*this, type, name_const_str, *size, offset, 0, 0,
1715061da546Spatrick false, false, eAddressTypeInvalid, 0);
1716061da546Spatrick if (synthetic_child) {
1717061da546Spatrick AddSyntheticChild(name_const_str, synthetic_child);
1718061da546Spatrick synthetic_child_sp = synthetic_child->GetSP();
1719061da546Spatrick synthetic_child_sp->SetName(name_const_str);
1720be691f3bSpatrick synthetic_child_sp->m_flags.m_is_child_at_offset = true;
1721061da546Spatrick }
1722061da546Spatrick return synthetic_child_sp;
1723061da546Spatrick }
1724061da546Spatrick
GetSyntheticBase(uint32_t offset,const CompilerType & type,bool can_create,ConstString name_const_str)1725061da546Spatrick ValueObjectSP ValueObject::GetSyntheticBase(uint32_t offset,
1726061da546Spatrick const CompilerType &type,
1727061da546Spatrick bool can_create,
1728061da546Spatrick ConstString name_const_str) {
1729061da546Spatrick ValueObjectSP synthetic_child_sp;
1730061da546Spatrick
1731061da546Spatrick if (name_const_str.IsEmpty()) {
1732061da546Spatrick char name_str[128];
1733061da546Spatrick snprintf(name_str, sizeof(name_str), "base%s@%i",
1734061da546Spatrick type.GetTypeName().AsCString("<unknown>"), offset);
1735061da546Spatrick name_const_str.SetCString(name_str);
1736061da546Spatrick }
1737061da546Spatrick
1738061da546Spatrick // Check if we have already created a synthetic array member in this valid
1739061da546Spatrick // object. If we have we will re-use it.
1740061da546Spatrick synthetic_child_sp = GetSyntheticChild(name_const_str);
1741061da546Spatrick
1742061da546Spatrick if (synthetic_child_sp.get())
1743061da546Spatrick return synthetic_child_sp;
1744061da546Spatrick
1745061da546Spatrick if (!can_create)
1746061da546Spatrick return {};
1747061da546Spatrick
1748061da546Spatrick const bool is_base_class = true;
1749061da546Spatrick
1750061da546Spatrick ExecutionContext exe_ctx(GetExecutionContextRef());
1751*f6aab3d8Srobert std::optional<uint64_t> size =
1752061da546Spatrick type.GetByteSize(exe_ctx.GetBestExecutionContextScope());
1753061da546Spatrick if (!size)
1754061da546Spatrick return {};
1755061da546Spatrick ValueObjectChild *synthetic_child =
1756061da546Spatrick new ValueObjectChild(*this, type, name_const_str, *size, offset, 0, 0,
1757061da546Spatrick is_base_class, false, eAddressTypeInvalid, 0);
1758061da546Spatrick if (synthetic_child) {
1759061da546Spatrick AddSyntheticChild(name_const_str, synthetic_child);
1760061da546Spatrick synthetic_child_sp = synthetic_child->GetSP();
1761061da546Spatrick synthetic_child_sp->SetName(name_const_str);
1762061da546Spatrick }
1763061da546Spatrick return synthetic_child_sp;
1764061da546Spatrick }
1765061da546Spatrick
1766061da546Spatrick // your expression path needs to have a leading . or -> (unless it somehow
1767061da546Spatrick // "looks like" an array, in which case it has a leading [ symbol). while the [
1768061da546Spatrick // is meaningful and should be shown to the user, . and -> are just parser
1769061da546Spatrick // design, but by no means added information for the user.. strip them off
SkipLeadingExpressionPathSeparators(const char * expression)1770061da546Spatrick static const char *SkipLeadingExpressionPathSeparators(const char *expression) {
1771061da546Spatrick if (!expression || !expression[0])
1772061da546Spatrick return expression;
1773061da546Spatrick if (expression[0] == '.')
1774061da546Spatrick return expression + 1;
1775061da546Spatrick if (expression[0] == '-' && expression[1] == '>')
1776061da546Spatrick return expression + 2;
1777061da546Spatrick return expression;
1778061da546Spatrick }
1779061da546Spatrick
1780061da546Spatrick ValueObjectSP
GetSyntheticExpressionPathChild(const char * expression,bool can_create)1781061da546Spatrick ValueObject::GetSyntheticExpressionPathChild(const char *expression,
1782061da546Spatrick bool can_create) {
1783061da546Spatrick ValueObjectSP synthetic_child_sp;
1784061da546Spatrick ConstString name_const_string(expression);
1785061da546Spatrick // Check if we have already created a synthetic array member in this valid
1786061da546Spatrick // object. If we have we will re-use it.
1787061da546Spatrick synthetic_child_sp = GetSyntheticChild(name_const_string);
1788061da546Spatrick if (!synthetic_child_sp) {
1789061da546Spatrick // We haven't made a synthetic array member for expression yet, so lets
1790061da546Spatrick // make one and cache it for any future reference.
1791061da546Spatrick synthetic_child_sp = GetValueForExpressionPath(
1792061da546Spatrick expression, nullptr, nullptr,
1793061da546Spatrick GetValueForExpressionPathOptions().SetSyntheticChildrenTraversal(
1794061da546Spatrick GetValueForExpressionPathOptions::SyntheticChildrenTraversal::
1795061da546Spatrick None));
1796061da546Spatrick
1797061da546Spatrick // Cache the value if we got one back...
1798061da546Spatrick if (synthetic_child_sp.get()) {
1799061da546Spatrick // FIXME: this causes a "real" child to end up with its name changed to
1800061da546Spatrick // the contents of expression
1801061da546Spatrick AddSyntheticChild(name_const_string, synthetic_child_sp.get());
1802061da546Spatrick synthetic_child_sp->SetName(
1803061da546Spatrick ConstString(SkipLeadingExpressionPathSeparators(expression)));
1804061da546Spatrick }
1805061da546Spatrick }
1806061da546Spatrick return synthetic_child_sp;
1807061da546Spatrick }
1808061da546Spatrick
CalculateSyntheticValue()1809dda28197Spatrick void ValueObject::CalculateSyntheticValue() {
1810061da546Spatrick TargetSP target_sp(GetTargetSP());
1811061da546Spatrick if (target_sp && !target_sp->GetEnableSyntheticValue()) {
1812061da546Spatrick m_synthetic_value = nullptr;
1813061da546Spatrick return;
1814061da546Spatrick }
1815061da546Spatrick
1816061da546Spatrick lldb::SyntheticChildrenSP current_synth_sp(m_synthetic_children_sp);
1817061da546Spatrick
1818061da546Spatrick if (!UpdateFormatsIfNeeded() && m_synthetic_value)
1819061da546Spatrick return;
1820061da546Spatrick
1821061da546Spatrick if (m_synthetic_children_sp.get() == nullptr)
1822061da546Spatrick return;
1823061da546Spatrick
1824061da546Spatrick if (current_synth_sp == m_synthetic_children_sp && m_synthetic_value)
1825061da546Spatrick return;
1826061da546Spatrick
1827061da546Spatrick m_synthetic_value = new ValueObjectSynthetic(*this, m_synthetic_children_sp);
1828061da546Spatrick }
1829061da546Spatrick
CalculateDynamicValue(DynamicValueType use_dynamic)1830061da546Spatrick void ValueObject::CalculateDynamicValue(DynamicValueType use_dynamic) {
1831061da546Spatrick if (use_dynamic == eNoDynamicValues)
1832061da546Spatrick return;
1833061da546Spatrick
1834061da546Spatrick if (!m_dynamic_value && !IsDynamic()) {
1835061da546Spatrick ExecutionContext exe_ctx(GetExecutionContextRef());
1836061da546Spatrick Process *process = exe_ctx.GetProcessPtr();
1837061da546Spatrick if (process && process->IsPossibleDynamicValue(*this)) {
1838061da546Spatrick ClearDynamicTypeInformation();
1839061da546Spatrick m_dynamic_value = new ValueObjectDynamicValue(*this, use_dynamic);
1840061da546Spatrick }
1841061da546Spatrick }
1842061da546Spatrick }
1843061da546Spatrick
GetDynamicValue(DynamicValueType use_dynamic)1844061da546Spatrick ValueObjectSP ValueObject::GetDynamicValue(DynamicValueType use_dynamic) {
1845061da546Spatrick if (use_dynamic == eNoDynamicValues)
1846061da546Spatrick return ValueObjectSP();
1847061da546Spatrick
1848061da546Spatrick if (!IsDynamic() && m_dynamic_value == nullptr) {
1849061da546Spatrick CalculateDynamicValue(use_dynamic);
1850061da546Spatrick }
1851061da546Spatrick if (m_dynamic_value)
1852061da546Spatrick return m_dynamic_value->GetSP();
1853061da546Spatrick else
1854061da546Spatrick return ValueObjectSP();
1855061da546Spatrick }
1856061da546Spatrick
GetSyntheticValue()1857dda28197Spatrick ValueObjectSP ValueObject::GetSyntheticValue() {
1858dda28197Spatrick CalculateSyntheticValue();
1859061da546Spatrick
1860061da546Spatrick if (m_synthetic_value)
1861061da546Spatrick return m_synthetic_value->GetSP();
1862061da546Spatrick else
1863061da546Spatrick return ValueObjectSP();
1864061da546Spatrick }
1865061da546Spatrick
HasSyntheticValue()1866061da546Spatrick bool ValueObject::HasSyntheticValue() {
1867061da546Spatrick UpdateFormatsIfNeeded();
1868061da546Spatrick
1869061da546Spatrick if (m_synthetic_children_sp.get() == nullptr)
1870061da546Spatrick return false;
1871061da546Spatrick
1872dda28197Spatrick CalculateSyntheticValue();
1873061da546Spatrick
1874061da546Spatrick return m_synthetic_value != nullptr;
1875061da546Spatrick }
1876061da546Spatrick
GetNonBaseClassParent()1877061da546Spatrick ValueObject *ValueObject::GetNonBaseClassParent() {
1878061da546Spatrick if (GetParent()) {
1879061da546Spatrick if (GetParent()->IsBaseClass())
1880061da546Spatrick return GetParent()->GetNonBaseClassParent();
1881061da546Spatrick else
1882061da546Spatrick return GetParent();
1883061da546Spatrick }
1884061da546Spatrick return nullptr;
1885061da546Spatrick }
1886061da546Spatrick
IsBaseClass(uint32_t & depth)1887061da546Spatrick bool ValueObject::IsBaseClass(uint32_t &depth) {
1888061da546Spatrick if (!IsBaseClass()) {
1889061da546Spatrick depth = 0;
1890061da546Spatrick return false;
1891061da546Spatrick }
1892061da546Spatrick if (GetParent()) {
1893061da546Spatrick GetParent()->IsBaseClass(depth);
1894061da546Spatrick depth = depth + 1;
1895061da546Spatrick return true;
1896061da546Spatrick }
1897061da546Spatrick // TODO: a base of no parent? weird..
1898061da546Spatrick depth = 1;
1899061da546Spatrick return true;
1900061da546Spatrick }
1901061da546Spatrick
GetExpressionPath(Stream & s,GetExpressionPathFormat epformat)1902dda28197Spatrick void ValueObject::GetExpressionPath(Stream &s,
1903061da546Spatrick GetExpressionPathFormat epformat) {
1904061da546Spatrick // synthetic children do not actually "exist" as part of the hierarchy, and
1905061da546Spatrick // sometimes they are consed up in ways that don't make sense from an
1906061da546Spatrick // underlying language/API standpoint. So, use a special code path here to
1907061da546Spatrick // return something that can hopefully be used in expression
1908be691f3bSpatrick if (m_flags.m_is_synthetic_children_generated) {
1909061da546Spatrick UpdateValueIfNeeded();
1910061da546Spatrick
1911be691f3bSpatrick if (m_value.GetValueType() == Value::ValueType::LoadAddress) {
1912061da546Spatrick if (IsPointerOrReferenceType()) {
1913061da546Spatrick s.Printf("((%s)0x%" PRIx64 ")", GetTypeName().AsCString("void"),
1914061da546Spatrick GetValueAsUnsigned(0));
1915061da546Spatrick return;
1916061da546Spatrick } else {
1917061da546Spatrick uint64_t load_addr =
1918061da546Spatrick m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
1919061da546Spatrick if (load_addr != LLDB_INVALID_ADDRESS) {
1920061da546Spatrick s.Printf("(*( (%s *)0x%" PRIx64 "))", GetTypeName().AsCString("void"),
1921061da546Spatrick load_addr);
1922061da546Spatrick return;
1923061da546Spatrick }
1924061da546Spatrick }
1925061da546Spatrick }
1926061da546Spatrick
1927061da546Spatrick if (CanProvideValue()) {
1928061da546Spatrick s.Printf("((%s)%s)", GetTypeName().AsCString("void"),
1929061da546Spatrick GetValueAsCString());
1930061da546Spatrick return;
1931061da546Spatrick }
1932061da546Spatrick
1933061da546Spatrick return;
1934061da546Spatrick }
1935061da546Spatrick
1936061da546Spatrick const bool is_deref_of_parent = IsDereferenceOfParent();
1937061da546Spatrick
1938061da546Spatrick if (is_deref_of_parent &&
1939061da546Spatrick epformat == eGetExpressionPathFormatDereferencePointers) {
1940061da546Spatrick // this is the original format of GetExpressionPath() producing code like
1941061da546Spatrick // *(a_ptr).memberName, which is entirely fine, until you put this into
1942061da546Spatrick // StackFrame::GetValueForVariableExpressionPath() which prefers to see
1943061da546Spatrick // a_ptr->memberName. the eHonorPointers mode is meant to produce strings
1944061da546Spatrick // in this latter format
1945061da546Spatrick s.PutCString("*(");
1946061da546Spatrick }
1947061da546Spatrick
1948061da546Spatrick ValueObject *parent = GetParent();
1949061da546Spatrick
1950061da546Spatrick if (parent)
1951dda28197Spatrick parent->GetExpressionPath(s, epformat);
1952061da546Spatrick
1953061da546Spatrick // if we are a deref_of_parent just because we are synthetic array members
1954061da546Spatrick // made up to allow ptr[%d] syntax to work in variable printing, then add our
1955061da546Spatrick // name ([%d]) to the expression path
1956be691f3bSpatrick if (m_flags.m_is_array_item_for_pointer &&
1957061da546Spatrick epformat == eGetExpressionPathFormatHonorPointers)
1958dda28197Spatrick s.PutCString(m_name.GetStringRef());
1959061da546Spatrick
1960061da546Spatrick if (!IsBaseClass()) {
1961061da546Spatrick if (!is_deref_of_parent) {
1962061da546Spatrick ValueObject *non_base_class_parent = GetNonBaseClassParent();
1963061da546Spatrick if (non_base_class_parent &&
1964061da546Spatrick !non_base_class_parent->GetName().IsEmpty()) {
1965061da546Spatrick CompilerType non_base_class_parent_compiler_type =
1966061da546Spatrick non_base_class_parent->GetCompilerType();
1967061da546Spatrick if (non_base_class_parent_compiler_type) {
1968061da546Spatrick if (parent && parent->IsDereferenceOfParent() &&
1969061da546Spatrick epformat == eGetExpressionPathFormatHonorPointers) {
1970061da546Spatrick s.PutCString("->");
1971061da546Spatrick } else {
1972061da546Spatrick const uint32_t non_base_class_parent_type_info =
1973061da546Spatrick non_base_class_parent_compiler_type.GetTypeInfo();
1974061da546Spatrick
1975061da546Spatrick if (non_base_class_parent_type_info & eTypeIsPointer) {
1976061da546Spatrick s.PutCString("->");
1977061da546Spatrick } else if ((non_base_class_parent_type_info & eTypeHasChildren) &&
1978061da546Spatrick !(non_base_class_parent_type_info & eTypeIsArray)) {
1979061da546Spatrick s.PutChar('.');
1980061da546Spatrick }
1981061da546Spatrick }
1982061da546Spatrick }
1983061da546Spatrick }
1984061da546Spatrick
1985061da546Spatrick const char *name = GetName().GetCString();
1986dda28197Spatrick if (name)
1987061da546Spatrick s.PutCString(name);
1988061da546Spatrick }
1989061da546Spatrick }
1990061da546Spatrick
1991061da546Spatrick if (is_deref_of_parent &&
1992061da546Spatrick epformat == eGetExpressionPathFormatDereferencePointers) {
1993061da546Spatrick s.PutChar(')');
1994061da546Spatrick }
1995061da546Spatrick }
1996061da546Spatrick
GetValueForExpressionPath(llvm::StringRef expression,ExpressionPathScanEndReason * reason_to_stop,ExpressionPathEndResultType * final_value_type,const GetValueForExpressionPathOptions & options,ExpressionPathAftermath * final_task_on_target)1997061da546Spatrick ValueObjectSP ValueObject::GetValueForExpressionPath(
1998061da546Spatrick llvm::StringRef expression, ExpressionPathScanEndReason *reason_to_stop,
1999061da546Spatrick ExpressionPathEndResultType *final_value_type,
2000061da546Spatrick const GetValueForExpressionPathOptions &options,
2001061da546Spatrick ExpressionPathAftermath *final_task_on_target) {
2002061da546Spatrick
2003061da546Spatrick ExpressionPathScanEndReason dummy_reason_to_stop =
2004061da546Spatrick ValueObject::eExpressionPathScanEndReasonUnknown;
2005061da546Spatrick ExpressionPathEndResultType dummy_final_value_type =
2006061da546Spatrick ValueObject::eExpressionPathEndResultTypeInvalid;
2007061da546Spatrick ExpressionPathAftermath dummy_final_task_on_target =
2008061da546Spatrick ValueObject::eExpressionPathAftermathNothing;
2009061da546Spatrick
2010061da546Spatrick ValueObjectSP ret_val = GetValueForExpressionPath_Impl(
2011061da546Spatrick expression, reason_to_stop ? reason_to_stop : &dummy_reason_to_stop,
2012061da546Spatrick final_value_type ? final_value_type : &dummy_final_value_type, options,
2013061da546Spatrick final_task_on_target ? final_task_on_target
2014061da546Spatrick : &dummy_final_task_on_target);
2015061da546Spatrick
2016061da546Spatrick if (!final_task_on_target ||
2017061da546Spatrick *final_task_on_target == ValueObject::eExpressionPathAftermathNothing)
2018061da546Spatrick return ret_val;
2019061da546Spatrick
2020061da546Spatrick if (ret_val.get() &&
2021061da546Spatrick ((final_value_type ? *final_value_type : dummy_final_value_type) ==
2022061da546Spatrick eExpressionPathEndResultTypePlain)) // I can only deref and takeaddress
2023061da546Spatrick // of plain objects
2024061da546Spatrick {
2025061da546Spatrick if ((final_task_on_target ? *final_task_on_target
2026061da546Spatrick : dummy_final_task_on_target) ==
2027061da546Spatrick ValueObject::eExpressionPathAftermathDereference) {
2028061da546Spatrick Status error;
2029061da546Spatrick ValueObjectSP final_value = ret_val->Dereference(error);
2030061da546Spatrick if (error.Fail() || !final_value.get()) {
2031061da546Spatrick if (reason_to_stop)
2032061da546Spatrick *reason_to_stop =
2033061da546Spatrick ValueObject::eExpressionPathScanEndReasonDereferencingFailed;
2034061da546Spatrick if (final_value_type)
2035061da546Spatrick *final_value_type = ValueObject::eExpressionPathEndResultTypeInvalid;
2036061da546Spatrick return ValueObjectSP();
2037061da546Spatrick } else {
2038061da546Spatrick if (final_task_on_target)
2039061da546Spatrick *final_task_on_target = ValueObject::eExpressionPathAftermathNothing;
2040061da546Spatrick return final_value;
2041061da546Spatrick }
2042061da546Spatrick }
2043061da546Spatrick if (*final_task_on_target ==
2044061da546Spatrick ValueObject::eExpressionPathAftermathTakeAddress) {
2045061da546Spatrick Status error;
2046061da546Spatrick ValueObjectSP final_value = ret_val->AddressOf(error);
2047061da546Spatrick if (error.Fail() || !final_value.get()) {
2048061da546Spatrick if (reason_to_stop)
2049061da546Spatrick *reason_to_stop =
2050061da546Spatrick ValueObject::eExpressionPathScanEndReasonTakingAddressFailed;
2051061da546Spatrick if (final_value_type)
2052061da546Spatrick *final_value_type = ValueObject::eExpressionPathEndResultTypeInvalid;
2053061da546Spatrick return ValueObjectSP();
2054061da546Spatrick } else {
2055061da546Spatrick if (final_task_on_target)
2056061da546Spatrick *final_task_on_target = ValueObject::eExpressionPathAftermathNothing;
2057061da546Spatrick return final_value;
2058061da546Spatrick }
2059061da546Spatrick }
2060061da546Spatrick }
2061061da546Spatrick return ret_val; // final_task_on_target will still have its original value, so
2062061da546Spatrick // you know I did not do it
2063061da546Spatrick }
2064061da546Spatrick
GetValueForExpressionPath_Impl(llvm::StringRef expression,ExpressionPathScanEndReason * reason_to_stop,ExpressionPathEndResultType * final_result,const GetValueForExpressionPathOptions & options,ExpressionPathAftermath * what_next)2065061da546Spatrick ValueObjectSP ValueObject::GetValueForExpressionPath_Impl(
2066061da546Spatrick llvm::StringRef expression, ExpressionPathScanEndReason *reason_to_stop,
2067061da546Spatrick ExpressionPathEndResultType *final_result,
2068061da546Spatrick const GetValueForExpressionPathOptions &options,
2069061da546Spatrick ExpressionPathAftermath *what_next) {
2070061da546Spatrick ValueObjectSP root = GetSP();
2071061da546Spatrick
2072061da546Spatrick if (!root)
2073061da546Spatrick return nullptr;
2074061da546Spatrick
2075061da546Spatrick llvm::StringRef remainder = expression;
2076061da546Spatrick
2077061da546Spatrick while (true) {
2078061da546Spatrick llvm::StringRef temp_expression = remainder;
2079061da546Spatrick
2080061da546Spatrick CompilerType root_compiler_type = root->GetCompilerType();
2081061da546Spatrick CompilerType pointee_compiler_type;
2082061da546Spatrick Flags pointee_compiler_type_info;
2083061da546Spatrick
2084061da546Spatrick Flags root_compiler_type_info(
2085061da546Spatrick root_compiler_type.GetTypeInfo(&pointee_compiler_type));
2086061da546Spatrick if (pointee_compiler_type)
2087061da546Spatrick pointee_compiler_type_info.Reset(pointee_compiler_type.GetTypeInfo());
2088061da546Spatrick
2089061da546Spatrick if (temp_expression.empty()) {
2090061da546Spatrick *reason_to_stop = ValueObject::eExpressionPathScanEndReasonEndOfString;
2091061da546Spatrick return root;
2092061da546Spatrick }
2093061da546Spatrick
2094061da546Spatrick switch (temp_expression.front()) {
2095061da546Spatrick case '-': {
2096061da546Spatrick temp_expression = temp_expression.drop_front();
2097061da546Spatrick if (options.m_check_dot_vs_arrow_syntax &&
2098061da546Spatrick root_compiler_type_info.Test(eTypeIsPointer)) // if you are trying to
2099061da546Spatrick // use -> on a
2100061da546Spatrick // non-pointer and I
2101061da546Spatrick // must catch the error
2102061da546Spatrick {
2103061da546Spatrick *reason_to_stop =
2104061da546Spatrick ValueObject::eExpressionPathScanEndReasonArrowInsteadOfDot;
2105061da546Spatrick *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
2106061da546Spatrick return ValueObjectSP();
2107061da546Spatrick }
2108061da546Spatrick if (root_compiler_type_info.Test(eTypeIsObjC) && // if yo are trying to
2109061da546Spatrick // extract an ObjC IVar
2110061da546Spatrick // when this is forbidden
2111061da546Spatrick root_compiler_type_info.Test(eTypeIsPointer) &&
2112061da546Spatrick options.m_no_fragile_ivar) {
2113061da546Spatrick *reason_to_stop =
2114061da546Spatrick ValueObject::eExpressionPathScanEndReasonFragileIVarNotAllowed;
2115061da546Spatrick *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
2116061da546Spatrick return ValueObjectSP();
2117061da546Spatrick }
2118061da546Spatrick if (!temp_expression.startswith(">")) {
2119061da546Spatrick *reason_to_stop =
2120061da546Spatrick ValueObject::eExpressionPathScanEndReasonUnexpectedSymbol;
2121061da546Spatrick *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
2122061da546Spatrick return ValueObjectSP();
2123061da546Spatrick }
2124061da546Spatrick }
2125*f6aab3d8Srobert [[fallthrough]];
2126061da546Spatrick case '.': // or fallthrough from ->
2127061da546Spatrick {
2128061da546Spatrick if (options.m_check_dot_vs_arrow_syntax &&
2129061da546Spatrick temp_expression.front() == '.' &&
2130061da546Spatrick root_compiler_type_info.Test(eTypeIsPointer)) // if you are trying to
2131061da546Spatrick // use . on a pointer
2132061da546Spatrick // and I must catch the
2133061da546Spatrick // error
2134061da546Spatrick {
2135061da546Spatrick *reason_to_stop =
2136061da546Spatrick ValueObject::eExpressionPathScanEndReasonDotInsteadOfArrow;
2137061da546Spatrick *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
2138061da546Spatrick return nullptr;
2139061da546Spatrick }
2140061da546Spatrick temp_expression = temp_expression.drop_front(); // skip . or >
2141061da546Spatrick
2142061da546Spatrick size_t next_sep_pos = temp_expression.find_first_of("-.[", 1);
2143061da546Spatrick ConstString child_name;
2144061da546Spatrick if (next_sep_pos == llvm::StringRef::npos) // if no other separator just
2145061da546Spatrick // expand this last layer
2146061da546Spatrick {
2147061da546Spatrick child_name.SetString(temp_expression);
2148061da546Spatrick ValueObjectSP child_valobj_sp =
2149061da546Spatrick root->GetChildMemberWithName(child_name, true);
2150061da546Spatrick
2151061da546Spatrick if (child_valobj_sp.get()) // we know we are done, so just return
2152061da546Spatrick {
2153061da546Spatrick *reason_to_stop =
2154061da546Spatrick ValueObject::eExpressionPathScanEndReasonEndOfString;
2155061da546Spatrick *final_result = ValueObject::eExpressionPathEndResultTypePlain;
2156061da546Spatrick return child_valobj_sp;
2157061da546Spatrick } else {
2158061da546Spatrick switch (options.m_synthetic_children_traversal) {
2159061da546Spatrick case GetValueForExpressionPathOptions::SyntheticChildrenTraversal::
2160061da546Spatrick None:
2161061da546Spatrick break;
2162061da546Spatrick case GetValueForExpressionPathOptions::SyntheticChildrenTraversal::
2163061da546Spatrick FromSynthetic:
2164061da546Spatrick if (root->IsSynthetic()) {
2165061da546Spatrick child_valobj_sp = root->GetNonSyntheticValue();
2166061da546Spatrick if (child_valobj_sp.get())
2167061da546Spatrick child_valobj_sp =
2168061da546Spatrick child_valobj_sp->GetChildMemberWithName(child_name, true);
2169061da546Spatrick }
2170061da546Spatrick break;
2171061da546Spatrick case GetValueForExpressionPathOptions::SyntheticChildrenTraversal::
2172061da546Spatrick ToSynthetic:
2173061da546Spatrick if (!root->IsSynthetic()) {
2174061da546Spatrick child_valobj_sp = root->GetSyntheticValue();
2175061da546Spatrick if (child_valobj_sp.get())
2176061da546Spatrick child_valobj_sp =
2177061da546Spatrick child_valobj_sp->GetChildMemberWithName(child_name, true);
2178061da546Spatrick }
2179061da546Spatrick break;
2180061da546Spatrick case GetValueForExpressionPathOptions::SyntheticChildrenTraversal::
2181061da546Spatrick Both:
2182061da546Spatrick if (root->IsSynthetic()) {
2183061da546Spatrick child_valobj_sp = root->GetNonSyntheticValue();
2184061da546Spatrick if (child_valobj_sp.get())
2185061da546Spatrick child_valobj_sp =
2186061da546Spatrick child_valobj_sp->GetChildMemberWithName(child_name, true);
2187061da546Spatrick } else {
2188061da546Spatrick child_valobj_sp = root->GetSyntheticValue();
2189061da546Spatrick if (child_valobj_sp.get())
2190061da546Spatrick child_valobj_sp =
2191061da546Spatrick child_valobj_sp->GetChildMemberWithName(child_name, true);
2192061da546Spatrick }
2193061da546Spatrick break;
2194061da546Spatrick }
2195061da546Spatrick }
2196061da546Spatrick
2197061da546Spatrick // if we are here and options.m_no_synthetic_children is true,
2198061da546Spatrick // child_valobj_sp is going to be a NULL SP, so we hit the "else"
2199061da546Spatrick // branch, and return an error
2200061da546Spatrick if (child_valobj_sp.get()) // if it worked, just return
2201061da546Spatrick {
2202061da546Spatrick *reason_to_stop =
2203061da546Spatrick ValueObject::eExpressionPathScanEndReasonEndOfString;
2204061da546Spatrick *final_result = ValueObject::eExpressionPathEndResultTypePlain;
2205061da546Spatrick return child_valobj_sp;
2206061da546Spatrick } else {
2207061da546Spatrick *reason_to_stop =
2208061da546Spatrick ValueObject::eExpressionPathScanEndReasonNoSuchChild;
2209061da546Spatrick *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
2210061da546Spatrick return nullptr;
2211061da546Spatrick }
2212061da546Spatrick } else // other layers do expand
2213061da546Spatrick {
2214061da546Spatrick llvm::StringRef next_separator = temp_expression.substr(next_sep_pos);
2215061da546Spatrick
2216061da546Spatrick child_name.SetString(temp_expression.slice(0, next_sep_pos));
2217061da546Spatrick
2218061da546Spatrick ValueObjectSP child_valobj_sp =
2219061da546Spatrick root->GetChildMemberWithName(child_name, true);
2220061da546Spatrick if (child_valobj_sp.get()) // store the new root and move on
2221061da546Spatrick {
2222061da546Spatrick root = child_valobj_sp;
2223061da546Spatrick remainder = next_separator;
2224061da546Spatrick *final_result = ValueObject::eExpressionPathEndResultTypePlain;
2225061da546Spatrick continue;
2226061da546Spatrick } else {
2227061da546Spatrick switch (options.m_synthetic_children_traversal) {
2228061da546Spatrick case GetValueForExpressionPathOptions::SyntheticChildrenTraversal::
2229061da546Spatrick None:
2230061da546Spatrick break;
2231061da546Spatrick case GetValueForExpressionPathOptions::SyntheticChildrenTraversal::
2232061da546Spatrick FromSynthetic:
2233061da546Spatrick if (root->IsSynthetic()) {
2234061da546Spatrick child_valobj_sp = root->GetNonSyntheticValue();
2235061da546Spatrick if (child_valobj_sp.get())
2236061da546Spatrick child_valobj_sp =
2237061da546Spatrick child_valobj_sp->GetChildMemberWithName(child_name, true);
2238061da546Spatrick }
2239061da546Spatrick break;
2240061da546Spatrick case GetValueForExpressionPathOptions::SyntheticChildrenTraversal::
2241061da546Spatrick ToSynthetic:
2242061da546Spatrick if (!root->IsSynthetic()) {
2243061da546Spatrick child_valobj_sp = root->GetSyntheticValue();
2244061da546Spatrick if (child_valobj_sp.get())
2245061da546Spatrick child_valobj_sp =
2246061da546Spatrick child_valobj_sp->GetChildMemberWithName(child_name, true);
2247061da546Spatrick }
2248061da546Spatrick break;
2249061da546Spatrick case GetValueForExpressionPathOptions::SyntheticChildrenTraversal::
2250061da546Spatrick Both:
2251061da546Spatrick if (root->IsSynthetic()) {
2252061da546Spatrick child_valobj_sp = root->GetNonSyntheticValue();
2253061da546Spatrick if (child_valobj_sp.get())
2254061da546Spatrick child_valobj_sp =
2255061da546Spatrick child_valobj_sp->GetChildMemberWithName(child_name, true);
2256061da546Spatrick } else {
2257061da546Spatrick child_valobj_sp = root->GetSyntheticValue();
2258061da546Spatrick if (child_valobj_sp.get())
2259061da546Spatrick child_valobj_sp =
2260061da546Spatrick child_valobj_sp->GetChildMemberWithName(child_name, true);
2261061da546Spatrick }
2262061da546Spatrick break;
2263061da546Spatrick }
2264061da546Spatrick }
2265061da546Spatrick
2266061da546Spatrick // if we are here and options.m_no_synthetic_children is true,
2267061da546Spatrick // child_valobj_sp is going to be a NULL SP, so we hit the "else"
2268061da546Spatrick // branch, and return an error
2269061da546Spatrick if (child_valobj_sp.get()) // if it worked, move on
2270061da546Spatrick {
2271061da546Spatrick root = child_valobj_sp;
2272061da546Spatrick remainder = next_separator;
2273061da546Spatrick *final_result = ValueObject::eExpressionPathEndResultTypePlain;
2274061da546Spatrick continue;
2275061da546Spatrick } else {
2276061da546Spatrick *reason_to_stop =
2277061da546Spatrick ValueObject::eExpressionPathScanEndReasonNoSuchChild;
2278061da546Spatrick *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
2279061da546Spatrick return nullptr;
2280061da546Spatrick }
2281061da546Spatrick }
2282061da546Spatrick break;
2283061da546Spatrick }
2284061da546Spatrick case '[': {
2285061da546Spatrick if (!root_compiler_type_info.Test(eTypeIsArray) &&
2286061da546Spatrick !root_compiler_type_info.Test(eTypeIsPointer) &&
2287061da546Spatrick !root_compiler_type_info.Test(
2288061da546Spatrick eTypeIsVector)) // if this is not a T[] nor a T*
2289061da546Spatrick {
2290061da546Spatrick if (!root_compiler_type_info.Test(
2291061da546Spatrick eTypeIsScalar)) // if this is not even a scalar...
2292061da546Spatrick {
2293061da546Spatrick if (options.m_synthetic_children_traversal ==
2294061da546Spatrick GetValueForExpressionPathOptions::SyntheticChildrenTraversal::
2295061da546Spatrick None) // ...only chance left is synthetic
2296061da546Spatrick {
2297061da546Spatrick *reason_to_stop =
2298061da546Spatrick ValueObject::eExpressionPathScanEndReasonRangeOperatorInvalid;
2299061da546Spatrick *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
2300061da546Spatrick return ValueObjectSP();
2301061da546Spatrick }
2302061da546Spatrick } else if (!options.m_allow_bitfields_syntax) // if this is a scalar,
2303061da546Spatrick // check that we can
2304061da546Spatrick // expand bitfields
2305061da546Spatrick {
2306061da546Spatrick *reason_to_stop =
2307061da546Spatrick ValueObject::eExpressionPathScanEndReasonRangeOperatorNotAllowed;
2308061da546Spatrick *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
2309061da546Spatrick return ValueObjectSP();
2310061da546Spatrick }
2311061da546Spatrick }
2312061da546Spatrick if (temp_expression[1] ==
2313061da546Spatrick ']') // if this is an unbounded range it only works for arrays
2314061da546Spatrick {
2315061da546Spatrick if (!root_compiler_type_info.Test(eTypeIsArray)) {
2316061da546Spatrick *reason_to_stop =
2317061da546Spatrick ValueObject::eExpressionPathScanEndReasonEmptyRangeNotAllowed;
2318061da546Spatrick *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
2319061da546Spatrick return nullptr;
2320061da546Spatrick } else // even if something follows, we cannot expand unbounded ranges,
2321061da546Spatrick // just let the caller do it
2322061da546Spatrick {
2323061da546Spatrick *reason_to_stop =
2324061da546Spatrick ValueObject::eExpressionPathScanEndReasonArrayRangeOperatorMet;
2325061da546Spatrick *final_result =
2326061da546Spatrick ValueObject::eExpressionPathEndResultTypeUnboundedRange;
2327061da546Spatrick return root;
2328061da546Spatrick }
2329061da546Spatrick }
2330061da546Spatrick
2331061da546Spatrick size_t close_bracket_position = temp_expression.find(']', 1);
2332061da546Spatrick if (close_bracket_position ==
2333061da546Spatrick llvm::StringRef::npos) // if there is no ], this is a syntax error
2334061da546Spatrick {
2335061da546Spatrick *reason_to_stop =
2336061da546Spatrick ValueObject::eExpressionPathScanEndReasonUnexpectedSymbol;
2337061da546Spatrick *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
2338061da546Spatrick return nullptr;
2339061da546Spatrick }
2340061da546Spatrick
2341061da546Spatrick llvm::StringRef bracket_expr =
2342061da546Spatrick temp_expression.slice(1, close_bracket_position);
2343061da546Spatrick
2344061da546Spatrick // If this was an empty expression it would have been caught by the if
2345061da546Spatrick // above.
2346061da546Spatrick assert(!bracket_expr.empty());
2347061da546Spatrick
2348061da546Spatrick if (!bracket_expr.contains('-')) {
2349061da546Spatrick // if no separator, this is of the form [N]. Note that this cannot be
2350061da546Spatrick // an unbounded range of the form [], because that case was handled
2351061da546Spatrick // above with an unconditional return.
2352061da546Spatrick unsigned long index = 0;
2353061da546Spatrick if (bracket_expr.getAsInteger(0, index)) {
2354061da546Spatrick *reason_to_stop =
2355061da546Spatrick ValueObject::eExpressionPathScanEndReasonUnexpectedSymbol;
2356061da546Spatrick *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
2357061da546Spatrick return nullptr;
2358061da546Spatrick }
2359061da546Spatrick
2360061da546Spatrick // from here on we do have a valid index
2361061da546Spatrick if (root_compiler_type_info.Test(eTypeIsArray)) {
2362061da546Spatrick ValueObjectSP child_valobj_sp = root->GetChildAtIndex(index, true);
2363061da546Spatrick if (!child_valobj_sp)
2364061da546Spatrick child_valobj_sp = root->GetSyntheticArrayMember(index, true);
2365061da546Spatrick if (!child_valobj_sp)
2366061da546Spatrick if (root->HasSyntheticValue() &&
2367061da546Spatrick root->GetSyntheticValue()->GetNumChildren() > index)
2368061da546Spatrick child_valobj_sp =
2369061da546Spatrick root->GetSyntheticValue()->GetChildAtIndex(index, true);
2370061da546Spatrick if (child_valobj_sp) {
2371061da546Spatrick root = child_valobj_sp;
2372061da546Spatrick remainder =
2373061da546Spatrick temp_expression.substr(close_bracket_position + 1); // skip ]
2374061da546Spatrick *final_result = ValueObject::eExpressionPathEndResultTypePlain;
2375061da546Spatrick continue;
2376061da546Spatrick } else {
2377061da546Spatrick *reason_to_stop =
2378061da546Spatrick ValueObject::eExpressionPathScanEndReasonNoSuchChild;
2379061da546Spatrick *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
2380061da546Spatrick return nullptr;
2381061da546Spatrick }
2382061da546Spatrick } else if (root_compiler_type_info.Test(eTypeIsPointer)) {
2383061da546Spatrick if (*what_next ==
2384061da546Spatrick ValueObject::
2385061da546Spatrick eExpressionPathAftermathDereference && // if this is a
2386061da546Spatrick // ptr-to-scalar, I
2387061da546Spatrick // am accessing it
2388061da546Spatrick // by index and I
2389061da546Spatrick // would have
2390061da546Spatrick // deref'ed anyway,
2391061da546Spatrick // then do it now
2392061da546Spatrick // and use this as
2393061da546Spatrick // a bitfield
2394061da546Spatrick pointee_compiler_type_info.Test(eTypeIsScalar)) {
2395061da546Spatrick Status error;
2396061da546Spatrick root = root->Dereference(error);
2397061da546Spatrick if (error.Fail() || !root) {
2398061da546Spatrick *reason_to_stop =
2399061da546Spatrick ValueObject::eExpressionPathScanEndReasonDereferencingFailed;
2400061da546Spatrick *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
2401061da546Spatrick return nullptr;
2402061da546Spatrick } else {
2403061da546Spatrick *what_next = eExpressionPathAftermathNothing;
2404061da546Spatrick continue;
2405061da546Spatrick }
2406061da546Spatrick } else {
2407061da546Spatrick if (root->GetCompilerType().GetMinimumLanguage() ==
2408061da546Spatrick eLanguageTypeObjC &&
2409061da546Spatrick pointee_compiler_type_info.AllClear(eTypeIsPointer) &&
2410061da546Spatrick root->HasSyntheticValue() &&
2411061da546Spatrick (options.m_synthetic_children_traversal ==
2412061da546Spatrick GetValueForExpressionPathOptions::
2413061da546Spatrick SyntheticChildrenTraversal::ToSynthetic ||
2414061da546Spatrick options.m_synthetic_children_traversal ==
2415061da546Spatrick GetValueForExpressionPathOptions::
2416061da546Spatrick SyntheticChildrenTraversal::Both)) {
2417061da546Spatrick root = root->GetSyntheticValue()->GetChildAtIndex(index, true);
2418061da546Spatrick } else
2419061da546Spatrick root = root->GetSyntheticArrayMember(index, true);
2420061da546Spatrick if (!root) {
2421061da546Spatrick *reason_to_stop =
2422061da546Spatrick ValueObject::eExpressionPathScanEndReasonNoSuchChild;
2423061da546Spatrick *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
2424061da546Spatrick return nullptr;
2425061da546Spatrick } else {
2426061da546Spatrick remainder =
2427061da546Spatrick temp_expression.substr(close_bracket_position + 1); // skip ]
2428061da546Spatrick *final_result = ValueObject::eExpressionPathEndResultTypePlain;
2429061da546Spatrick continue;
2430061da546Spatrick }
2431061da546Spatrick }
2432061da546Spatrick } else if (root_compiler_type_info.Test(eTypeIsScalar)) {
2433061da546Spatrick root = root->GetSyntheticBitFieldChild(index, index, true);
2434061da546Spatrick if (!root) {
2435061da546Spatrick *reason_to_stop =
2436061da546Spatrick ValueObject::eExpressionPathScanEndReasonNoSuchChild;
2437061da546Spatrick *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
2438061da546Spatrick return nullptr;
2439061da546Spatrick } else // we do not know how to expand members of bitfields, so we
2440061da546Spatrick // just return and let the caller do any further processing
2441061da546Spatrick {
2442061da546Spatrick *reason_to_stop = ValueObject::
2443061da546Spatrick eExpressionPathScanEndReasonBitfieldRangeOperatorMet;
2444061da546Spatrick *final_result = ValueObject::eExpressionPathEndResultTypeBitfield;
2445061da546Spatrick return root;
2446061da546Spatrick }
2447061da546Spatrick } else if (root_compiler_type_info.Test(eTypeIsVector)) {
2448061da546Spatrick root = root->GetChildAtIndex(index, true);
2449061da546Spatrick if (!root) {
2450061da546Spatrick *reason_to_stop =
2451061da546Spatrick ValueObject::eExpressionPathScanEndReasonNoSuchChild;
2452061da546Spatrick *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
2453061da546Spatrick return ValueObjectSP();
2454061da546Spatrick } else {
2455061da546Spatrick remainder =
2456061da546Spatrick temp_expression.substr(close_bracket_position + 1); // skip ]
2457061da546Spatrick *final_result = ValueObject::eExpressionPathEndResultTypePlain;
2458061da546Spatrick continue;
2459061da546Spatrick }
2460061da546Spatrick } else if (options.m_synthetic_children_traversal ==
2461061da546Spatrick GetValueForExpressionPathOptions::
2462061da546Spatrick SyntheticChildrenTraversal::ToSynthetic ||
2463061da546Spatrick options.m_synthetic_children_traversal ==
2464061da546Spatrick GetValueForExpressionPathOptions::
2465061da546Spatrick SyntheticChildrenTraversal::Both) {
2466061da546Spatrick if (root->HasSyntheticValue())
2467061da546Spatrick root = root->GetSyntheticValue();
2468061da546Spatrick else if (!root->IsSynthetic()) {
2469061da546Spatrick *reason_to_stop =
2470061da546Spatrick ValueObject::eExpressionPathScanEndReasonSyntheticValueMissing;
2471061da546Spatrick *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
2472061da546Spatrick return nullptr;
2473061da546Spatrick }
2474061da546Spatrick // if we are here, then root itself is a synthetic VO.. should be
2475061da546Spatrick // good to go
2476061da546Spatrick
2477061da546Spatrick if (!root) {
2478061da546Spatrick *reason_to_stop =
2479061da546Spatrick ValueObject::eExpressionPathScanEndReasonSyntheticValueMissing;
2480061da546Spatrick *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
2481061da546Spatrick return nullptr;
2482061da546Spatrick }
2483061da546Spatrick root = root->GetChildAtIndex(index, true);
2484061da546Spatrick if (!root) {
2485061da546Spatrick *reason_to_stop =
2486061da546Spatrick ValueObject::eExpressionPathScanEndReasonNoSuchChild;
2487061da546Spatrick *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
2488061da546Spatrick return nullptr;
2489061da546Spatrick } else {
2490061da546Spatrick remainder =
2491061da546Spatrick temp_expression.substr(close_bracket_position + 1); // skip ]
2492061da546Spatrick *final_result = ValueObject::eExpressionPathEndResultTypePlain;
2493061da546Spatrick continue;
2494061da546Spatrick }
2495061da546Spatrick } else {
2496061da546Spatrick *reason_to_stop =
2497061da546Spatrick ValueObject::eExpressionPathScanEndReasonNoSuchChild;
2498061da546Spatrick *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
2499061da546Spatrick return nullptr;
2500061da546Spatrick }
2501061da546Spatrick } else {
2502061da546Spatrick // we have a low and a high index
2503061da546Spatrick llvm::StringRef sleft, sright;
2504061da546Spatrick unsigned long low_index, high_index;
2505061da546Spatrick std::tie(sleft, sright) = bracket_expr.split('-');
2506061da546Spatrick if (sleft.getAsInteger(0, low_index) ||
2507061da546Spatrick sright.getAsInteger(0, high_index)) {
2508061da546Spatrick *reason_to_stop =
2509061da546Spatrick ValueObject::eExpressionPathScanEndReasonUnexpectedSymbol;
2510061da546Spatrick *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
2511061da546Spatrick return nullptr;
2512061da546Spatrick }
2513061da546Spatrick
2514061da546Spatrick if (low_index > high_index) // swap indices if required
2515061da546Spatrick std::swap(low_index, high_index);
2516061da546Spatrick
2517061da546Spatrick if (root_compiler_type_info.Test(
2518061da546Spatrick eTypeIsScalar)) // expansion only works for scalars
2519061da546Spatrick {
2520061da546Spatrick root = root->GetSyntheticBitFieldChild(low_index, high_index, true);
2521061da546Spatrick if (!root) {
2522061da546Spatrick *reason_to_stop =
2523061da546Spatrick ValueObject::eExpressionPathScanEndReasonNoSuchChild;
2524061da546Spatrick *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
2525061da546Spatrick return nullptr;
2526061da546Spatrick } else {
2527061da546Spatrick *reason_to_stop = ValueObject::
2528061da546Spatrick eExpressionPathScanEndReasonBitfieldRangeOperatorMet;
2529061da546Spatrick *final_result = ValueObject::eExpressionPathEndResultTypeBitfield;
2530061da546Spatrick return root;
2531061da546Spatrick }
2532061da546Spatrick } else if (root_compiler_type_info.Test(
2533061da546Spatrick eTypeIsPointer) && // if this is a ptr-to-scalar, I am
2534061da546Spatrick // accessing it by index and I would
2535061da546Spatrick // have deref'ed anyway, then do it
2536061da546Spatrick // now and use this as a bitfield
2537061da546Spatrick *what_next ==
2538061da546Spatrick ValueObject::eExpressionPathAftermathDereference &&
2539061da546Spatrick pointee_compiler_type_info.Test(eTypeIsScalar)) {
2540061da546Spatrick Status error;
2541061da546Spatrick root = root->Dereference(error);
2542061da546Spatrick if (error.Fail() || !root) {
2543061da546Spatrick *reason_to_stop =
2544061da546Spatrick ValueObject::eExpressionPathScanEndReasonDereferencingFailed;
2545061da546Spatrick *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
2546061da546Spatrick return nullptr;
2547061da546Spatrick } else {
2548061da546Spatrick *what_next = ValueObject::eExpressionPathAftermathNothing;
2549061da546Spatrick continue;
2550061da546Spatrick }
2551061da546Spatrick } else {
2552061da546Spatrick *reason_to_stop =
2553061da546Spatrick ValueObject::eExpressionPathScanEndReasonArrayRangeOperatorMet;
2554061da546Spatrick *final_result = ValueObject::eExpressionPathEndResultTypeBoundedRange;
2555061da546Spatrick return root;
2556061da546Spatrick }
2557061da546Spatrick }
2558061da546Spatrick break;
2559061da546Spatrick }
2560061da546Spatrick default: // some non-separator is in the way
2561061da546Spatrick {
2562061da546Spatrick *reason_to_stop =
2563061da546Spatrick ValueObject::eExpressionPathScanEndReasonUnexpectedSymbol;
2564061da546Spatrick *final_result = ValueObject::eExpressionPathEndResultTypeInvalid;
2565061da546Spatrick return nullptr;
2566061da546Spatrick }
2567061da546Spatrick }
2568061da546Spatrick }
2569061da546Spatrick }
2570061da546Spatrick
Dump(Stream & s)2571061da546Spatrick void ValueObject::Dump(Stream &s) { Dump(s, DumpValueObjectOptions(*this)); }
2572061da546Spatrick
Dump(Stream & s,const DumpValueObjectOptions & options)2573061da546Spatrick void ValueObject::Dump(Stream &s, const DumpValueObjectOptions &options) {
2574061da546Spatrick ValueObjectPrinter printer(this, &s, options);
2575061da546Spatrick printer.PrintValueObject();
2576061da546Spatrick }
2577061da546Spatrick
CreateConstantValue(ConstString name)2578061da546Spatrick ValueObjectSP ValueObject::CreateConstantValue(ConstString name) {
2579061da546Spatrick ValueObjectSP valobj_sp;
2580061da546Spatrick
2581061da546Spatrick if (UpdateValueIfNeeded(false) && m_error.Success()) {
2582061da546Spatrick ExecutionContext exe_ctx(GetExecutionContextRef());
2583061da546Spatrick
2584061da546Spatrick DataExtractor data;
2585061da546Spatrick data.SetByteOrder(m_data.GetByteOrder());
2586061da546Spatrick data.SetAddressByteSize(m_data.GetAddressByteSize());
2587061da546Spatrick
2588061da546Spatrick if (IsBitfield()) {
2589061da546Spatrick Value v(Scalar(GetValueAsUnsigned(UINT64_MAX)));
2590061da546Spatrick m_error = v.GetValueAsData(&exe_ctx, data, GetModule().get());
2591061da546Spatrick } else
2592061da546Spatrick m_error = m_value.GetValueAsData(&exe_ctx, data, GetModule().get());
2593061da546Spatrick
2594061da546Spatrick valobj_sp = ValueObjectConstResult::Create(
2595061da546Spatrick exe_ctx.GetBestExecutionContextScope(), GetCompilerType(), name, data,
2596061da546Spatrick GetAddressOf());
2597061da546Spatrick }
2598061da546Spatrick
2599061da546Spatrick if (!valobj_sp) {
2600061da546Spatrick ExecutionContext exe_ctx(GetExecutionContextRef());
2601061da546Spatrick valobj_sp = ValueObjectConstResult::Create(
2602061da546Spatrick exe_ctx.GetBestExecutionContextScope(), m_error);
2603061da546Spatrick }
2604061da546Spatrick return valobj_sp;
2605061da546Spatrick }
2606061da546Spatrick
GetQualifiedRepresentationIfAvailable(lldb::DynamicValueType dynValue,bool synthValue)2607061da546Spatrick ValueObjectSP ValueObject::GetQualifiedRepresentationIfAvailable(
2608061da546Spatrick lldb::DynamicValueType dynValue, bool synthValue) {
2609061da546Spatrick ValueObjectSP result_sp(GetSP());
2610061da546Spatrick
2611061da546Spatrick switch (dynValue) {
2612061da546Spatrick case lldb::eDynamicCanRunTarget:
2613061da546Spatrick case lldb::eDynamicDontRunTarget: {
2614061da546Spatrick if (!result_sp->IsDynamic()) {
2615061da546Spatrick if (result_sp->GetDynamicValue(dynValue))
2616061da546Spatrick result_sp = result_sp->GetDynamicValue(dynValue);
2617061da546Spatrick }
2618061da546Spatrick } break;
2619061da546Spatrick case lldb::eNoDynamicValues: {
2620061da546Spatrick if (result_sp->IsDynamic()) {
2621061da546Spatrick if (result_sp->GetStaticValue())
2622061da546Spatrick result_sp = result_sp->GetStaticValue();
2623061da546Spatrick }
2624061da546Spatrick } break;
2625061da546Spatrick }
2626061da546Spatrick
2627061da546Spatrick if (synthValue) {
2628061da546Spatrick if (!result_sp->IsSynthetic()) {
2629061da546Spatrick if (result_sp->GetSyntheticValue())
2630061da546Spatrick result_sp = result_sp->GetSyntheticValue();
2631061da546Spatrick }
2632061da546Spatrick } else {
2633061da546Spatrick if (result_sp->IsSynthetic()) {
2634061da546Spatrick if (result_sp->GetNonSyntheticValue())
2635061da546Spatrick result_sp = result_sp->GetNonSyntheticValue();
2636061da546Spatrick }
2637061da546Spatrick }
2638061da546Spatrick
2639061da546Spatrick return result_sp;
2640061da546Spatrick }
2641061da546Spatrick
Dereference(Status & error)2642061da546Spatrick ValueObjectSP ValueObject::Dereference(Status &error) {
2643061da546Spatrick if (m_deref_valobj)
2644061da546Spatrick return m_deref_valobj->GetSP();
2645061da546Spatrick
2646061da546Spatrick const bool is_pointer_or_reference_type = IsPointerOrReferenceType();
2647061da546Spatrick if (is_pointer_or_reference_type) {
2648061da546Spatrick bool omit_empty_base_classes = true;
2649061da546Spatrick bool ignore_array_bounds = false;
2650061da546Spatrick
2651061da546Spatrick std::string child_name_str;
2652061da546Spatrick uint32_t child_byte_size = 0;
2653061da546Spatrick int32_t child_byte_offset = 0;
2654061da546Spatrick uint32_t child_bitfield_bit_size = 0;
2655061da546Spatrick uint32_t child_bitfield_bit_offset = 0;
2656061da546Spatrick bool child_is_base_class = false;
2657061da546Spatrick bool child_is_deref_of_parent = false;
2658061da546Spatrick const bool transparent_pointers = false;
2659061da546Spatrick CompilerType compiler_type = GetCompilerType();
2660061da546Spatrick CompilerType child_compiler_type;
2661dda28197Spatrick uint64_t language_flags = 0;
2662061da546Spatrick
2663061da546Spatrick ExecutionContext exe_ctx(GetExecutionContextRef());
2664061da546Spatrick
2665061da546Spatrick child_compiler_type = compiler_type.GetChildCompilerTypeAtIndex(
2666061da546Spatrick &exe_ctx, 0, transparent_pointers, omit_empty_base_classes,
2667061da546Spatrick ignore_array_bounds, child_name_str, child_byte_size, child_byte_offset,
2668061da546Spatrick child_bitfield_bit_size, child_bitfield_bit_offset, child_is_base_class,
2669061da546Spatrick child_is_deref_of_parent, this, language_flags);
2670061da546Spatrick if (child_compiler_type && child_byte_size) {
2671061da546Spatrick ConstString child_name;
2672061da546Spatrick if (!child_name_str.empty())
2673061da546Spatrick child_name.SetCString(child_name_str.c_str());
2674061da546Spatrick
2675061da546Spatrick m_deref_valobj = new ValueObjectChild(
2676061da546Spatrick *this, child_compiler_type, child_name, child_byte_size,
2677061da546Spatrick child_byte_offset, child_bitfield_bit_size, child_bitfield_bit_offset,
2678061da546Spatrick child_is_base_class, child_is_deref_of_parent, eAddressTypeInvalid,
2679061da546Spatrick language_flags);
2680061da546Spatrick }
2681dda28197Spatrick
2682dda28197Spatrick // In case of incomplete child compiler type, use the pointee type and try
2683dda28197Spatrick // to recreate a new ValueObjectChild using it.
2684dda28197Spatrick if (!m_deref_valobj) {
2685*f6aab3d8Srobert // FIXME(#59012): C++ stdlib formatters break with incomplete types (e.g.
2686*f6aab3d8Srobert // `std::vector<int> &`). Remove ObjC restriction once that's resolved.
2687*f6aab3d8Srobert if (Language::LanguageIsObjC(GetPreferredDisplayLanguage()) &&
2688*f6aab3d8Srobert HasSyntheticValue()) {
2689dda28197Spatrick child_compiler_type = compiler_type.GetPointeeType();
2690dda28197Spatrick
2691dda28197Spatrick if (child_compiler_type) {
2692dda28197Spatrick ConstString child_name;
2693dda28197Spatrick if (!child_name_str.empty())
2694dda28197Spatrick child_name.SetCString(child_name_str.c_str());
2695dda28197Spatrick
2696dda28197Spatrick m_deref_valobj = new ValueObjectChild(
2697dda28197Spatrick *this, child_compiler_type, child_name, child_byte_size,
2698dda28197Spatrick child_byte_offset, child_bitfield_bit_size,
2699dda28197Spatrick child_bitfield_bit_offset, child_is_base_class,
2700dda28197Spatrick child_is_deref_of_parent, eAddressTypeInvalid, language_flags);
2701dda28197Spatrick }
2702dda28197Spatrick }
2703dda28197Spatrick }
2704dda28197Spatrick
2705061da546Spatrick } else if (HasSyntheticValue()) {
2706061da546Spatrick m_deref_valobj =
2707061da546Spatrick GetSyntheticValue()
2708061da546Spatrick ->GetChildMemberWithName(ConstString("$$dereference$$"), true)
2709061da546Spatrick .get();
2710dda28197Spatrick } else if (IsSynthetic()) {
2711dda28197Spatrick m_deref_valobj =
2712dda28197Spatrick GetChildMemberWithName(ConstString("$$dereference$$"), true).get();
2713061da546Spatrick }
2714061da546Spatrick
2715061da546Spatrick if (m_deref_valobj) {
2716061da546Spatrick error.Clear();
2717061da546Spatrick return m_deref_valobj->GetSP();
2718061da546Spatrick } else {
2719061da546Spatrick StreamString strm;
2720dda28197Spatrick GetExpressionPath(strm);
2721061da546Spatrick
2722061da546Spatrick if (is_pointer_or_reference_type)
2723061da546Spatrick error.SetErrorStringWithFormat("dereference failed: (%s) %s",
2724061da546Spatrick GetTypeName().AsCString("<invalid type>"),
2725061da546Spatrick strm.GetData());
2726061da546Spatrick else
2727061da546Spatrick error.SetErrorStringWithFormat("not a pointer or reference type: (%s) %s",
2728061da546Spatrick GetTypeName().AsCString("<invalid type>"),
2729061da546Spatrick strm.GetData());
2730061da546Spatrick return ValueObjectSP();
2731061da546Spatrick }
2732061da546Spatrick }
2733061da546Spatrick
AddressOf(Status & error)2734061da546Spatrick ValueObjectSP ValueObject::AddressOf(Status &error) {
2735061da546Spatrick if (m_addr_of_valobj_sp)
2736061da546Spatrick return m_addr_of_valobj_sp;
2737061da546Spatrick
2738061da546Spatrick AddressType address_type = eAddressTypeInvalid;
2739061da546Spatrick const bool scalar_is_load_address = false;
2740061da546Spatrick addr_t addr = GetAddressOf(scalar_is_load_address, &address_type);
2741061da546Spatrick error.Clear();
2742061da546Spatrick if (addr != LLDB_INVALID_ADDRESS && address_type != eAddressTypeHost) {
2743061da546Spatrick switch (address_type) {
2744061da546Spatrick case eAddressTypeInvalid: {
2745061da546Spatrick StreamString expr_path_strm;
2746dda28197Spatrick GetExpressionPath(expr_path_strm);
2747061da546Spatrick error.SetErrorStringWithFormat("'%s' is not in memory",
2748061da546Spatrick expr_path_strm.GetData());
2749061da546Spatrick } break;
2750061da546Spatrick
2751061da546Spatrick case eAddressTypeFile:
2752061da546Spatrick case eAddressTypeLoad: {
2753061da546Spatrick CompilerType compiler_type = GetCompilerType();
2754061da546Spatrick if (compiler_type) {
2755061da546Spatrick std::string name(1, '&');
2756061da546Spatrick name.append(m_name.AsCString(""));
2757061da546Spatrick ExecutionContext exe_ctx(GetExecutionContextRef());
2758061da546Spatrick m_addr_of_valobj_sp = ValueObjectConstResult::Create(
2759061da546Spatrick exe_ctx.GetBestExecutionContextScope(),
2760061da546Spatrick compiler_type.GetPointerType(), ConstString(name.c_str()), addr,
2761061da546Spatrick eAddressTypeInvalid, m_data.GetAddressByteSize());
2762061da546Spatrick }
2763061da546Spatrick } break;
2764061da546Spatrick default:
2765061da546Spatrick break;
2766061da546Spatrick }
2767061da546Spatrick } else {
2768061da546Spatrick StreamString expr_path_strm;
2769dda28197Spatrick GetExpressionPath(expr_path_strm);
2770061da546Spatrick error.SetErrorStringWithFormat("'%s' doesn't have a valid address",
2771061da546Spatrick expr_path_strm.GetData());
2772061da546Spatrick }
2773061da546Spatrick
2774061da546Spatrick return m_addr_of_valobj_sp;
2775061da546Spatrick }
2776061da546Spatrick
Cast(const CompilerType & compiler_type)2777061da546Spatrick ValueObjectSP ValueObject::Cast(const CompilerType &compiler_type) {
2778061da546Spatrick return ValueObjectCast::Create(*this, GetName(), compiler_type);
2779061da546Spatrick }
2780061da546Spatrick
Clone(ConstString new_name)2781061da546Spatrick lldb::ValueObjectSP ValueObject::Clone(ConstString new_name) {
2782061da546Spatrick return ValueObjectCast::Create(*this, new_name, GetCompilerType());
2783061da546Spatrick }
2784061da546Spatrick
CastPointerType(const char * name,CompilerType & compiler_type)2785061da546Spatrick ValueObjectSP ValueObject::CastPointerType(const char *name,
2786061da546Spatrick CompilerType &compiler_type) {
2787061da546Spatrick ValueObjectSP valobj_sp;
2788061da546Spatrick AddressType address_type;
2789061da546Spatrick addr_t ptr_value = GetPointerValue(&address_type);
2790061da546Spatrick
2791061da546Spatrick if (ptr_value != LLDB_INVALID_ADDRESS) {
2792061da546Spatrick Address ptr_addr(ptr_value);
2793061da546Spatrick ExecutionContext exe_ctx(GetExecutionContextRef());
2794061da546Spatrick valobj_sp = ValueObjectMemory::Create(
2795061da546Spatrick exe_ctx.GetBestExecutionContextScope(), name, ptr_addr, compiler_type);
2796061da546Spatrick }
2797061da546Spatrick return valobj_sp;
2798061da546Spatrick }
2799061da546Spatrick
CastPointerType(const char * name,TypeSP & type_sp)2800061da546Spatrick ValueObjectSP ValueObject::CastPointerType(const char *name, TypeSP &type_sp) {
2801061da546Spatrick ValueObjectSP valobj_sp;
2802061da546Spatrick AddressType address_type;
2803061da546Spatrick addr_t ptr_value = GetPointerValue(&address_type);
2804061da546Spatrick
2805061da546Spatrick if (ptr_value != LLDB_INVALID_ADDRESS) {
2806061da546Spatrick Address ptr_addr(ptr_value);
2807061da546Spatrick ExecutionContext exe_ctx(GetExecutionContextRef());
2808061da546Spatrick valobj_sp = ValueObjectMemory::Create(
2809061da546Spatrick exe_ctx.GetBestExecutionContextScope(), name, ptr_addr, type_sp);
2810061da546Spatrick }
2811061da546Spatrick return valobj_sp;
2812061da546Spatrick }
2813061da546Spatrick
EvaluationPoint()2814be691f3bSpatrick ValueObject::EvaluationPoint::EvaluationPoint() : m_mod_id(), m_exe_ctx_ref() {}
2815061da546Spatrick
EvaluationPoint(ExecutionContextScope * exe_scope,bool use_selected)2816061da546Spatrick ValueObject::EvaluationPoint::EvaluationPoint(ExecutionContextScope *exe_scope,
2817061da546Spatrick bool use_selected)
2818*f6aab3d8Srobert : m_mod_id(), m_exe_ctx_ref() {
2819061da546Spatrick ExecutionContext exe_ctx(exe_scope);
2820061da546Spatrick TargetSP target_sp(exe_ctx.GetTargetSP());
2821061da546Spatrick if (target_sp) {
2822061da546Spatrick m_exe_ctx_ref.SetTargetSP(target_sp);
2823061da546Spatrick ProcessSP process_sp(exe_ctx.GetProcessSP());
2824061da546Spatrick if (!process_sp)
2825061da546Spatrick process_sp = target_sp->GetProcessSP();
2826061da546Spatrick
2827061da546Spatrick if (process_sp) {
2828061da546Spatrick m_mod_id = process_sp->GetModID();
2829061da546Spatrick m_exe_ctx_ref.SetProcessSP(process_sp);
2830061da546Spatrick
2831061da546Spatrick ThreadSP thread_sp(exe_ctx.GetThreadSP());
2832061da546Spatrick
2833061da546Spatrick if (!thread_sp) {
2834061da546Spatrick if (use_selected)
2835061da546Spatrick thread_sp = process_sp->GetThreadList().GetSelectedThread();
2836061da546Spatrick }
2837061da546Spatrick
2838061da546Spatrick if (thread_sp) {
2839061da546Spatrick m_exe_ctx_ref.SetThreadSP(thread_sp);
2840061da546Spatrick
2841061da546Spatrick StackFrameSP frame_sp(exe_ctx.GetFrameSP());
2842061da546Spatrick if (!frame_sp) {
2843061da546Spatrick if (use_selected)
2844061da546Spatrick frame_sp = thread_sp->GetSelectedFrame();
2845061da546Spatrick }
2846061da546Spatrick if (frame_sp)
2847061da546Spatrick m_exe_ctx_ref.SetFrameSP(frame_sp);
2848061da546Spatrick }
2849061da546Spatrick }
2850061da546Spatrick }
2851061da546Spatrick }
2852061da546Spatrick
EvaluationPoint(const ValueObject::EvaluationPoint & rhs)2853061da546Spatrick ValueObject::EvaluationPoint::EvaluationPoint(
2854061da546Spatrick const ValueObject::EvaluationPoint &rhs)
2855*f6aab3d8Srobert : m_mod_id(), m_exe_ctx_ref(rhs.m_exe_ctx_ref) {}
2856061da546Spatrick
2857be691f3bSpatrick ValueObject::EvaluationPoint::~EvaluationPoint() = default;
2858061da546Spatrick
2859061da546Spatrick // This function checks the EvaluationPoint against the current process state.
2860061da546Spatrick // If the current state matches the evaluation point, or the evaluation point
2861061da546Spatrick // is already invalid, then we return false, meaning "no change". If the
2862061da546Spatrick // current state is different, we update our state, and return true meaning
2863061da546Spatrick // "yes, change". If we did see a change, we also set m_needs_update to true,
2864061da546Spatrick // so future calls to NeedsUpdate will return true. exe_scope will be set to
2865061da546Spatrick // the current execution context scope.
2866061da546Spatrick
SyncWithProcessState(bool accept_invalid_exe_ctx)2867061da546Spatrick bool ValueObject::EvaluationPoint::SyncWithProcessState(
2868061da546Spatrick bool accept_invalid_exe_ctx) {
2869061da546Spatrick // Start with the target, if it is NULL, then we're obviously not going to
2870061da546Spatrick // get any further:
2871061da546Spatrick const bool thread_and_frame_only_if_stopped = true;
2872061da546Spatrick ExecutionContext exe_ctx(
2873061da546Spatrick m_exe_ctx_ref.Lock(thread_and_frame_only_if_stopped));
2874061da546Spatrick
2875061da546Spatrick if (exe_ctx.GetTargetPtr() == nullptr)
2876061da546Spatrick return false;
2877061da546Spatrick
2878061da546Spatrick // If we don't have a process nothing can change.
2879061da546Spatrick Process *process = exe_ctx.GetProcessPtr();
2880061da546Spatrick if (process == nullptr)
2881061da546Spatrick return false;
2882061da546Spatrick
2883061da546Spatrick // If our stop id is the current stop ID, nothing has changed:
2884061da546Spatrick ProcessModID current_mod_id = process->GetModID();
2885061da546Spatrick
2886061da546Spatrick // If the current stop id is 0, either we haven't run yet, or the process
2887061da546Spatrick // state has been cleared. In either case, we aren't going to be able to sync
2888061da546Spatrick // with the process state.
2889061da546Spatrick if (current_mod_id.GetStopID() == 0)
2890061da546Spatrick return false;
2891061da546Spatrick
2892061da546Spatrick bool changed = false;
2893061da546Spatrick const bool was_valid = m_mod_id.IsValid();
2894061da546Spatrick if (was_valid) {
2895061da546Spatrick if (m_mod_id == current_mod_id) {
2896061da546Spatrick // Everything is already up to date in this object, no need to update the
2897061da546Spatrick // execution context scope.
2898061da546Spatrick changed = false;
2899061da546Spatrick } else {
2900061da546Spatrick m_mod_id = current_mod_id;
2901061da546Spatrick m_needs_update = true;
2902061da546Spatrick changed = true;
2903061da546Spatrick }
2904061da546Spatrick }
2905061da546Spatrick
2906061da546Spatrick // Now re-look up the thread and frame in case the underlying objects have
2907061da546Spatrick // gone away & been recreated. That way we'll be sure to return a valid
2908061da546Spatrick // exe_scope. If we used to have a thread or a frame but can't find it
2909061da546Spatrick // anymore, then mark ourselves as invalid.
2910061da546Spatrick
2911061da546Spatrick if (!accept_invalid_exe_ctx) {
2912061da546Spatrick if (m_exe_ctx_ref.HasThreadRef()) {
2913061da546Spatrick ThreadSP thread_sp(m_exe_ctx_ref.GetThreadSP());
2914061da546Spatrick if (thread_sp) {
2915061da546Spatrick if (m_exe_ctx_ref.HasFrameRef()) {
2916061da546Spatrick StackFrameSP frame_sp(m_exe_ctx_ref.GetFrameSP());
2917061da546Spatrick if (!frame_sp) {
2918061da546Spatrick // We used to have a frame, but now it is gone
2919061da546Spatrick SetInvalid();
2920061da546Spatrick changed = was_valid;
2921061da546Spatrick }
2922061da546Spatrick }
2923061da546Spatrick } else {
2924061da546Spatrick // We used to have a thread, but now it is gone
2925061da546Spatrick SetInvalid();
2926061da546Spatrick changed = was_valid;
2927061da546Spatrick }
2928061da546Spatrick }
2929061da546Spatrick }
2930061da546Spatrick
2931061da546Spatrick return changed;
2932061da546Spatrick }
2933061da546Spatrick
SetUpdated()2934061da546Spatrick void ValueObject::EvaluationPoint::SetUpdated() {
2935061da546Spatrick ProcessSP process_sp(m_exe_ctx_ref.GetProcessSP());
2936061da546Spatrick if (process_sp)
2937061da546Spatrick m_mod_id = process_sp->GetModID();
2938061da546Spatrick m_needs_update = false;
2939061da546Spatrick }
2940061da546Spatrick
ClearUserVisibleData(uint32_t clear_mask)2941061da546Spatrick void ValueObject::ClearUserVisibleData(uint32_t clear_mask) {
2942061da546Spatrick if ((clear_mask & eClearUserVisibleDataItemsValue) ==
2943061da546Spatrick eClearUserVisibleDataItemsValue)
2944061da546Spatrick m_value_str.clear();
2945061da546Spatrick
2946061da546Spatrick if ((clear_mask & eClearUserVisibleDataItemsLocation) ==
2947061da546Spatrick eClearUserVisibleDataItemsLocation)
2948061da546Spatrick m_location_str.clear();
2949061da546Spatrick
2950061da546Spatrick if ((clear_mask & eClearUserVisibleDataItemsSummary) ==
2951061da546Spatrick eClearUserVisibleDataItemsSummary)
2952061da546Spatrick m_summary_str.clear();
2953061da546Spatrick
2954061da546Spatrick if ((clear_mask & eClearUserVisibleDataItemsDescription) ==
2955061da546Spatrick eClearUserVisibleDataItemsDescription)
2956061da546Spatrick m_object_desc_str.clear();
2957061da546Spatrick
2958061da546Spatrick if ((clear_mask & eClearUserVisibleDataItemsSyntheticChildren) ==
2959061da546Spatrick eClearUserVisibleDataItemsSyntheticChildren) {
2960061da546Spatrick if (m_synthetic_value)
2961061da546Spatrick m_synthetic_value = nullptr;
2962061da546Spatrick }
2963061da546Spatrick }
2964061da546Spatrick
GetSymbolContextScope()2965061da546Spatrick SymbolContextScope *ValueObject::GetSymbolContextScope() {
2966061da546Spatrick if (m_parent) {
2967061da546Spatrick if (!m_parent->IsPointerOrReferenceType())
2968061da546Spatrick return m_parent->GetSymbolContextScope();
2969061da546Spatrick }
2970061da546Spatrick return nullptr;
2971061da546Spatrick }
2972061da546Spatrick
2973061da546Spatrick lldb::ValueObjectSP
CreateValueObjectFromExpression(llvm::StringRef name,llvm::StringRef expression,const ExecutionContext & exe_ctx)2974061da546Spatrick ValueObject::CreateValueObjectFromExpression(llvm::StringRef name,
2975061da546Spatrick llvm::StringRef expression,
2976061da546Spatrick const ExecutionContext &exe_ctx) {
2977061da546Spatrick return CreateValueObjectFromExpression(name, expression, exe_ctx,
2978061da546Spatrick EvaluateExpressionOptions());
2979061da546Spatrick }
2980061da546Spatrick
CreateValueObjectFromExpression(llvm::StringRef name,llvm::StringRef expression,const ExecutionContext & exe_ctx,const EvaluateExpressionOptions & options)2981061da546Spatrick lldb::ValueObjectSP ValueObject::CreateValueObjectFromExpression(
2982061da546Spatrick llvm::StringRef name, llvm::StringRef expression,
2983061da546Spatrick const ExecutionContext &exe_ctx, const EvaluateExpressionOptions &options) {
2984061da546Spatrick lldb::ValueObjectSP retval_sp;
2985061da546Spatrick lldb::TargetSP target_sp(exe_ctx.GetTargetSP());
2986061da546Spatrick if (!target_sp)
2987061da546Spatrick return retval_sp;
2988061da546Spatrick if (expression.empty())
2989061da546Spatrick return retval_sp;
2990061da546Spatrick target_sp->EvaluateExpression(expression, exe_ctx.GetFrameSP().get(),
2991061da546Spatrick retval_sp, options);
2992061da546Spatrick if (retval_sp && !name.empty())
2993061da546Spatrick retval_sp->SetName(ConstString(name));
2994061da546Spatrick return retval_sp;
2995061da546Spatrick }
2996061da546Spatrick
CreateValueObjectFromAddress(llvm::StringRef name,uint64_t address,const ExecutionContext & exe_ctx,CompilerType type)2997061da546Spatrick lldb::ValueObjectSP ValueObject::CreateValueObjectFromAddress(
2998061da546Spatrick llvm::StringRef name, uint64_t address, const ExecutionContext &exe_ctx,
2999061da546Spatrick CompilerType type) {
3000061da546Spatrick if (type) {
3001061da546Spatrick CompilerType pointer_type(type.GetPointerType());
3002061da546Spatrick if (pointer_type) {
3003061da546Spatrick lldb::DataBufferSP buffer(
3004061da546Spatrick new lldb_private::DataBufferHeap(&address, sizeof(lldb::addr_t)));
3005061da546Spatrick lldb::ValueObjectSP ptr_result_valobj_sp(ValueObjectConstResult::Create(
3006061da546Spatrick exe_ctx.GetBestExecutionContextScope(), pointer_type,
3007061da546Spatrick ConstString(name), buffer, exe_ctx.GetByteOrder(),
3008061da546Spatrick exe_ctx.GetAddressByteSize()));
3009061da546Spatrick if (ptr_result_valobj_sp) {
3010061da546Spatrick ptr_result_valobj_sp->GetValue().SetValueType(
3011be691f3bSpatrick Value::ValueType::LoadAddress);
3012061da546Spatrick Status err;
3013061da546Spatrick ptr_result_valobj_sp = ptr_result_valobj_sp->Dereference(err);
3014061da546Spatrick if (ptr_result_valobj_sp && !name.empty())
3015061da546Spatrick ptr_result_valobj_sp->SetName(ConstString(name));
3016061da546Spatrick }
3017061da546Spatrick return ptr_result_valobj_sp;
3018061da546Spatrick }
3019061da546Spatrick }
3020061da546Spatrick return lldb::ValueObjectSP();
3021061da546Spatrick }
3022061da546Spatrick
CreateValueObjectFromData(llvm::StringRef name,const DataExtractor & data,const ExecutionContext & exe_ctx,CompilerType type)3023061da546Spatrick lldb::ValueObjectSP ValueObject::CreateValueObjectFromData(
3024061da546Spatrick llvm::StringRef name, const DataExtractor &data,
3025061da546Spatrick const ExecutionContext &exe_ctx, CompilerType type) {
3026061da546Spatrick lldb::ValueObjectSP new_value_sp;
3027061da546Spatrick new_value_sp = ValueObjectConstResult::Create(
3028061da546Spatrick exe_ctx.GetBestExecutionContextScope(), type, ConstString(name), data,
3029061da546Spatrick LLDB_INVALID_ADDRESS);
3030061da546Spatrick new_value_sp->SetAddressTypeOfChildren(eAddressTypeLoad);
3031061da546Spatrick if (new_value_sp && !name.empty())
3032061da546Spatrick new_value_sp->SetName(ConstString(name));
3033061da546Spatrick return new_value_sp;
3034061da546Spatrick }
3035061da546Spatrick
GetModule()3036061da546Spatrick ModuleSP ValueObject::GetModule() {
3037061da546Spatrick ValueObject *root(GetRoot());
3038061da546Spatrick if (root != this)
3039061da546Spatrick return root->GetModule();
3040061da546Spatrick return lldb::ModuleSP();
3041061da546Spatrick }
3042061da546Spatrick
GetRoot()3043061da546Spatrick ValueObject *ValueObject::GetRoot() {
3044061da546Spatrick if (m_root)
3045061da546Spatrick return m_root;
3046061da546Spatrick return (m_root = FollowParentChain([](ValueObject *vo) -> bool {
3047061da546Spatrick return (vo->m_parent != nullptr);
3048061da546Spatrick }));
3049061da546Spatrick }
3050061da546Spatrick
3051061da546Spatrick ValueObject *
FollowParentChain(std::function<bool (ValueObject *)> f)3052061da546Spatrick ValueObject::FollowParentChain(std::function<bool(ValueObject *)> f) {
3053061da546Spatrick ValueObject *vo = this;
3054061da546Spatrick while (vo) {
3055061da546Spatrick if (!f(vo))
3056061da546Spatrick break;
3057061da546Spatrick vo = vo->m_parent;
3058061da546Spatrick }
3059061da546Spatrick return vo;
3060061da546Spatrick }
3061061da546Spatrick
GetAddressTypeOfChildren()3062061da546Spatrick AddressType ValueObject::GetAddressTypeOfChildren() {
3063061da546Spatrick if (m_address_type_of_ptr_or_ref_children == eAddressTypeInvalid) {
3064061da546Spatrick ValueObject *root(GetRoot());
3065061da546Spatrick if (root != this)
3066061da546Spatrick return root->GetAddressTypeOfChildren();
3067061da546Spatrick }
3068061da546Spatrick return m_address_type_of_ptr_or_ref_children;
3069061da546Spatrick }
3070061da546Spatrick
GetDynamicValueType()3071061da546Spatrick lldb::DynamicValueType ValueObject::GetDynamicValueType() {
3072061da546Spatrick ValueObject *with_dv_info = this;
3073061da546Spatrick while (with_dv_info) {
3074061da546Spatrick if (with_dv_info->HasDynamicValueTypeInfo())
3075061da546Spatrick return with_dv_info->GetDynamicValueTypeImpl();
3076061da546Spatrick with_dv_info = with_dv_info->m_parent;
3077061da546Spatrick }
3078061da546Spatrick return lldb::eNoDynamicValues;
3079061da546Spatrick }
3080061da546Spatrick
GetFormat() const3081061da546Spatrick lldb::Format ValueObject::GetFormat() const {
3082061da546Spatrick const ValueObject *with_fmt_info = this;
3083061da546Spatrick while (with_fmt_info) {
3084061da546Spatrick if (with_fmt_info->m_format != lldb::eFormatDefault)
3085061da546Spatrick return with_fmt_info->m_format;
3086061da546Spatrick with_fmt_info = with_fmt_info->m_parent;
3087061da546Spatrick }
3088061da546Spatrick return m_format;
3089061da546Spatrick }
3090061da546Spatrick
GetPreferredDisplayLanguage()3091061da546Spatrick lldb::LanguageType ValueObject::GetPreferredDisplayLanguage() {
3092061da546Spatrick lldb::LanguageType type = m_preferred_display_language;
3093061da546Spatrick if (m_preferred_display_language == lldb::eLanguageTypeUnknown) {
3094061da546Spatrick if (GetRoot()) {
3095061da546Spatrick if (GetRoot() == this) {
3096061da546Spatrick if (StackFrameSP frame_sp = GetFrameSP()) {
3097061da546Spatrick const SymbolContext &sc(
3098061da546Spatrick frame_sp->GetSymbolContext(eSymbolContextCompUnit));
3099061da546Spatrick if (CompileUnit *cu = sc.comp_unit)
3100061da546Spatrick type = cu->GetLanguage();
3101061da546Spatrick }
3102061da546Spatrick } else {
3103061da546Spatrick type = GetRoot()->GetPreferredDisplayLanguage();
3104061da546Spatrick }
3105061da546Spatrick }
3106061da546Spatrick }
3107061da546Spatrick return (m_preferred_display_language = type); // only compute it once
3108061da546Spatrick }
3109061da546Spatrick
SetPreferredDisplayLanguageIfNeeded(lldb::LanguageType lt)3110061da546Spatrick void ValueObject::SetPreferredDisplayLanguageIfNeeded(lldb::LanguageType lt) {
3111061da546Spatrick if (m_preferred_display_language == lldb::eLanguageTypeUnknown)
3112061da546Spatrick SetPreferredDisplayLanguage(lt);
3113061da546Spatrick }
3114061da546Spatrick
CanProvideValue()3115061da546Spatrick bool ValueObject::CanProvideValue() {
3116061da546Spatrick // we need to support invalid types as providers of values because some bare-
3117061da546Spatrick // board debugging scenarios have no notion of types, but still manage to
3118061da546Spatrick // have raw numeric values for things like registers. sigh.
3119be691f3bSpatrick CompilerType type = GetCompilerType();
3120061da546Spatrick return (!type.IsValid()) || (0 != (type.GetTypeInfo() & eTypeHasValue));
3121061da546Spatrick }
3122061da546Spatrick
3123be691f3bSpatrick
3124061da546Spatrick
Persist()3125061da546Spatrick ValueObjectSP ValueObject::Persist() {
3126061da546Spatrick if (!UpdateValueIfNeeded())
3127061da546Spatrick return nullptr;
3128061da546Spatrick
3129061da546Spatrick TargetSP target_sp(GetTargetSP());
3130061da546Spatrick if (!target_sp)
3131061da546Spatrick return nullptr;
3132061da546Spatrick
3133061da546Spatrick PersistentExpressionState *persistent_state =
3134061da546Spatrick target_sp->GetPersistentExpressionStateForLanguage(
3135061da546Spatrick GetPreferredDisplayLanguage());
3136061da546Spatrick
3137061da546Spatrick if (!persistent_state)
3138061da546Spatrick return nullptr;
3139061da546Spatrick
3140dda28197Spatrick ConstString name = persistent_state->GetNextPersistentVariableName();
3141061da546Spatrick
3142061da546Spatrick ValueObjectSP const_result_sp =
3143061da546Spatrick ValueObjectConstResult::Create(target_sp.get(), GetValue(), name);
3144061da546Spatrick
3145dda28197Spatrick ExpressionVariableSP persistent_var_sp =
3146061da546Spatrick persistent_state->CreatePersistentVariable(const_result_sp);
3147dda28197Spatrick persistent_var_sp->m_live_sp = persistent_var_sp->m_frozen_sp;
3148dda28197Spatrick persistent_var_sp->m_flags |= ExpressionVariable::EVIsProgramReference;
3149061da546Spatrick
3150dda28197Spatrick return persistent_var_sp->GetValueObject();
3151061da546Spatrick }
3152