/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/source/Core/ValueObject.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===-- ValueObject.cpp ---------------------------------------------------===// |
2 | | // |
3 | | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | | // See https://llvm.org/LICENSE.txt for license information. |
5 | | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | | // |
7 | | //===----------------------------------------------------------------------===// |
8 | | |
9 | | #include "lldb/Core/ValueObject.h" |
10 | | |
11 | | #include "lldb/Core/Address.h" |
12 | | #include "lldb/Core/Declaration.h" |
13 | | #include "lldb/Core/Module.h" |
14 | | #include "lldb/Core/ValueObjectCast.h" |
15 | | #include "lldb/Core/ValueObjectChild.h" |
16 | | #include "lldb/Core/ValueObjectConstResult.h" |
17 | | #include "lldb/Core/ValueObjectDynamicValue.h" |
18 | | #include "lldb/Core/ValueObjectMemory.h" |
19 | | #include "lldb/Core/ValueObjectSyntheticFilter.h" |
20 | | #include "lldb/Core/ValueObjectVTable.h" |
21 | | #include "lldb/DataFormatters/DataVisualization.h" |
22 | | #include "lldb/DataFormatters/DumpValueObjectOptions.h" |
23 | | #include "lldb/DataFormatters/FormatManager.h" |
24 | | #include "lldb/DataFormatters/StringPrinter.h" |
25 | | #include "lldb/DataFormatters/TypeFormat.h" |
26 | | #include "lldb/DataFormatters/TypeSummary.h" |
27 | | #include "lldb/DataFormatters/ValueObjectPrinter.h" |
28 | | #include "lldb/Expression/ExpressionVariable.h" |
29 | | #include "lldb/Host/Config.h" |
30 | | #include "lldb/Symbol/CompileUnit.h" |
31 | | #include "lldb/Symbol/CompilerType.h" |
32 | | #include "lldb/Symbol/SymbolContext.h" |
33 | | #include "lldb/Symbol/Type.h" |
34 | | #include "lldb/Symbol/Variable.h" |
35 | | #include "lldb/Target/ExecutionContext.h" |
36 | | #include "lldb/Target/Language.h" |
37 | | #include "lldb/Target/LanguageRuntime.h" |
38 | | #include "lldb/Target/Process.h" |
39 | | #include "lldb/Target/StackFrame.h" |
40 | | #include "lldb/Target/Target.h" |
41 | | #include "lldb/Target/Thread.h" |
42 | | #include "lldb/Target/ThreadList.h" |
43 | | #include "lldb/Utility/DataBuffer.h" |
44 | | #include "lldb/Utility/DataBufferHeap.h" |
45 | | #include "lldb/Utility/Flags.h" |
46 | | #include "lldb/Utility/LLDBLog.h" |
47 | | #include "lldb/Utility/Log.h" |
48 | | #include "lldb/Utility/Scalar.h" |
49 | | #include "lldb/Utility/Stream.h" |
50 | | #include "lldb/Utility/StreamString.h" |
51 | | #include "lldb/lldb-private-types.h" |
52 | | |
53 | | #include "llvm/Support/Compiler.h" |
54 | | |
55 | | #include <algorithm> |
56 | | #include <cstdint> |
57 | | #include <cstdlib> |
58 | | #include <memory> |
59 | | #include <optional> |
60 | | #include <tuple> |
61 | | |
62 | | #include <cassert> |
63 | | #include <cinttypes> |
64 | | #include <cstdio> |
65 | | #include <cstring> |
66 | | |
67 | | #include <lldb/Core/ValueObject.h> |
68 | | |
69 | | namespace lldb_private { |
70 | | class ExecutionContextScope; |
71 | | } |
72 | | namespace lldb_private { |
73 | | class SymbolContextScope; |
74 | | } |
75 | | |
76 | | using namespace lldb; |
77 | | using namespace lldb_private; |
78 | | |
79 | | static user_id_t g_value_obj_uid = 0; |
80 | | |
81 | | // ValueObject constructor |
82 | | ValueObject::ValueObject(ValueObject &parent) |
83 | 51.2k | : m_parent(&parent), m_update_point(parent.GetUpdatePoint()), |
84 | 51.2k | m_manager(parent.GetManager()), m_id(++g_value_obj_uid) { |
85 | 51.2k | m_flags.m_is_synthetic_children_generated = |
86 | 51.2k | parent.m_flags.m_is_synthetic_children_generated; |
87 | 51.2k | m_data.SetByteOrder(parent.GetDataExtractor().GetByteOrder()); |
88 | 51.2k | m_data.SetAddressByteSize(parent.GetDataExtractor().GetAddressByteSize()); |
89 | 51.2k | m_manager->ManageObject(this); |
90 | 51.2k | } |
91 | | |
92 | | // ValueObject constructor |
93 | | ValueObject::ValueObject(ExecutionContextScope *exe_scope, |
94 | | ValueObjectManager &manager, |
95 | | AddressType child_ptr_or_ref_addr_type) |
96 | 58.2k | : m_update_point(exe_scope), m_manager(&manager), |
97 | 58.2k | m_address_type_of_ptr_or_ref_children(child_ptr_or_ref_addr_type), |
98 | 58.2k | m_id(++g_value_obj_uid) { |
99 | 58.2k | if (exe_scope) { |
100 | 58.2k | TargetSP target_sp(exe_scope->CalculateTarget()); |
101 | 58.2k | if (target_sp) { |
102 | 58.2k | const ArchSpec &arch = target_sp->GetArchitecture(); |
103 | 58.2k | m_data.SetByteOrder(arch.GetByteOrder()); |
104 | 58.2k | m_data.SetAddressByteSize(arch.GetAddressByteSize()); |
105 | 58.2k | } |
106 | 58.2k | } |
107 | 58.2k | m_manager->ManageObject(this); |
108 | 58.2k | } |
109 | | |
110 | | // Destructor |
111 | 89.3k | ValueObject::~ValueObject() = default; |
112 | | |
113 | 1.05M | bool ValueObject::UpdateValueIfNeeded(bool update_format) { |
114 | | |
115 | 1.05M | bool did_change_formats = false; |
116 | | |
117 | 1.05M | if (update_format) |
118 | 391k | did_change_formats = UpdateFormatsIfNeeded(); |
119 | | |
120 | | // If this is a constant value, then our success is predicated on whether we |
121 | | // have an error or not |
122 | 1.05M | if (GetIsConstant()) { |
123 | | // if you are constant, things might still have changed behind your back |
124 | | // (e.g. you are a frozen object and things have changed deeper than you |
125 | | // cared to freeze-dry yourself) in this case, your value has not changed, |
126 | | // but "computed" entries might have, so you might now have a different |
127 | | // summary, or a different object description. clear these so we will |
128 | | // recompute them |
129 | 387k | if (update_format && !did_change_formats158k ) |
130 | 152k | ClearUserVisibleData(eClearUserVisibleDataItemsSummary | |
131 | 152k | eClearUserVisibleDataItemsDescription); |
132 | 387k | return m_error.Success(); |
133 | 387k | } |
134 | | |
135 | 663k | bool first_update = IsChecksumEmpty(); |
136 | | |
137 | 663k | if (NeedsUpdating()) { |
138 | 65.6k | m_update_point.SetUpdated(); |
139 | | |
140 | | // Save the old value using swap to avoid a string copy which also will |
141 | | // clear our m_value_str |
142 | 65.6k | if (m_value_str.empty()) { |
143 | 65.5k | m_flags.m_old_value_valid = false; |
144 | 65.5k | } else { |
145 | 144 | m_flags.m_old_value_valid = true; |
146 | 144 | m_old_value_str.swap(m_value_str); |
147 | 144 | ClearUserVisibleData(eClearUserVisibleDataItemsValue); |
148 | 144 | } |
149 | | |
150 | 65.6k | ClearUserVisibleData(); |
151 | | |
152 | 65.6k | if (IsInScope()) { |
153 | 65.6k | const bool value_was_valid = GetValueIsValid(); |
154 | 65.6k | SetValueDidChange(false); |
155 | | |
156 | 65.6k | m_error.Clear(); |
157 | | |
158 | | // Call the pure virtual function to update the value |
159 | | |
160 | 65.6k | bool need_compare_checksums = false; |
161 | 65.6k | llvm::SmallVector<uint8_t, 16> old_checksum; |
162 | | |
163 | 65.6k | if (!first_update && CanProvideValue()734 ) { |
164 | 604 | need_compare_checksums = true; |
165 | 604 | old_checksum.resize(m_value_checksum.size()); |
166 | 604 | std::copy(m_value_checksum.begin(), m_value_checksum.end(), |
167 | 604 | old_checksum.begin()); |
168 | 604 | } |
169 | | |
170 | 65.6k | bool success = UpdateValue(); |
171 | | |
172 | 65.6k | SetValueIsValid(success); |
173 | | |
174 | 65.6k | if (success) { |
175 | 64.8k | UpdateChildrenAddressType(); |
176 | 64.8k | const uint64_t max_checksum_size = 128; |
177 | 64.8k | m_data.Checksum(m_value_checksum, max_checksum_size); |
178 | 64.8k | } else { |
179 | 806 | need_compare_checksums = false; |
180 | 806 | m_value_checksum.clear(); |
181 | 806 | } |
182 | | |
183 | 65.6k | assert(!need_compare_checksums || |
184 | 65.6k | (!old_checksum.empty() && !m_value_checksum.empty())); |
185 | | |
186 | 65.6k | if (first_update) |
187 | 64.9k | SetValueDidChange(false); |
188 | 734 | else if (!m_flags.m_value_did_change && !success644 ) { |
189 | | // The value wasn't gotten successfully, so we mark this as changed if |
190 | | // the value used to be valid and now isn't |
191 | 2 | SetValueDidChange(value_was_valid); |
192 | 732 | } else if (need_compare_checksums) { |
193 | 598 | SetValueDidChange(memcmp(&old_checksum[0], &m_value_checksum[0], |
194 | 598 | m_value_checksum.size())); |
195 | 598 | } |
196 | | |
197 | 65.6k | } else { |
198 | 16 | m_error.SetErrorString("out of scope"); |
199 | 16 | } |
200 | 65.6k | } |
201 | 663k | return m_error.Success(); |
202 | 663k | } |
203 | | |
204 | 699k | bool ValueObject::UpdateFormatsIfNeeded() { |
205 | 699k | Log *log = GetLog(LLDBLog::DataFormatters); |
206 | 699k | LLDB_LOGF(log, |
207 | 699k | "[%s %p] checking for FormatManager revisions. ValueObject " |
208 | 699k | "rev: %d - Global rev: %d", |
209 | 699k | GetName().GetCString(), static_cast<void *>(this), |
210 | 699k | m_last_format_mgr_revision, |
211 | 699k | DataVisualization::GetCurrentRevision()); |
212 | | |
213 | 699k | bool any_change = false; |
214 | | |
215 | 699k | if ((m_last_format_mgr_revision != DataVisualization::GetCurrentRevision())) { |
216 | 69.7k | m_last_format_mgr_revision = DataVisualization::GetCurrentRevision(); |
217 | 69.7k | any_change = true; |
218 | | |
219 | 69.7k | SetValueFormat(DataVisualization::GetFormat(*this, eNoDynamicValues)); |
220 | 69.7k | SetSummaryFormat( |
221 | 69.7k | DataVisualization::GetSummaryFormat(*this, GetDynamicValueType())); |
222 | 69.7k | SetSyntheticChildren( |
223 | 69.7k | DataVisualization::GetSyntheticChildren(*this, GetDynamicValueType())); |
224 | 69.7k | } |
225 | | |
226 | 699k | return any_change; |
227 | 699k | } |
228 | | |
229 | 45 | void ValueObject::SetNeedsUpdate() { |
230 | 45 | m_update_point.SetNeedsUpdate(); |
231 | | // We have to clear the value string here so ConstResult children will notice |
232 | | // if their values are changed by hand (i.e. with SetValueAsCString). |
233 | 45 | ClearUserVisibleData(eClearUserVisibleDataItemsValue); |
234 | 45 | } |
235 | | |
236 | 2.81k | void ValueObject::ClearDynamicTypeInformation() { |
237 | 2.81k | m_flags.m_children_count_valid = false; |
238 | 2.81k | m_flags.m_did_calculate_complete_objc_class_type = false; |
239 | 2.81k | m_last_format_mgr_revision = 0; |
240 | 2.81k | m_override_type = CompilerType(); |
241 | 2.81k | SetValueFormat(lldb::TypeFormatImplSP()); |
242 | 2.81k | SetSummaryFormat(lldb::TypeSummaryImplSP()); |
243 | 2.81k | SetSyntheticChildren(lldb::SyntheticChildrenSP()); |
244 | 2.81k | } |
245 | | |
246 | 2.80M | CompilerType ValueObject::MaybeCalculateCompleteType() { |
247 | 2.80M | CompilerType compiler_type(GetCompilerTypeImpl()); |
248 | | |
249 | 2.80M | if (m_flags.m_did_calculate_complete_objc_class_type) { |
250 | 2.71M | if (m_override_type.IsValid()) |
251 | 11.7k | return m_override_type; |
252 | 2.70M | else |
253 | 2.70M | return compiler_type; |
254 | 2.71M | } |
255 | | |
256 | 83.3k | m_flags.m_did_calculate_complete_objc_class_type = true; |
257 | | |
258 | 83.3k | ProcessSP process_sp( |
259 | 83.3k | GetUpdatePoint().GetExecutionContextRef().GetProcessSP()); |
260 | | |
261 | 83.3k | if (!process_sp) |
262 | 1.48k | return compiler_type; |
263 | | |
264 | 81.9k | if (auto *runtime = |
265 | 81.9k | process_sp->GetLanguageRuntime(GetObjectRuntimeLanguage())) { |
266 | 45.8k | if (std::optional<CompilerType> complete_type = |
267 | 45.8k | runtime->GetRuntimeType(compiler_type)) { |
268 | 671 | m_override_type = *complete_type; |
269 | 671 | if (m_override_type.IsValid()) |
270 | 671 | return m_override_type; |
271 | 671 | } |
272 | 45.8k | } |
273 | 81.2k | return compiler_type; |
274 | 81.9k | } |
275 | | |
276 | | |
277 | | |
278 | 123k | DataExtractor &ValueObject::GetDataExtractor() { |
279 | 123k | UpdateValueIfNeeded(false); |
280 | 123k | return m_data; |
281 | 123k | } |
282 | | |
283 | 225k | const Status &ValueObject::GetError() { |
284 | 225k | UpdateValueIfNeeded(false); |
285 | 225k | return m_error; |
286 | 225k | } |
287 | | |
288 | | const char *ValueObject::GetLocationAsCStringImpl(const Value &value, |
289 | 284 | const DataExtractor &data) { |
290 | 284 | if (UpdateValueIfNeeded(false)) { |
291 | 284 | if (m_location_str.empty()) { |
292 | 214 | StreamString sstr; |
293 | | |
294 | 214 | Value::ValueType value_type = value.GetValueType(); |
295 | | |
296 | 214 | switch (value_type) { |
297 | 0 | case Value::ValueType::Invalid: |
298 | 0 | m_location_str = "invalid"; |
299 | 0 | break; |
300 | 12 | case Value::ValueType::Scalar: |
301 | 12 | if (value.GetContextType() == Value::ContextType::RegisterInfo) { |
302 | 4 | RegisterInfo *reg_info = value.GetRegisterInfo(); |
303 | 4 | if (reg_info) { |
304 | 4 | if (reg_info->name) |
305 | 4 | m_location_str = reg_info->name; |
306 | 0 | else if (reg_info->alt_name) |
307 | 0 | m_location_str = reg_info->alt_name; |
308 | 4 | if (m_location_str.empty()) |
309 | 0 | m_location_str = (reg_info->encoding == lldb::eEncodingVector) |
310 | 0 | ? "vector" |
311 | 0 | : "scalar"; |
312 | 4 | } |
313 | 4 | } |
314 | 12 | if (m_location_str.empty()) |
315 | 8 | m_location_str = "scalar"; |
316 | 12 | break; |
317 | | |
318 | 182 | case Value::ValueType::LoadAddress: |
319 | 182 | case Value::ValueType::FileAddress: |
320 | 202 | case Value::ValueType::HostAddress: { |
321 | 202 | uint32_t addr_nibble_size = data.GetAddressByteSize() * 2; |
322 | 202 | sstr.Printf("0x%*.*llx", addr_nibble_size, addr_nibble_size, |
323 | 202 | value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS)); |
324 | 202 | m_location_str = std::string(sstr.GetString()); |
325 | 202 | } break; |
326 | 214 | } |
327 | 214 | } |
328 | 284 | } |
329 | 284 | return m_location_str.c_str(); |
330 | 284 | } |
331 | | |
332 | 41.7k | bool ValueObject::ResolveValue(Scalar &scalar) { |
333 | 41.7k | if (UpdateValueIfNeeded( |
334 | 41.7k | false)) // make sure that you are up to date before returning anything |
335 | 41.6k | { |
336 | 41.6k | ExecutionContext exe_ctx(GetExecutionContextRef()); |
337 | 41.6k | Value tmp_value(m_value); |
338 | 41.6k | scalar = tmp_value.ResolveValue(&exe_ctx, GetModule().get()); |
339 | 41.6k | if (scalar.IsValid()) { |
340 | 41.6k | const uint32_t bitfield_bit_size = GetBitfieldBitSize(); |
341 | 41.6k | if (bitfield_bit_size) |
342 | 2.28k | return scalar.ExtractBitfield(bitfield_bit_size, |
343 | 2.28k | GetBitfieldBitOffset()); |
344 | 39.3k | return true; |
345 | 41.6k | } |
346 | 41.6k | } |
347 | 56 | return false; |
348 | 41.7k | } |
349 | | |
350 | 175 | bool ValueObject::IsLogicalTrue(Status &error) { |
351 | 175 | if (Language *language = Language::FindPlugin(GetObjectRuntimeLanguage())) { |
352 | 0 | LazyBool is_logical_true = language->IsLogicalTrue(*this, error); |
353 | 0 | switch (is_logical_true) { |
354 | 0 | case eLazyBoolYes: |
355 | 0 | case eLazyBoolNo: |
356 | 0 | return (is_logical_true == true); |
357 | 0 | case eLazyBoolCalculate: |
358 | 0 | break; |
359 | 0 | } |
360 | 0 | } |
361 | | |
362 | 175 | Scalar scalar_value; |
363 | | |
364 | 175 | if (!ResolveValue(scalar_value)) { |
365 | 0 | error.SetErrorString("failed to get a scalar result"); |
366 | 0 | return false; |
367 | 0 | } |
368 | | |
369 | 175 | bool ret; |
370 | 175 | ret = scalar_value.ULongLong(1) != 0; |
371 | 175 | error.Clear(); |
372 | 175 | return ret; |
373 | 175 | } |
374 | | |
375 | 100k | ValueObjectSP ValueObject::GetChildAtIndex(size_t idx, bool can_create) { |
376 | 100k | ValueObjectSP child_sp; |
377 | | // We may need to update our value if we are dynamic |
378 | 100k | if (IsPossibleDynamicType()) |
379 | 307 | UpdateValueIfNeeded(false); |
380 | 100k | if (idx < GetNumChildren()) { |
381 | | // Check if we have already made the child value object? |
382 | 100k | if (can_create && !m_children.HasChildAtIndex(idx)) { |
383 | | // No we haven't created the child at this index, so lets have our |
384 | | // subclass do it and cache the result for quick future access. |
385 | 43.6k | m_children.SetChildAtIndex(idx, CreateChildAtIndex(idx, false, 0)); |
386 | 43.6k | } |
387 | | |
388 | 100k | ValueObject *child = m_children.GetChildAtIndex(idx); |
389 | 100k | if (child != nullptr) |
390 | 100k | return child->GetSP(); |
391 | 100k | } |
392 | 165 | return child_sp; |
393 | 100k | } |
394 | | |
395 | | lldb::ValueObjectSP |
396 | | ValueObject::GetChildAtIndexPath(llvm::ArrayRef<size_t> idxs, |
397 | 0 | size_t *index_of_error) { |
398 | 0 | if (idxs.size() == 0) |
399 | 0 | return GetSP(); |
400 | 0 | ValueObjectSP root(GetSP()); |
401 | 0 | for (size_t idx : idxs) { |
402 | 0 | root = root->GetChildAtIndex(idx); |
403 | 0 | if (!root) { |
404 | 0 | if (index_of_error) |
405 | 0 | *index_of_error = idx; |
406 | 0 | return root; |
407 | 0 | } |
408 | 0 | } |
409 | 0 | return root; |
410 | 0 | } |
411 | | |
412 | | lldb::ValueObjectSP ValueObject::GetChildAtIndexPath( |
413 | 0 | llvm::ArrayRef<std::pair<size_t, bool>> idxs, size_t *index_of_error) { |
414 | 0 | if (idxs.size() == 0) |
415 | 0 | return GetSP(); |
416 | 0 | ValueObjectSP root(GetSP()); |
417 | 0 | for (std::pair<size_t, bool> idx : idxs) { |
418 | 0 | root = root->GetChildAtIndex(idx.first, idx.second); |
419 | 0 | if (!root) { |
420 | 0 | if (index_of_error) |
421 | 0 | *index_of_error = idx.first; |
422 | 0 | return root; |
423 | 0 | } |
424 | 0 | } |
425 | 0 | return root; |
426 | 0 | } |
427 | | |
428 | | lldb::ValueObjectSP |
429 | 298 | ValueObject::GetChildAtNamePath(llvm::ArrayRef<llvm::StringRef> names) { |
430 | 298 | if (names.size() == 0) |
431 | 0 | return GetSP(); |
432 | 298 | ValueObjectSP root(GetSP()); |
433 | 648 | for (llvm::StringRef name : names) { |
434 | 648 | root = root->GetChildMemberWithName(name); |
435 | 648 | if (!root) { |
436 | 0 | return root; |
437 | 0 | } |
438 | 648 | } |
439 | 298 | return root; |
440 | 298 | } |
441 | | |
442 | 1.08k | size_t ValueObject::GetIndexOfChildWithName(llvm::StringRef name) { |
443 | 1.08k | bool omit_empty_base_classes = true; |
444 | 1.08k | return GetCompilerType().GetIndexOfChildWithName(name, |
445 | 1.08k | omit_empty_base_classes); |
446 | 1.08k | } |
447 | | |
448 | | ValueObjectSP ValueObject::GetChildMemberWithName(llvm::StringRef name, |
449 | 25.7k | bool can_create) { |
450 | | // We may need to update our value if we are dynamic. |
451 | 25.7k | if (IsPossibleDynamicType()) |
452 | 202 | UpdateValueIfNeeded(false); |
453 | | |
454 | | // When getting a child by name, it could be buried inside some base classes |
455 | | // (which really aren't part of the expression path), so we need a vector of |
456 | | // indexes that can get us down to the correct child. |
457 | 25.7k | std::vector<uint32_t> child_indexes; |
458 | 25.7k | bool omit_empty_base_classes = true; |
459 | | |
460 | 25.7k | if (!GetCompilerType().IsValid()) |
461 | 0 | return ValueObjectSP(); |
462 | | |
463 | 25.7k | const size_t num_child_indexes = |
464 | 25.7k | GetCompilerType().GetIndexOfChildMemberWithName( |
465 | 25.7k | name, omit_empty_base_classes, child_indexes); |
466 | 25.7k | if (num_child_indexes == 0) |
467 | 822 | return nullptr; |
468 | | |
469 | 24.8k | ValueObjectSP child_sp = GetSP(); |
470 | 24.8k | for (uint32_t idx : child_indexes) |
471 | 38.7k | if (child_sp) |
472 | 38.7k | child_sp = child_sp->GetChildAtIndex(idx, can_create); |
473 | 24.8k | return child_sp; |
474 | 25.7k | } |
475 | | |
476 | 203k | size_t ValueObject::GetNumChildren(uint32_t max) { |
477 | 203k | UpdateValueIfNeeded(); |
478 | | |
479 | 203k | if (max < UINT32_MAX) { |
480 | 6 | if (m_flags.m_children_count_valid) { |
481 | 0 | size_t children_count = m_children.GetChildrenCount(); |
482 | 0 | return children_count <= max ? children_count : max; |
483 | 0 | } else |
484 | 6 | return CalculateNumChildren(max); |
485 | 6 | } |
486 | | |
487 | 203k | if (!m_flags.m_children_count_valid) { |
488 | 55.0k | SetNumChildren(CalculateNumChildren()); |
489 | 55.0k | } |
490 | 203k | return m_children.GetChildrenCount(); |
491 | 203k | } |
492 | | |
493 | 170 | bool ValueObject::MightHaveChildren() { |
494 | 170 | bool has_children = false; |
495 | 170 | const uint32_t type_info = GetTypeInfo(); |
496 | 170 | if (type_info) { |
497 | 170 | if (type_info & (eTypeHasChildren | eTypeIsPointer | eTypeIsReference)) |
498 | 170 | has_children = true; |
499 | 170 | } else { |
500 | 0 | has_children = GetNumChildren() > 0; |
501 | 0 | } |
502 | 170 | return has_children; |
503 | 170 | } |
504 | | |
505 | | // Should only be called by ValueObject::GetNumChildren() |
506 | 55.0k | void ValueObject::SetNumChildren(size_t num_children) { |
507 | 55.0k | m_flags.m_children_count_valid = true; |
508 | 55.0k | m_children.SetChildrenCount(num_children); |
509 | 55.0k | } |
510 | | |
511 | | ValueObject *ValueObject::CreateChildAtIndex(size_t idx, |
512 | | bool synthetic_array_member, |
513 | 36.2k | int32_t synthetic_index) { |
514 | 36.2k | ValueObject *valobj = nullptr; |
515 | | |
516 | 36.2k | bool omit_empty_base_classes = true; |
517 | 36.2k | bool ignore_array_bounds = synthetic_array_member; |
518 | 36.2k | std::string child_name_str; |
519 | 36.2k | uint32_t child_byte_size = 0; |
520 | 36.2k | int32_t child_byte_offset = 0; |
521 | 36.2k | uint32_t child_bitfield_bit_size = 0; |
522 | 36.2k | uint32_t child_bitfield_bit_offset = 0; |
523 | 36.2k | bool child_is_base_class = false; |
524 | 36.2k | bool child_is_deref_of_parent = false; |
525 | 36.2k | uint64_t language_flags = 0; |
526 | | |
527 | 36.2k | const bool transparent_pointers = !synthetic_array_member; |
528 | 36.2k | CompilerType child_compiler_type; |
529 | | |
530 | 36.2k | ExecutionContext exe_ctx(GetExecutionContextRef()); |
531 | | |
532 | 36.2k | child_compiler_type = GetCompilerType().GetChildCompilerTypeAtIndex( |
533 | 36.2k | &exe_ctx, idx, transparent_pointers, omit_empty_base_classes, |
534 | 36.2k | ignore_array_bounds, child_name_str, child_byte_size, child_byte_offset, |
535 | 36.2k | child_bitfield_bit_size, child_bitfield_bit_offset, child_is_base_class, |
536 | 36.2k | child_is_deref_of_parent, this, language_flags); |
537 | 36.2k | if (child_compiler_type) { |
538 | 36.2k | if (synthetic_index) |
539 | 75 | child_byte_offset += child_byte_size * synthetic_index; |
540 | | |
541 | 36.2k | ConstString child_name; |
542 | 36.2k | if (!child_name_str.empty()) |
543 | 33.7k | child_name.SetCString(child_name_str.c_str()); |
544 | | |
545 | 36.2k | valobj = new ValueObjectChild( |
546 | 36.2k | *this, child_compiler_type, child_name, child_byte_size, |
547 | 36.2k | child_byte_offset, child_bitfield_bit_size, child_bitfield_bit_offset, |
548 | 36.2k | child_is_base_class, child_is_deref_of_parent, eAddressTypeInvalid, |
549 | 36.2k | language_flags); |
550 | 36.2k | } |
551 | | |
552 | | // In case of an incomplete type, try to use the ValueObject's |
553 | | // synthetic value to create the child ValueObject. |
554 | 36.2k | if (!valobj && synthetic_array_member46 ) { |
555 | 2 | if (ValueObjectSP synth_valobj_sp = GetSyntheticValue()) { |
556 | 0 | valobj = synth_valobj_sp |
557 | 0 | ->GetChildAtIndex(synthetic_index, synthetic_array_member) |
558 | 0 | .get(); |
559 | 0 | } |
560 | 2 | } |
561 | | |
562 | 36.2k | return valobj; |
563 | 36.2k | } |
564 | | |
565 | | bool ValueObject::GetSummaryAsCString(TypeSummaryImpl *summary_ptr, |
566 | | std::string &destination, |
567 | 6.19k | lldb::LanguageType lang) { |
568 | 6.19k | return GetSummaryAsCString(summary_ptr, destination, |
569 | 6.19k | TypeSummaryOptions().SetLanguage(lang)); |
570 | 6.19k | } |
571 | | |
572 | | bool ValueObject::GetSummaryAsCString(TypeSummaryImpl *summary_ptr, |
573 | | std::string &destination, |
574 | 54.6k | const TypeSummaryOptions &options) { |
575 | 54.6k | destination.clear(); |
576 | | |
577 | | // If we have a forcefully completed type, don't try and show a summary from |
578 | | // a valid summary string or function because the type is not complete and |
579 | | // no member variables or member functions will be available. |
580 | 54.6k | if (GetCompilerType().IsForcefullyCompleted()) { |
581 | 66 | destination = "<incomplete type>"; |
582 | 66 | return true; |
583 | 66 | } |
584 | | |
585 | | // ideally we would like to bail out if passing NULL, but if we do so we end |
586 | | // up not providing the summary for function pointers anymore |
587 | 54.6k | if (/*summary_ptr == NULL ||*/ m_flags.m_is_getting_summary) |
588 | 0 | return false; |
589 | | |
590 | 54.6k | m_flags.m_is_getting_summary = true; |
591 | | |
592 | 54.6k | TypeSummaryOptions actual_options(options); |
593 | | |
594 | 54.6k | if (actual_options.GetLanguage() == lldb::eLanguageTypeUnknown) |
595 | 16.7k | actual_options.SetLanguage(GetPreferredDisplayLanguage()); |
596 | | |
597 | | // this is a hot path in code and we prefer to avoid setting this string all |
598 | | // too often also clearing out other information that we might care to see in |
599 | | // a crash log. might be useful in very specific situations though. |
600 | | /*Host::SetCrashDescriptionWithFormat("Trying to fetch a summary for %s %s. |
601 | | Summary provider's description is %s", |
602 | | GetTypeName().GetCString(), |
603 | | GetName().GetCString(), |
604 | | summary_ptr->GetDescription().c_str());*/ |
605 | | |
606 | 54.6k | if (UpdateValueIfNeeded(false) && summary_ptr54.5k ) { |
607 | 7.68k | if (HasSyntheticValue()) |
608 | 47 | m_synthetic_value->UpdateValueIfNeeded(); // the summary might depend on |
609 | | // the synthetic children being |
610 | | // up-to-date (e.g. ${svar%#}) |
611 | 7.68k | summary_ptr->FormatObject(this, destination, actual_options); |
612 | 7.68k | } |
613 | 54.6k | m_flags.m_is_getting_summary = false; |
614 | 54.6k | return !destination.empty(); |
615 | 54.6k | } |
616 | | |
617 | 49.7k | const char *ValueObject::GetSummaryAsCString(lldb::LanguageType lang) { |
618 | 49.7k | if (UpdateValueIfNeeded(true) && m_summary_str.empty()49.5k ) { |
619 | 48.4k | TypeSummaryOptions summary_options; |
620 | 48.4k | summary_options.SetLanguage(lang); |
621 | 48.4k | GetSummaryAsCString(GetSummaryFormat().get(), m_summary_str, |
622 | 48.4k | summary_options); |
623 | 48.4k | } |
624 | 49.7k | if (m_summary_str.empty()) |
625 | 47.0k | return nullptr; |
626 | 2.67k | return m_summary_str.c_str(); |
627 | 49.7k | } |
628 | | |
629 | | bool ValueObject::GetSummaryAsCString(std::string &destination, |
630 | 18 | const TypeSummaryOptions &options) { |
631 | 18 | return GetSummaryAsCString(GetSummaryFormat().get(), destination, options); |
632 | 18 | } |
633 | | |
634 | 2.95k | bool ValueObject::IsCStringContainer(bool check_pointer) { |
635 | 2.95k | CompilerType pointee_or_element_compiler_type; |
636 | 2.95k | const Flags type_flags(GetTypeInfo(&pointee_or_element_compiler_type)); |
637 | 2.95k | bool is_char_arr_ptr(type_flags.AnySet(eTypeIsArray | eTypeIsPointer) && |
638 | 2.95k | pointee_or_element_compiler_type.IsCharType()); |
639 | 2.95k | if (!is_char_arr_ptr) |
640 | 68 | return false; |
641 | 2.88k | if (!check_pointer) |
642 | 0 | return true; |
643 | 2.88k | if (type_flags.Test(eTypeIsArray)) |
644 | 1.91k | return true; |
645 | 966 | addr_t cstr_address = LLDB_INVALID_ADDRESS; |
646 | 966 | AddressType cstr_address_type = eAddressTypeInvalid; |
647 | 966 | cstr_address = GetPointerValue(&cstr_address_type); |
648 | 966 | return (cstr_address != LLDB_INVALID_ADDRESS); |
649 | 2.88k | } |
650 | | |
651 | | size_t ValueObject::GetPointeeData(DataExtractor &data, uint32_t item_idx, |
652 | 2.75k | uint32_t item_count) { |
653 | 2.75k | CompilerType pointee_or_element_compiler_type; |
654 | 2.75k | const uint32_t type_info = GetTypeInfo(&pointee_or_element_compiler_type); |
655 | 2.75k | const bool is_pointer_type = type_info & eTypeIsPointer; |
656 | 2.75k | const bool is_array_type = type_info & eTypeIsArray; |
657 | 2.75k | if (!(is_pointer_type || is_array_type1.86k )) |
658 | 0 | return 0; |
659 | | |
660 | 2.75k | if (item_count == 0) |
661 | 0 | return 0; |
662 | | |
663 | 2.75k | ExecutionContext exe_ctx(GetExecutionContextRef()); |
664 | | |
665 | 2.75k | std::optional<uint64_t> item_type_size = |
666 | 2.75k | pointee_or_element_compiler_type.GetByteSize( |
667 | 2.75k | exe_ctx.GetBestExecutionContextScope()); |
668 | 2.75k | if (!item_type_size) |
669 | 0 | return 0; |
670 | 2.75k | const uint64_t bytes = item_count * *item_type_size; |
671 | 2.75k | const uint64_t offset = item_idx * *item_type_size; |
672 | | |
673 | 2.75k | if (item_idx == 0 && item_count == 12.57k ) // simply a deref |
674 | 104 | { |
675 | 104 | if (is_pointer_type) { |
676 | 6 | Status error; |
677 | 6 | ValueObjectSP pointee_sp = Dereference(error); |
678 | 6 | if (error.Fail() || pointee_sp.get() == nullptr) |
679 | 0 | return 0; |
680 | 6 | return pointee_sp->GetData(data, error); |
681 | 98 | } else { |
682 | 98 | ValueObjectSP child_sp = GetChildAtIndex(0); |
683 | 98 | if (child_sp.get() == nullptr) |
684 | 0 | return 0; |
685 | 98 | Status error; |
686 | 98 | return child_sp->GetData(data, error); |
687 | 98 | } |
688 | 0 | return true; |
689 | 104 | } else /* (items > 1) */ |
690 | 2.64k | { |
691 | 2.64k | Status error; |
692 | 2.64k | lldb_private::DataBufferHeap *heap_buf_ptr = nullptr; |
693 | 2.64k | lldb::DataBufferSP data_sp(heap_buf_ptr = |
694 | 2.64k | new lldb_private::DataBufferHeap()); |
695 | | |
696 | 2.64k | AddressType addr_type; |
697 | 2.64k | lldb::addr_t addr = is_pointer_type ? GetPointerValue(&addr_type)883 |
698 | 2.64k | : GetAddressOf(true, &addr_type)1.76k ; |
699 | | |
700 | 2.64k | switch (addr_type) { |
701 | 0 | case eAddressTypeFile: { |
702 | 0 | ModuleSP module_sp(GetModule()); |
703 | 0 | if (module_sp) { |
704 | 0 | addr = addr + offset; |
705 | 0 | Address so_addr; |
706 | 0 | module_sp->ResolveFileAddress(addr, so_addr); |
707 | 0 | ExecutionContext exe_ctx(GetExecutionContextRef()); |
708 | 0 | Target *target = exe_ctx.GetTargetPtr(); |
709 | 0 | if (target) { |
710 | 0 | heap_buf_ptr->SetByteSize(bytes); |
711 | 0 | size_t bytes_read = target->ReadMemory( |
712 | 0 | so_addr, heap_buf_ptr->GetBytes(), bytes, error, true); |
713 | 0 | if (error.Success()) { |
714 | 0 | data.SetData(data_sp); |
715 | 0 | return bytes_read; |
716 | 0 | } |
717 | 0 | } |
718 | 0 | } |
719 | 0 | } break; |
720 | 2.49k | case eAddressTypeLoad: { |
721 | 2.49k | ExecutionContext exe_ctx(GetExecutionContextRef()); |
722 | 2.49k | Process *process = exe_ctx.GetProcessPtr(); |
723 | 2.49k | if (process) { |
724 | 2.49k | heap_buf_ptr->SetByteSize(bytes); |
725 | 2.49k | size_t bytes_read = process->ReadMemory( |
726 | 2.49k | addr + offset, heap_buf_ptr->GetBytes(), bytes, error); |
727 | 2.49k | if (error.Success() || bytes_read > 08 ) { |
728 | 2.48k | data.SetData(data_sp); |
729 | 2.48k | return bytes_read; |
730 | 2.48k | } |
731 | 2.49k | } |
732 | 2.49k | } break8 ; |
733 | 156 | case eAddressTypeHost: { |
734 | 156 | auto max_bytes = |
735 | 156 | GetCompilerType().GetByteSize(exe_ctx.GetBestExecutionContextScope()); |
736 | 156 | if (max_bytes && *max_bytes > offset) { |
737 | 156 | size_t bytes_read = std::min<uint64_t>(*max_bytes - offset, bytes); |
738 | 156 | addr = m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS); |
739 | 156 | if (addr == 0 || addr == LLDB_INVALID_ADDRESS) |
740 | 0 | break; |
741 | 156 | heap_buf_ptr->CopyData((uint8_t *)(addr + offset), bytes_read); |
742 | 156 | data.SetData(data_sp); |
743 | 156 | return bytes_read; |
744 | 156 | } |
745 | 156 | } break0 ; |
746 | 0 | case eAddressTypeInvalid: |
747 | 0 | break; |
748 | 2.64k | } |
749 | 2.64k | } |
750 | 8 | return 0; |
751 | 2.75k | } |
752 | | |
753 | 33.0k | uint64_t ValueObject::GetData(DataExtractor &data, Status &error) { |
754 | 33.0k | UpdateValueIfNeeded(false); |
755 | 33.0k | ExecutionContext exe_ctx(GetExecutionContextRef()); |
756 | 33.0k | error = m_value.GetValueAsData(&exe_ctx, data, GetModule().get()); |
757 | 33.0k | if (error.Fail()) { |
758 | 0 | if (m_data.GetByteSize()) { |
759 | 0 | data = m_data; |
760 | 0 | error.Clear(); |
761 | 0 | return data.GetByteSize(); |
762 | 0 | } else { |
763 | 0 | return 0; |
764 | 0 | } |
765 | 0 | } |
766 | 33.0k | data.SetAddressByteSize(m_data.GetAddressByteSize()); |
767 | 33.0k | data.SetByteOrder(m_data.GetByteOrder()); |
768 | 33.0k | return data.GetByteSize(); |
769 | 33.0k | } |
770 | | |
771 | 4 | bool ValueObject::SetData(DataExtractor &data, Status &error) { |
772 | 4 | error.Clear(); |
773 | | // Make sure our value is up to date first so that our location and location |
774 | | // type is valid. |
775 | 4 | if (!UpdateValueIfNeeded(false)) { |
776 | 0 | error.SetErrorString("unable to read value"); |
777 | 0 | return false; |
778 | 0 | } |
779 | | |
780 | 4 | uint64_t count = 0; |
781 | 4 | const Encoding encoding = GetCompilerType().GetEncoding(count); |
782 | | |
783 | 4 | const size_t byte_size = GetByteSize().value_or(0); |
784 | | |
785 | 4 | Value::ValueType value_type = m_value.GetValueType(); |
786 | | |
787 | 4 | switch (value_type) { |
788 | 0 | case Value::ValueType::Invalid: |
789 | 0 | error.SetErrorString("invalid location"); |
790 | 0 | return false; |
791 | 0 | case Value::ValueType::Scalar: { |
792 | 0 | Status set_error = |
793 | 0 | m_value.GetScalar().SetValueFromData(data, encoding, byte_size); |
794 | |
|
795 | 0 | if (!set_error.Success()) { |
796 | 0 | error.SetErrorStringWithFormat("unable to set scalar value: %s", |
797 | 0 | set_error.AsCString()); |
798 | 0 | return false; |
799 | 0 | } |
800 | 0 | } break; |
801 | 4 | case Value::ValueType::LoadAddress: { |
802 | | // If it is a load address, then the scalar value is the storage location |
803 | | // of the data, and we have to shove this value down to that load location. |
804 | 4 | ExecutionContext exe_ctx(GetExecutionContextRef()); |
805 | 4 | Process *process = exe_ctx.GetProcessPtr(); |
806 | 4 | if (process) { |
807 | 4 | addr_t target_addr = m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS); |
808 | 4 | size_t bytes_written = process->WriteMemory( |
809 | 4 | target_addr, data.GetDataStart(), byte_size, error); |
810 | 4 | if (!error.Success()) |
811 | 0 | return false; |
812 | 4 | if (bytes_written != byte_size) { |
813 | 0 | error.SetErrorString("unable to write value to memory"); |
814 | 0 | return false; |
815 | 0 | } |
816 | 4 | } |
817 | 4 | } break; |
818 | 4 | case Value::ValueType::HostAddress: { |
819 | | // If it is a host address, then we stuff the scalar as a DataBuffer into |
820 | | // the Value's data. |
821 | 0 | DataBufferSP buffer_sp(new DataBufferHeap(byte_size, 0)); |
822 | 0 | m_data.SetData(buffer_sp, 0); |
823 | 0 | data.CopyByteOrderedData(0, byte_size, |
824 | 0 | const_cast<uint8_t *>(m_data.GetDataStart()), |
825 | 0 | byte_size, m_data.GetByteOrder()); |
826 | 0 | m_value.GetScalar() = (uintptr_t)m_data.GetDataStart(); |
827 | 0 | } break; |
828 | 0 | case Value::ValueType::FileAddress: |
829 | 0 | break; |
830 | 4 | } |
831 | | |
832 | | // If we have reached this point, then we have successfully changed the |
833 | | // value. |
834 | 4 | SetNeedsUpdate(); |
835 | 4 | return true; |
836 | 4 | } |
837 | | |
838 | | static bool CopyStringDataToBufferSP(const StreamString &source, |
839 | 1.44k | lldb::WritableDataBufferSP &destination) { |
840 | 1.44k | llvm::StringRef src = source.GetString(); |
841 | 1.44k | src = src.rtrim('\0'); |
842 | 1.44k | destination = std::make_shared<DataBufferHeap>(src.size(), 0); |
843 | 1.44k | memcpy(destination->GetBytes(), src.data(), src.size()); |
844 | 1.44k | return true; |
845 | 1.44k | } |
846 | | |
847 | | std::pair<size_t, bool> |
848 | | ValueObject::ReadPointedString(lldb::WritableDataBufferSP &buffer_sp, |
849 | | Status &error, uint32_t max_length, |
850 | 1.44k | bool honor_array, Format item_format) { |
851 | 1.44k | bool was_capped = false; |
852 | 1.44k | StreamString s; |
853 | 1.44k | ExecutionContext exe_ctx(GetExecutionContextRef()); |
854 | 1.44k | Target *target = exe_ctx.GetTargetPtr(); |
855 | | |
856 | 1.44k | if (!target) { |
857 | 0 | s << "<no target to read from>"; |
858 | 0 | error.SetErrorString("no target to read from"); |
859 | 0 | CopyStringDataToBufferSP(s, buffer_sp); |
860 | 0 | return {0, was_capped}; |
861 | 0 | } |
862 | | |
863 | 1.44k | if (max_length == 0) |
864 | 1.44k | max_length = target->GetMaximumSizeOfStringSummary(); |
865 | | |
866 | 1.44k | size_t bytes_read = 0; |
867 | 1.44k | size_t total_bytes_read = 0; |
868 | | |
869 | 1.44k | CompilerType compiler_type = GetCompilerType(); |
870 | 1.44k | CompilerType elem_or_pointee_compiler_type; |
871 | 1.44k | const Flags type_flags(GetTypeInfo(&elem_or_pointee_compiler_type)); |
872 | 1.44k | if (type_flags.AnySet(eTypeIsArray | eTypeIsPointer) && |
873 | 1.44k | elem_or_pointee_compiler_type.IsCharType()) { |
874 | 1.44k | addr_t cstr_address = LLDB_INVALID_ADDRESS; |
875 | 1.44k | AddressType cstr_address_type = eAddressTypeInvalid; |
876 | | |
877 | 1.44k | size_t cstr_len = 0; |
878 | 1.44k | bool capped_data = false; |
879 | 1.44k | const bool is_array = type_flags.Test(eTypeIsArray); |
880 | 1.44k | if (is_array) { |
881 | | // We have an array |
882 | 958 | uint64_t array_size = 0; |
883 | 958 | if (compiler_type.IsArrayType(nullptr, &array_size)) { |
884 | 958 | cstr_len = array_size; |
885 | 958 | if (cstr_len > max_length) { |
886 | 0 | capped_data = true; |
887 | 0 | cstr_len = max_length; |
888 | 0 | } |
889 | 958 | } |
890 | 958 | cstr_address = GetAddressOf(true, &cstr_address_type); |
891 | 958 | } else { |
892 | | // We have a pointer |
893 | 483 | cstr_address = GetPointerValue(&cstr_address_type); |
894 | 483 | } |
895 | | |
896 | 1.44k | if (cstr_address == 0 || cstr_address == 1.41k LLDB_INVALID_ADDRESS1.41k ) { |
897 | 29 | if (cstr_address_type == eAddressTypeHost && is_array5 ) { |
898 | 5 | const char *cstr = GetDataExtractor().PeekCStr(0); |
899 | 5 | if (cstr == nullptr) { |
900 | 0 | s << "<invalid address>"; |
901 | 0 | error.SetErrorString("invalid address"); |
902 | 0 | CopyStringDataToBufferSP(s, buffer_sp); |
903 | 0 | return {0, was_capped}; |
904 | 0 | } |
905 | 5 | s << llvm::StringRef(cstr, cstr_len); |
906 | 5 | CopyStringDataToBufferSP(s, buffer_sp); |
907 | 5 | return {cstr_len, was_capped}; |
908 | 24 | } else { |
909 | 24 | s << "<invalid address>"; |
910 | 24 | error.SetErrorString("invalid address"); |
911 | 24 | CopyStringDataToBufferSP(s, buffer_sp); |
912 | 24 | return {0, was_capped}; |
913 | 24 | } |
914 | 29 | } |
915 | | |
916 | 1.41k | Address cstr_so_addr(cstr_address); |
917 | 1.41k | DataExtractor data; |
918 | 1.41k | if (cstr_len > 0 && honor_array947 ) { |
919 | | // I am using GetPointeeData() here to abstract the fact that some |
920 | | // ValueObjects are actually frozen pointers in the host but the pointed- |
921 | | // to data lives in the debuggee, and GetPointeeData() automatically |
922 | | // takes care of this |
923 | 925 | GetPointeeData(data, 0, cstr_len); |
924 | | |
925 | 925 | if ((bytes_read = data.GetByteSize()) > 0) { |
926 | 925 | total_bytes_read = bytes_read; |
927 | 802k | for (size_t offset = 0; offset < bytes_read; offset++801k ) |
928 | 801k | s.Printf("%c", *data.PeekData(offset, 1)); |
929 | 925 | if (capped_data) |
930 | 0 | was_capped = true; |
931 | 925 | } |
932 | 925 | } else { |
933 | 487 | cstr_len = max_length; |
934 | 487 | const size_t k_max_buf_size = 64; |
935 | | |
936 | 487 | size_t offset = 0; |
937 | | |
938 | 487 | int cstr_len_displayed = -1; |
939 | 487 | bool capped_cstr = false; |
940 | | // I am using GetPointeeData() here to abstract the fact that some |
941 | | // ValueObjects are actually frozen pointers in the host but the pointed- |
942 | | // to data lives in the debuggee, and GetPointeeData() automatically |
943 | | // takes care of this |
944 | 661 | while ((bytes_read = GetPointeeData(data, offset, k_max_buf_size)) > 0) { |
945 | 659 | total_bytes_read += bytes_read; |
946 | 659 | const char *cstr = data.PeekCStr(0); |
947 | 659 | size_t len = strnlen(cstr, k_max_buf_size); |
948 | 659 | if (cstr_len_displayed < 0) |
949 | 485 | cstr_len_displayed = len; |
950 | | |
951 | 659 | if (len == 0) |
952 | 18 | break; |
953 | 641 | cstr_len_displayed += len; |
954 | 641 | if (len > bytes_read) |
955 | 0 | len = bytes_read; |
956 | 641 | if (len > cstr_len) |
957 | 0 | len = cstr_len; |
958 | | |
959 | 41.6k | for (size_t offset = 0; offset < bytes_read; offset++41.0k ) |
960 | 41.0k | s.Printf("%c", *data.PeekData(offset, 1)); |
961 | | |
962 | 641 | if (len < k_max_buf_size) |
963 | 463 | break; |
964 | | |
965 | 178 | if (len >= cstr_len) { |
966 | 4 | capped_cstr = true; |
967 | 4 | break; |
968 | 4 | } |
969 | | |
970 | 174 | cstr_len -= len; |
971 | 174 | offset += len; |
972 | 174 | } |
973 | | |
974 | 487 | if (cstr_len_displayed >= 0) { |
975 | 485 | if (capped_cstr) |
976 | 4 | was_capped = true; |
977 | 485 | } |
978 | 487 | } |
979 | 1.41k | } else { |
980 | 0 | error.SetErrorString("not a string object"); |
981 | 0 | s << "<not a string object>"; |
982 | 0 | } |
983 | 1.41k | CopyStringDataToBufferSP(s, buffer_sp); |
984 | 1.41k | return {total_bytes_read, was_capped}; |
985 | 1.44k | } |
986 | | |
987 | 154 | const char *ValueObject::GetObjectDescription() { |
988 | 154 | if (!UpdateValueIfNeeded(true)) |
989 | 0 | return nullptr; |
990 | | |
991 | | // Return cached value. |
992 | 154 | if (!m_object_desc_str.empty()) |
993 | 0 | return m_object_desc_str.c_str(); |
994 | | |
995 | 154 | ExecutionContext exe_ctx(GetExecutionContextRef()); |
996 | 154 | Process *process = exe_ctx.GetProcessPtr(); |
997 | 154 | if (!process) |
998 | 0 | return nullptr; |
999 | | |
1000 | | // Returns the object description produced by one language runtime. |
1001 | 172 | auto get_object_description = [&](LanguageType language) -> const char * 154 { |
1002 | 172 | if (LanguageRuntime *runtime = process->GetLanguageRuntime(language)) { |
1003 | 162 | StreamString s; |
1004 | 162 | if (runtime->GetObjectDescription(s, *this)) { |
1005 | 136 | m_object_desc_str.append(std::string(s.GetString())); |
1006 | 136 | return m_object_desc_str.c_str(); |
1007 | 136 | } |
1008 | 162 | } |
1009 | 36 | return nullptr; |
1010 | 172 | }; |
1011 | | |
1012 | | // Try the native language runtime first. |
1013 | 154 | LanguageType native_language = GetObjectRuntimeLanguage(); |
1014 | 154 | if (const char *desc = get_object_description(native_language)) |
1015 | 136 | return desc; |
1016 | | |
1017 | | // Try the Objective-C language runtime. This fallback is necessary |
1018 | | // for Objective-C++ and mixed Objective-C / C++ programs. |
1019 | 18 | if (Language::LanguageIsCFamily(native_language)) |
1020 | 18 | return get_object_description(eLanguageTypeObjC); |
1021 | 0 | return nullptr; |
1022 | 18 | } |
1023 | | |
1024 | | bool ValueObject::GetValueAsCString(const lldb_private::TypeFormatImpl &format, |
1025 | 38.9k | std::string &destination) { |
1026 | 38.9k | if (UpdateValueIfNeeded(false)) |
1027 | 38.9k | return format.FormatObject(this, destination); |
1028 | 0 | else |
1029 | 0 | return false; |
1030 | 38.9k | } |
1031 | | |
1032 | | bool ValueObject::GetValueAsCString(lldb::Format format, |
1033 | 348 | std::string &destination) { |
1034 | 348 | return GetValueAsCString(TypeFormatImpl_Format(format), destination); |
1035 | 348 | } |
1036 | | |
1037 | 67.5k | const char *ValueObject::GetValueAsCString() { |
1038 | 67.5k | if (UpdateValueIfNeeded(true)) { |
1039 | 67.3k | lldb::TypeFormatImplSP format_sp; |
1040 | 67.3k | lldb::Format my_format = GetFormat(); |
1041 | 67.3k | if (my_format == lldb::eFormatDefault) { |
1042 | 66.5k | if (m_type_format_sp) |
1043 | 575 | format_sp = m_type_format_sp; |
1044 | 65.9k | else { |
1045 | 65.9k | if (m_flags.m_is_bitfield_for_scalar) |
1046 | 22 | my_format = eFormatUnsigned; |
1047 | 65.9k | else { |
1048 | 65.9k | if (m_value.GetContextType() == Value::ContextType::RegisterInfo) { |
1049 | 829 | const RegisterInfo *reg_info = m_value.GetRegisterInfo(); |
1050 | 829 | if (reg_info) |
1051 | 829 | my_format = reg_info->format; |
1052 | 65.0k | } else { |
1053 | 65.0k | my_format = GetValue().GetCompilerType().GetFormat(); |
1054 | 65.0k | } |
1055 | 65.9k | } |
1056 | 65.9k | } |
1057 | 66.5k | } |
1058 | 67.3k | if (my_format != m_last_format || m_value_str.empty()34.2k ) { |
1059 | 38.5k | m_last_format = my_format; |
1060 | 38.5k | if (!format_sp) |
1061 | 38.3k | format_sp = std::make_shared<TypeFormatImpl_Format>(my_format); |
1062 | 38.5k | if (GetValueAsCString(*format_sp.get(), m_value_str)) { |
1063 | 29.5k | if (!m_flags.m_value_did_change && m_flags.m_old_value_valid29.4k ) { |
1064 | | // The value was gotten successfully, so we consider the value as |
1065 | | // changed if the value string differs |
1066 | 70 | SetValueDidChange(m_old_value_str != m_value_str); |
1067 | 70 | } |
1068 | 29.5k | } |
1069 | 38.5k | } |
1070 | 67.3k | } |
1071 | 67.5k | if (m_value_str.empty()) |
1072 | 9.17k | return nullptr; |
1073 | 58.3k | return m_value_str.c_str(); |
1074 | 67.5k | } |
1075 | | |
1076 | | // if > 8bytes, 0 is returned. this method should mostly be used to read |
1077 | | // address values out of pointers |
1078 | 41.6k | uint64_t ValueObject::GetValueAsUnsigned(uint64_t fail_value, bool *success) { |
1079 | | // If our byte size is zero this is an aggregate type that has children |
1080 | 41.6k | if (CanProvideValue()) { |
1081 | 41.4k | Scalar scalar; |
1082 | 41.4k | if (ResolveValue(scalar)) { |
1083 | 41.3k | if (success) |
1084 | 3.05k | *success = true; |
1085 | 41.3k | scalar.MakeUnsigned(); |
1086 | 41.3k | return scalar.ULongLong(fail_value); |
1087 | 41.3k | } |
1088 | | // fallthrough, otherwise... |
1089 | 41.4k | } |
1090 | | |
1091 | 277 | if (success) |
1092 | 24 | *success = false; |
1093 | 277 | return fail_value; |
1094 | 41.6k | } |
1095 | | |
1096 | 291 | int64_t ValueObject::GetValueAsSigned(int64_t fail_value, bool *success) { |
1097 | | // If our byte size is zero this is an aggregate type that has children |
1098 | 291 | if (CanProvideValue()) { |
1099 | 291 | Scalar scalar; |
1100 | 291 | if (ResolveValue(scalar)) { |
1101 | 291 | if (success) |
1102 | 37 | *success = true; |
1103 | 291 | scalar.MakeSigned(); |
1104 | 291 | return scalar.SLongLong(fail_value); |
1105 | 291 | } |
1106 | | // fallthrough, otherwise... |
1107 | 291 | } |
1108 | | |
1109 | 0 | if (success) |
1110 | 0 | *success = false; |
1111 | 0 | return fail_value; |
1112 | 291 | } |
1113 | | |
1114 | | // if any more "special cases" are added to |
1115 | | // ValueObject::DumpPrintableRepresentation() please keep this call up to date |
1116 | | // by returning true for your new special cases. We will eventually move to |
1117 | | // checking this call result before trying to display special cases |
1118 | | bool ValueObject::HasSpecialPrintableRepresentation( |
1119 | 1.48k | ValueObjectRepresentationStyle val_obj_display, Format custom_format) { |
1120 | 1.48k | Flags flags(GetTypeInfo()); |
1121 | 1.48k | if (flags.AnySet(eTypeIsArray | eTypeIsPointer) && |
1122 | 1.48k | val_obj_display == ValueObject::eValueObjectRepresentationStyleValue) { |
1123 | 1.48k | if (IsCStringContainer(true) && |
1124 | 1.48k | (1.44k custom_format == eFormatCString1.44k || custom_format == eFormatCharArray962 || |
1125 | 1.44k | custom_format == eFormatChar946 || custom_format == eFormatVectorOfChar930 )) |
1126 | 1.44k | return true; |
1127 | | |
1128 | 44 | if (flags.Test(eTypeIsArray)) { |
1129 | 24 | if ((custom_format == eFormatBytes) || |
1130 | 24 | (custom_format == eFormatBytesWithASCII)16 ) |
1131 | 16 | return true; |
1132 | | |
1133 | 8 | if ((custom_format == eFormatVectorOfChar) || |
1134 | 8 | (custom_format == eFormatVectorOfFloat32) || |
1135 | 8 | (custom_format == eFormatVectorOfFloat64)4 || |
1136 | 8 | (custom_format == eFormatVectorOfSInt16)4 || |
1137 | 8 | (custom_format == eFormatVectorOfSInt32)4 || |
1138 | 8 | (custom_format == eFormatVectorOfSInt64)4 || |
1139 | 8 | (custom_format == eFormatVectorOfSInt8)4 || |
1140 | 8 | (custom_format == eFormatVectorOfUInt128)4 || |
1141 | 8 | (custom_format == eFormatVectorOfUInt16)4 || |
1142 | 8 | (custom_format == eFormatVectorOfUInt32)4 || |
1143 | 8 | (custom_format == eFormatVectorOfUInt64)0 || |
1144 | 8 | (custom_format == eFormatVectorOfUInt8)0 ) |
1145 | 8 | return true; |
1146 | 8 | } |
1147 | 44 | } |
1148 | 20 | return false; |
1149 | 1.48k | } |
1150 | | |
1151 | | bool ValueObject::DumpPrintableRepresentation( |
1152 | | Stream &s, ValueObjectRepresentationStyle val_obj_display, |
1153 | | Format custom_format, PrintableRepresentationSpecialCases special, |
1154 | 19.1k | bool do_dump_error) { |
1155 | | |
1156 | | // If the ValueObject has an error, we might end up dumping the type, which |
1157 | | // is useful, but if we don't even have a type, then don't examine the object |
1158 | | // further as that's not meaningful, only the error is. |
1159 | 19.1k | if (m_error.Fail() && !GetCompilerType().IsValid()4 ) { |
1160 | 0 | if (do_dump_error) |
1161 | 0 | s.Printf("<%s>", m_error.AsCString()); |
1162 | 0 | return false; |
1163 | 0 | } |
1164 | | |
1165 | 19.1k | Flags flags(GetTypeInfo()); |
1166 | | |
1167 | 19.1k | bool allow_special = |
1168 | 19.1k | (special == ValueObject::PrintableRepresentationSpecialCases::eAllow); |
1169 | 19.1k | const bool only_special = false; |
1170 | | |
1171 | 19.1k | if (allow_special) { |
1172 | 6.38k | if (flags.AnySet(eTypeIsArray | eTypeIsPointer) && |
1173 | 6.38k | val_obj_display == ValueObject::eValueObjectRepresentationStyleValue3.11k ) { |
1174 | | // when being asked to get a printable display an array or pointer type |
1175 | | // directly, try to "do the right thing" |
1176 | | |
1177 | 1.46k | if (IsCStringContainer(true) && |
1178 | 1.46k | (1.44k custom_format == eFormatCString1.44k || |
1179 | 1.44k | custom_format == eFormatCharArray962 || custom_format == eFormatChar946 || |
1180 | 1.44k | custom_format == |
1181 | 930 | eFormatVectorOfChar)) // print char[] & char* directly |
1182 | 1.44k | { |
1183 | 1.44k | Status error; |
1184 | 1.44k | lldb::WritableDataBufferSP buffer_sp; |
1185 | 1.44k | std::pair<size_t, bool> read_string = ReadPointedString( |
1186 | 1.44k | buffer_sp, error, 0, (custom_format == eFormatVectorOfChar) || |
1187 | 1.44k | (custom_format == eFormatCharArray)511 ); |
1188 | 1.44k | lldb_private::formatters::StringPrinter:: |
1189 | 1.44k | ReadBufferAndDumpToStreamOptions options(*this); |
1190 | 1.44k | options.SetData(DataExtractor( |
1191 | 1.44k | buffer_sp, lldb::eByteOrderInvalid, |
1192 | 1.44k | 8)); // none of this matters for a string - pass some defaults |
1193 | 1.44k | options.SetStream(&s); |
1194 | 1.44k | options.SetPrefixToken(nullptr); |
1195 | 1.44k | options.SetQuote('"'); |
1196 | 1.44k | options.SetSourceSize(buffer_sp->GetByteSize()); |
1197 | 1.44k | options.SetIsTruncated(read_string.second); |
1198 | 1.44k | options.SetBinaryZeroIsTerminator(custom_format != eFormatVectorOfChar); |
1199 | 1.44k | formatters::StringPrinter::ReadBufferAndDumpToStream< |
1200 | 1.44k | lldb_private::formatters::StringPrinter::StringElementType::ASCII>( |
1201 | 1.44k | options); |
1202 | 1.44k | return !error.Fail(); |
1203 | 1.44k | } |
1204 | | |
1205 | 24 | if (custom_format == eFormatEnum) |
1206 | 0 | return false; |
1207 | | |
1208 | | // this only works for arrays, because I have no way to know when the |
1209 | | // pointed memory ends, and no special \0 end of data marker |
1210 | 24 | if (flags.Test(eTypeIsArray)) { |
1211 | 24 | if ((custom_format == eFormatBytes) || |
1212 | 24 | (custom_format == eFormatBytesWithASCII)16 ) { |
1213 | 16 | const size_t count = GetNumChildren(); |
1214 | | |
1215 | 16 | s << '['; |
1216 | 112 | for (size_t low = 0; low < count; low++96 ) { |
1217 | | |
1218 | 96 | if (low) |
1219 | 80 | s << ','; |
1220 | | |
1221 | 96 | ValueObjectSP child = GetChildAtIndex(low); |
1222 | 96 | if (!child.get()) { |
1223 | 0 | s << "<invalid child>"; |
1224 | 0 | continue; |
1225 | 0 | } |
1226 | 96 | child->DumpPrintableRepresentation( |
1227 | 96 | s, ValueObject::eValueObjectRepresentationStyleValue, |
1228 | 96 | custom_format); |
1229 | 96 | } |
1230 | | |
1231 | 16 | s << ']'; |
1232 | | |
1233 | 16 | return true; |
1234 | 16 | } |
1235 | | |
1236 | 8 | if ((custom_format == eFormatVectorOfChar) || |
1237 | 8 | (custom_format == eFormatVectorOfFloat32) || |
1238 | 8 | (custom_format == eFormatVectorOfFloat64)4 || |
1239 | 8 | (custom_format == eFormatVectorOfSInt16)4 || |
1240 | 8 | (custom_format == eFormatVectorOfSInt32)4 || |
1241 | 8 | (custom_format == eFormatVectorOfSInt64)4 || |
1242 | 8 | (custom_format == eFormatVectorOfSInt8)4 || |
1243 | 8 | (custom_format == eFormatVectorOfUInt128)4 || |
1244 | 8 | (custom_format == eFormatVectorOfUInt16)4 || |
1245 | 8 | (custom_format == eFormatVectorOfUInt32)4 || |
1246 | 8 | (custom_format == eFormatVectorOfUInt64)0 || |
1247 | 8 | (custom_format == eFormatVectorOfUInt8)0 ) // arrays of bytes, bytes |
1248 | | // with ASCII or any vector |
1249 | | // format should be printed |
1250 | | // directly |
1251 | 8 | { |
1252 | 8 | const size_t count = GetNumChildren(); |
1253 | | |
1254 | 8 | Format format = FormatManager::GetSingleItemFormat(custom_format); |
1255 | | |
1256 | 8 | s << '['; |
1257 | 56 | for (size_t low = 0; low < count; low++48 ) { |
1258 | | |
1259 | 48 | if (low) |
1260 | 40 | s << ','; |
1261 | | |
1262 | 48 | ValueObjectSP child = GetChildAtIndex(low); |
1263 | 48 | if (!child.get()) { |
1264 | 0 | s << "<invalid child>"; |
1265 | 0 | continue; |
1266 | 0 | } |
1267 | 48 | child->DumpPrintableRepresentation( |
1268 | 48 | s, ValueObject::eValueObjectRepresentationStyleValue, format); |
1269 | 48 | } |
1270 | | |
1271 | 8 | s << ']'; |
1272 | | |
1273 | 8 | return true; |
1274 | 8 | } |
1275 | 8 | } |
1276 | | |
1277 | 0 | if ((custom_format == eFormatBoolean) || |
1278 | 0 | (custom_format == eFormatBinary) || (custom_format == eFormatChar) || |
1279 | 0 | (custom_format == eFormatCharPrintable) || |
1280 | 0 | (custom_format == eFormatComplexFloat) || |
1281 | 0 | (custom_format == eFormatDecimal) || (custom_format == eFormatHex) || |
1282 | 0 | (custom_format == eFormatHexUppercase) || |
1283 | 0 | (custom_format == eFormatFloat) || (custom_format == eFormatOctal) || |
1284 | 0 | (custom_format == eFormatOSType) || |
1285 | 0 | (custom_format == eFormatUnicode16) || |
1286 | 0 | (custom_format == eFormatUnicode32) || |
1287 | 0 | (custom_format == eFormatUnsigned) || |
1288 | 0 | (custom_format == eFormatPointer) || |
1289 | 0 | (custom_format == eFormatComplexInteger) || |
1290 | 0 | (custom_format == eFormatComplex) || |
1291 | 0 | (custom_format == eFormatDefault)) // use the [] operator |
1292 | 0 | return false; |
1293 | 0 | } |
1294 | 6.38k | } |
1295 | | |
1296 | 17.6k | if (only_special) |
1297 | 0 | return false; |
1298 | | |
1299 | 17.6k | bool var_success = false; |
1300 | | |
1301 | 17.6k | { |
1302 | 17.6k | llvm::StringRef str; |
1303 | | |
1304 | | // this is a local stream that we are using to ensure that the data pointed |
1305 | | // to by cstr survives long enough for us to copy it to its destination - |
1306 | | // it is necessary to have this temporary storage area for cases where our |
1307 | | // desired output is not backed by some other longer-term storage |
1308 | 17.6k | StreamString strm; |
1309 | | |
1310 | 17.6k | if (custom_format != eFormatInvalid) |
1311 | 362 | SetFormat(custom_format); |
1312 | | |
1313 | 17.6k | switch (val_obj_display) { |
1314 | 288 | case eValueObjectRepresentationStyleValue: |
1315 | 288 | str = GetValueAsCString(); |
1316 | 288 | break; |
1317 | | |
1318 | 16.5k | case eValueObjectRepresentationStyleSummary: |
1319 | 16.5k | str = GetSummaryAsCString(); |
1320 | 16.5k | break; |
1321 | | |
1322 | 4 | case eValueObjectRepresentationStyleLanguageSpecific: |
1323 | 4 | str = GetObjectDescription(); |
1324 | 4 | break; |
1325 | | |
1326 | 20 | case eValueObjectRepresentationStyleLocation: |
1327 | 20 | str = GetLocationAsCString(); |
1328 | 20 | break; |
1329 | | |
1330 | 832 | case eValueObjectRepresentationStyleChildrenCount: |
1331 | 832 | strm.Printf("%" PRIu64 "", (uint64_t)GetNumChildren()); |
1332 | 832 | str = strm.GetString(); |
1333 | 832 | break; |
1334 | | |
1335 | 10 | case eValueObjectRepresentationStyleType: |
1336 | 10 | str = GetTypeName().GetStringRef(); |
1337 | 10 | break; |
1338 | | |
1339 | 0 | case eValueObjectRepresentationStyleName: |
1340 | 0 | str = GetName().GetStringRef(); |
1341 | 0 | break; |
1342 | | |
1343 | 0 | case eValueObjectRepresentationStyleExpressionPath: |
1344 | 0 | GetExpressionPath(strm); |
1345 | 0 | str = strm.GetString(); |
1346 | 0 | break; |
1347 | 17.6k | } |
1348 | | |
1349 | 17.6k | if (str.empty()) { |
1350 | 14.5k | if (val_obj_display == eValueObjectRepresentationStyleValue) |
1351 | 0 | str = GetSummaryAsCString(); |
1352 | 14.5k | else if (val_obj_display == eValueObjectRepresentationStyleSummary) { |
1353 | 14.5k | if (!CanProvideValue()) { |
1354 | 61 | strm.Printf("%s @ %s", GetTypeName().AsCString(), |
1355 | 61 | GetLocationAsCString()); |
1356 | 61 | str = strm.GetString(); |
1357 | 61 | } else |
1358 | 14.4k | str = GetValueAsCString(); |
1359 | 14.5k | } |
1360 | 14.5k | } |
1361 | | |
1362 | 17.6k | if (!str.empty()) |
1363 | 17.5k | s << str; |
1364 | 106 | else { |
1365 | | // We checked for errors at the start, but do it again here in case |
1366 | | // realizing the value for dumping produced an error. |
1367 | 106 | if (m_error.Fail()) { |
1368 | 96 | if (do_dump_error) |
1369 | 8 | s.Printf("<%s>", m_error.AsCString()); |
1370 | 88 | else |
1371 | 88 | return false; |
1372 | 96 | } else if (10 val_obj_display == eValueObjectRepresentationStyleSummary10 ) |
1373 | 8 | s.PutCString("<no summary available>"); |
1374 | 2 | else if (val_obj_display == eValueObjectRepresentationStyleValue) |
1375 | 0 | s.PutCString("<no value available>"); |
1376 | 2 | else if (val_obj_display == |
1377 | 2 | eValueObjectRepresentationStyleLanguageSpecific) |
1378 | 2 | s.PutCString("<not a valid Objective-C object>"); // edit this if we |
1379 | | // have other runtimes |
1380 | | // that support a |
1381 | | // description |
1382 | 0 | else |
1383 | 0 | s.PutCString("<no printable representation>"); |
1384 | 106 | } |
1385 | | |
1386 | | // we should only return false here if we could not do *anything* even if |
1387 | | // we have an error message as output, that's a success from our callers' |
1388 | | // perspective, so return true |
1389 | 17.5k | var_success = true; |
1390 | | |
1391 | 17.5k | if (custom_format != eFormatInvalid) |
1392 | 362 | SetFormat(eFormatDefault); |
1393 | 17.5k | } |
1394 | | |
1395 | 0 | return var_success; |
1396 | 17.6k | } |
1397 | | |
1398 | | addr_t ValueObject::GetAddressOf(bool scalar_is_load_address, |
1399 | 6.93k | AddressType *address_type) { |
1400 | | // Can't take address of a bitfield |
1401 | 6.93k | if (IsBitfield()) |
1402 | 0 | return LLDB_INVALID_ADDRESS; |
1403 | | |
1404 | 6.93k | if (!UpdateValueIfNeeded(false)) |
1405 | 0 | return LLDB_INVALID_ADDRESS; |
1406 | | |
1407 | 6.93k | switch (m_value.GetValueType()) { |
1408 | 0 | case Value::ValueType::Invalid: |
1409 | 0 | return LLDB_INVALID_ADDRESS; |
1410 | 88 | case Value::ValueType::Scalar: |
1411 | 88 | if (scalar_is_load_address) { |
1412 | 60 | if (address_type) |
1413 | 15 | *address_type = eAddressTypeLoad; |
1414 | 60 | return m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS); |
1415 | 60 | } |
1416 | 28 | break; |
1417 | | |
1418 | 6.48k | case Value::ValueType::LoadAddress: |
1419 | 6.66k | case Value::ValueType::FileAddress: { |
1420 | 6.66k | if (address_type) |
1421 | 6.42k | *address_type = m_value.GetValueAddressType(); |
1422 | 6.66k | return m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS); |
1423 | 6.48k | } break0 ; |
1424 | 184 | case Value::ValueType::HostAddress: { |
1425 | 184 | if (address_type) |
1426 | 184 | *address_type = m_value.GetValueAddressType(); |
1427 | 184 | return LLDB_INVALID_ADDRESS; |
1428 | 6.48k | } break0 ; |
1429 | 6.93k | } |
1430 | 28 | if (address_type) |
1431 | 28 | *address_type = eAddressTypeInvalid; |
1432 | 28 | return LLDB_INVALID_ADDRESS; |
1433 | 6.93k | } |
1434 | | |
1435 | 40.4k | addr_t ValueObject::GetPointerValue(AddressType *address_type) { |
1436 | 40.4k | addr_t address = LLDB_INVALID_ADDRESS; |
1437 | 40.4k | if (address_type) |
1438 | 7.00k | *address_type = eAddressTypeInvalid; |
1439 | | |
1440 | 40.4k | if (!UpdateValueIfNeeded(false)) |
1441 | 0 | return address; |
1442 | | |
1443 | 40.4k | switch (m_value.GetValueType()) { |
1444 | 0 | case Value::ValueType::Invalid: |
1445 | 0 | return LLDB_INVALID_ADDRESS; |
1446 | 3.85k | case Value::ValueType::Scalar: |
1447 | 3.85k | address = m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS); |
1448 | 3.85k | break; |
1449 | | |
1450 | 4.44k | case Value::ValueType::HostAddress: |
1451 | 36.6k | case Value::ValueType::LoadAddress: |
1452 | 36.6k | case Value::ValueType::FileAddress: { |
1453 | 36.6k | lldb::offset_t data_offset = 0; |
1454 | 36.6k | address = m_data.GetAddress(&data_offset); |
1455 | 36.6k | } break; |
1456 | 40.4k | } |
1457 | | |
1458 | 40.4k | if (address_type) |
1459 | 7.00k | *address_type = GetAddressTypeOfChildren(); |
1460 | | |
1461 | 40.4k | return address; |
1462 | 40.4k | } |
1463 | | |
1464 | 16 | bool ValueObject::SetValueFromCString(const char *value_str, Status &error) { |
1465 | 16 | error.Clear(); |
1466 | | // Make sure our value is up to date first so that our location and location |
1467 | | // type is valid. |
1468 | 16 | if (!UpdateValueIfNeeded(false)) { |
1469 | 0 | error.SetErrorString("unable to read value"); |
1470 | 0 | return false; |
1471 | 0 | } |
1472 | | |
1473 | 16 | uint64_t count = 0; |
1474 | 16 | const Encoding encoding = GetCompilerType().GetEncoding(count); |
1475 | | |
1476 | 16 | const size_t byte_size = GetByteSize().value_or(0); |
1477 | | |
1478 | 16 | Value::ValueType value_type = m_value.GetValueType(); |
1479 | | |
1480 | 16 | if (value_type == Value::ValueType::Scalar) { |
1481 | | // If the value is already a scalar, then let the scalar change itself: |
1482 | 0 | m_value.GetScalar().SetValueFromCString(value_str, encoding, byte_size); |
1483 | 16 | } else if (byte_size <= 16) { |
1484 | | // If the value fits in a scalar, then make a new scalar and again let the |
1485 | | // scalar code do the conversion, then figure out where to put the new |
1486 | | // value. |
1487 | 16 | Scalar new_scalar; |
1488 | 16 | error = new_scalar.SetValueFromCString(value_str, encoding, byte_size); |
1489 | 16 | if (error.Success()) { |
1490 | 16 | switch (value_type) { |
1491 | 16 | case Value::ValueType::LoadAddress: { |
1492 | | // If it is a load address, then the scalar value is the storage |
1493 | | // location of the data, and we have to shove this value down to that |
1494 | | // load location. |
1495 | 16 | ExecutionContext exe_ctx(GetExecutionContextRef()); |
1496 | 16 | Process *process = exe_ctx.GetProcessPtr(); |
1497 | 16 | if (process) { |
1498 | 16 | addr_t target_addr = |
1499 | 16 | m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS); |
1500 | 16 | size_t bytes_written = process->WriteScalarToMemory( |
1501 | 16 | target_addr, new_scalar, byte_size, error); |
1502 | 16 | if (!error.Success()) |
1503 | 0 | return false; |
1504 | 16 | if (bytes_written != byte_size) { |
1505 | 0 | error.SetErrorString("unable to write value to memory"); |
1506 | 0 | return false; |
1507 | 0 | } |
1508 | 16 | } |
1509 | 16 | } break; |
1510 | 16 | case Value::ValueType::HostAddress: { |
1511 | | // If it is a host address, then we stuff the scalar as a DataBuffer |
1512 | | // into the Value's data. |
1513 | 0 | DataExtractor new_data; |
1514 | 0 | new_data.SetByteOrder(m_data.GetByteOrder()); |
1515 | |
|
1516 | 0 | DataBufferSP buffer_sp(new DataBufferHeap(byte_size, 0)); |
1517 | 0 | m_data.SetData(buffer_sp, 0); |
1518 | 0 | bool success = new_scalar.GetData(new_data); |
1519 | 0 | if (success) { |
1520 | 0 | new_data.CopyByteOrderedData( |
1521 | 0 | 0, byte_size, const_cast<uint8_t *>(m_data.GetDataStart()), |
1522 | 0 | byte_size, m_data.GetByteOrder()); |
1523 | 0 | } |
1524 | 0 | m_value.GetScalar() = (uintptr_t)m_data.GetDataStart(); |
1525 | |
|
1526 | 0 | } break; |
1527 | 0 | case Value::ValueType::Invalid: |
1528 | 0 | error.SetErrorString("invalid location"); |
1529 | 0 | return false; |
1530 | 0 | case Value::ValueType::FileAddress: |
1531 | 0 | case Value::ValueType::Scalar: |
1532 | 0 | break; |
1533 | 16 | } |
1534 | 16 | } else { |
1535 | 0 | return false; |
1536 | 0 | } |
1537 | 16 | } else { |
1538 | | // We don't support setting things bigger than a scalar at present. |
1539 | 0 | error.SetErrorString("unable to write aggregate data type"); |
1540 | 0 | return false; |
1541 | 0 | } |
1542 | | |
1543 | | // If we have reached this point, then we have successfully changed the |
1544 | | // value. |
1545 | 16 | SetNeedsUpdate(); |
1546 | 16 | return true; |
1547 | 16 | } |
1548 | | |
1549 | 3 | bool ValueObject::GetDeclaration(Declaration &decl) { |
1550 | 3 | decl.Clear(); |
1551 | 3 | return false; |
1552 | 3 | } |
1553 | | |
1554 | | void ValueObject::AddSyntheticChild(ConstString key, |
1555 | 2.13k | ValueObject *valobj) { |
1556 | 2.13k | m_synthetic_children[key] = valobj; |
1557 | 2.13k | } |
1558 | | |
1559 | 2.34k | ValueObjectSP ValueObject::GetSyntheticChild(ConstString key) const { |
1560 | 2.34k | ValueObjectSP synthetic_child_sp; |
1561 | 2.34k | std::map<ConstString, ValueObject *>::const_iterator pos = |
1562 | 2.34k | m_synthetic_children.find(key); |
1563 | 2.34k | if (pos != m_synthetic_children.end()) |
1564 | 211 | synthetic_child_sp = pos->second->GetSP(); |
1565 | 2.34k | return synthetic_child_sp; |
1566 | 2.34k | } |
1567 | | |
1568 | 126k | bool ValueObject::IsPossibleDynamicType() { |
1569 | 126k | ExecutionContext exe_ctx(GetExecutionContextRef()); |
1570 | 126k | Process *process = exe_ctx.GetProcessPtr(); |
1571 | 126k | if (process) |
1572 | 124k | return process->IsPossibleDynamicValue(*this); |
1573 | 1.58k | else |
1574 | 1.58k | return GetCompilerType().IsPossibleDynamicType(nullptr, true, true); |
1575 | 126k | } |
1576 | | |
1577 | 2.08k | bool ValueObject::IsRuntimeSupportValue() { |
1578 | 2.08k | Process *process(GetProcessSP().get()); |
1579 | 2.08k | if (!process) |
1580 | 321 | return false; |
1581 | | |
1582 | | // We trust that the compiler did the right thing and marked runtime support |
1583 | | // values as artificial. |
1584 | 1.76k | if (!GetVariable() || !GetVariable()->IsArtificial()1.75k ) |
1585 | 1.74k | return false; |
1586 | | |
1587 | 20 | if (auto *runtime = process->GetLanguageRuntime(GetVariable()->GetLanguage())) |
1588 | 18 | if (runtime->IsAllowedRuntimeValue(GetName())) |
1589 | 18 | return false; |
1590 | | |
1591 | 2 | return true; |
1592 | 20 | } |
1593 | | |
1594 | 38.9k | bool ValueObject::IsNilReference() { |
1595 | 38.9k | if (Language *language = Language::FindPlugin(GetObjectRuntimeLanguage())) { |
1596 | 10.7k | return language->IsNilReference(*this); |
1597 | 10.7k | } |
1598 | 28.2k | return false; |
1599 | 38.9k | } |
1600 | | |
1601 | 39.0k | bool ValueObject::IsUninitializedReference() { |
1602 | 39.0k | if (Language *language = Language::FindPlugin(GetObjectRuntimeLanguage())) { |
1603 | 10.8k | return language->IsUninitializedReference(*this); |
1604 | 10.8k | } |
1605 | 28.2k | return false; |
1606 | 39.0k | } |
1607 | | |
1608 | | // This allows you to create an array member using and index that doesn't not |
1609 | | // fall in the normal bounds of the array. Many times structure can be defined |
1610 | | // as: struct Collection { |
1611 | | // uint32_t item_count; |
1612 | | // Item item_array[0]; |
1613 | | // }; |
1614 | | // The size of the "item_array" is 1, but many times in practice there are more |
1615 | | // items in "item_array". |
1616 | | |
1617 | | ValueObjectSP ValueObject::GetSyntheticArrayMember(size_t index, |
1618 | 249 | bool can_create) { |
1619 | 249 | ValueObjectSP synthetic_child_sp; |
1620 | 249 | if (IsPointerType() || IsArrayType()4 ) { |
1621 | 249 | std::string index_str = llvm::formatv("[{0}]", index); |
1622 | 249 | ConstString index_const_str(index_str); |
1623 | | // Check if we have already created a synthetic array member in this valid |
1624 | | // object. If we have we will re-use it. |
1625 | 249 | synthetic_child_sp = GetSyntheticChild(index_const_str); |
1626 | 249 | if (!synthetic_child_sp) { |
1627 | 230 | ValueObject *synthetic_child; |
1628 | | // We haven't made a synthetic array member for INDEX yet, so lets make |
1629 | | // one and cache it for any future reference. |
1630 | 230 | synthetic_child = CreateChildAtIndex(0, true, index); |
1631 | | |
1632 | | // Cache the value if we got one back... |
1633 | 230 | if (synthetic_child) { |
1634 | 228 | AddSyntheticChild(index_const_str, synthetic_child); |
1635 | 228 | synthetic_child_sp = synthetic_child->GetSP(); |
1636 | 228 | synthetic_child_sp->SetName(ConstString(index_str)); |
1637 | 228 | synthetic_child_sp->m_flags.m_is_array_item_for_pointer = true; |
1638 | 228 | } |
1639 | 230 | } |
1640 | 249 | } |
1641 | 249 | return synthetic_child_sp; |
1642 | 249 | } |
1643 | | |
1644 | | ValueObjectSP ValueObject::GetSyntheticBitFieldChild(uint32_t from, uint32_t to, |
1645 | 46 | bool can_create) { |
1646 | 46 | ValueObjectSP synthetic_child_sp; |
1647 | 46 | if (IsScalarType()) { |
1648 | 46 | std::string index_str = llvm::formatv("[{0}-{1}]", from, to); |
1649 | 46 | ConstString index_const_str(index_str); |
1650 | | // Check if we have already created a synthetic array member in this valid |
1651 | | // object. If we have we will re-use it. |
1652 | 46 | synthetic_child_sp = GetSyntheticChild(index_const_str); |
1653 | 46 | if (!synthetic_child_sp) { |
1654 | 40 | uint32_t bit_field_size = to - from + 1; |
1655 | 40 | uint32_t bit_field_offset = from; |
1656 | 40 | if (GetDataExtractor().GetByteOrder() == eByteOrderBig) |
1657 | 0 | bit_field_offset = |
1658 | 0 | GetByteSize().value_or(0) * 8 - bit_field_size - bit_field_offset; |
1659 | | // We haven't made a synthetic array member for INDEX yet, so lets make |
1660 | | // one and cache it for any future reference. |
1661 | 40 | ValueObjectChild *synthetic_child = new ValueObjectChild( |
1662 | 40 | *this, GetCompilerType(), index_const_str, GetByteSize().value_or(0), |
1663 | 40 | 0, bit_field_size, bit_field_offset, false, false, |
1664 | 40 | eAddressTypeInvalid, 0); |
1665 | | |
1666 | | // Cache the value if we got one back... |
1667 | 40 | if (synthetic_child) { |
1668 | 40 | AddSyntheticChild(index_const_str, synthetic_child); |
1669 | 40 | synthetic_child_sp = synthetic_child->GetSP(); |
1670 | 40 | synthetic_child_sp->SetName(ConstString(index_str)); |
1671 | 40 | synthetic_child_sp->m_flags.m_is_bitfield_for_scalar = true; |
1672 | 40 | } |
1673 | 40 | } |
1674 | 46 | } |
1675 | 46 | return synthetic_child_sp; |
1676 | 46 | } |
1677 | | |
1678 | | ValueObjectSP ValueObject::GetSyntheticChildAtOffset( |
1679 | | uint32_t offset, const CompilerType &type, bool can_create, |
1680 | 1.97k | ConstString name_const_str) { |
1681 | | |
1682 | 1.97k | ValueObjectSP synthetic_child_sp; |
1683 | | |
1684 | 1.97k | if (name_const_str.IsEmpty()) { |
1685 | 1.56k | name_const_str.SetString("@" + std::to_string(offset)); |
1686 | 1.56k | } |
1687 | | |
1688 | | // Check if we have already created a synthetic array member in this valid |
1689 | | // object. If we have we will re-use it. |
1690 | 1.97k | synthetic_child_sp = GetSyntheticChild(name_const_str); |
1691 | | |
1692 | 1.97k | if (synthetic_child_sp.get()) |
1693 | 176 | return synthetic_child_sp; |
1694 | | |
1695 | 1.80k | if (!can_create) |
1696 | 0 | return {}; |
1697 | | |
1698 | 1.80k | ExecutionContext exe_ctx(GetExecutionContextRef()); |
1699 | 1.80k | std::optional<uint64_t> size = |
1700 | 1.80k | type.GetByteSize(exe_ctx.GetBestExecutionContextScope()); |
1701 | 1.80k | if (!size) |
1702 | 0 | return {}; |
1703 | 1.80k | ValueObjectChild *synthetic_child = |
1704 | 1.80k | new ValueObjectChild(*this, type, name_const_str, *size, offset, 0, 0, |
1705 | 1.80k | false, false, eAddressTypeInvalid, 0); |
1706 | 1.80k | if (synthetic_child) { |
1707 | 1.80k | AddSyntheticChild(name_const_str, synthetic_child); |
1708 | 1.80k | synthetic_child_sp = synthetic_child->GetSP(); |
1709 | 1.80k | synthetic_child_sp->SetName(name_const_str); |
1710 | 1.80k | synthetic_child_sp->m_flags.m_is_child_at_offset = true; |
1711 | 1.80k | } |
1712 | 1.80k | return synthetic_child_sp; |
1713 | 1.80k | } |
1714 | | |
1715 | | ValueObjectSP ValueObject::GetSyntheticBase(uint32_t offset, |
1716 | | const CompilerType &type, |
1717 | | bool can_create, |
1718 | 0 | ConstString name_const_str) { |
1719 | 0 | ValueObjectSP synthetic_child_sp; |
1720 | |
|
1721 | 0 | if (name_const_str.IsEmpty()) { |
1722 | 0 | char name_str[128]; |
1723 | 0 | snprintf(name_str, sizeof(name_str), "base%s@%i", |
1724 | 0 | type.GetTypeName().AsCString("<unknown>"), offset); |
1725 | 0 | name_const_str.SetCString(name_str); |
1726 | 0 | } |
1727 | | |
1728 | | // Check if we have already created a synthetic array member in this valid |
1729 | | // object. If we have we will re-use it. |
1730 | 0 | synthetic_child_sp = GetSyntheticChild(name_const_str); |
1731 | |
|
1732 | 0 | if (synthetic_child_sp.get()) |
1733 | 0 | return synthetic_child_sp; |
1734 | | |
1735 | 0 | if (!can_create) |
1736 | 0 | return {}; |
1737 | | |
1738 | 0 | const bool is_base_class = true; |
1739 | |
|
1740 | 0 | ExecutionContext exe_ctx(GetExecutionContextRef()); |
1741 | 0 | std::optional<uint64_t> size = |
1742 | 0 | type.GetByteSize(exe_ctx.GetBestExecutionContextScope()); |
1743 | 0 | if (!size) |
1744 | 0 | return {}; |
1745 | 0 | ValueObjectChild *synthetic_child = |
1746 | 0 | new ValueObjectChild(*this, type, name_const_str, *size, offset, 0, 0, |
1747 | 0 | is_base_class, false, eAddressTypeInvalid, 0); |
1748 | 0 | if (synthetic_child) { |
1749 | 0 | AddSyntheticChild(name_const_str, synthetic_child); |
1750 | 0 | synthetic_child_sp = synthetic_child->GetSP(); |
1751 | 0 | synthetic_child_sp->SetName(name_const_str); |
1752 | 0 | } |
1753 | 0 | return synthetic_child_sp; |
1754 | 0 | } |
1755 | | |
1756 | | // your expression path needs to have a leading . or -> (unless it somehow |
1757 | | // "looks like" an array, in which case it has a leading [ symbol). while the [ |
1758 | | // is meaningful and should be shown to the user, . and -> are just parser |
1759 | | // design, but by no means added information for the user.. strip them off |
1760 | 64 | static const char *SkipLeadingExpressionPathSeparators(const char *expression) { |
1761 | 64 | if (!expression || !expression[0]) |
1762 | 0 | return expression; |
1763 | 64 | if (expression[0] == '.') |
1764 | 64 | return expression + 1; |
1765 | 0 | if (expression[0] == '-' && expression[1] == '>') |
1766 | 0 | return expression + 2; |
1767 | 0 | return expression; |
1768 | 0 | } |
1769 | | |
1770 | | ValueObjectSP |
1771 | | ValueObject::GetSyntheticExpressionPathChild(const char *expression, |
1772 | 74 | bool can_create) { |
1773 | 74 | ValueObjectSP synthetic_child_sp; |
1774 | 74 | ConstString name_const_string(expression); |
1775 | | // Check if we have already created a synthetic array member in this valid |
1776 | | // object. If we have we will re-use it. |
1777 | 74 | synthetic_child_sp = GetSyntheticChild(name_const_string); |
1778 | 74 | if (!synthetic_child_sp) { |
1779 | | // We haven't made a synthetic array member for expression yet, so lets |
1780 | | // make one and cache it for any future reference. |
1781 | 64 | synthetic_child_sp = GetValueForExpressionPath( |
1782 | 64 | expression, nullptr, nullptr, |
1783 | 64 | GetValueForExpressionPathOptions().SetSyntheticChildrenTraversal( |
1784 | 64 | GetValueForExpressionPathOptions::SyntheticChildrenTraversal:: |
1785 | 64 | None)); |
1786 | | |
1787 | | // Cache the value if we got one back... |
1788 | 64 | if (synthetic_child_sp.get()) { |
1789 | | // FIXME: this causes a "real" child to end up with its name changed to |
1790 | | // the contents of expression |
1791 | 64 | AddSyntheticChild(name_const_string, synthetic_child_sp.get()); |
1792 | 64 | synthetic_child_sp->SetName( |
1793 | 64 | ConstString(SkipLeadingExpressionPathSeparators(expression))); |
1794 | 64 | } |
1795 | 64 | } |
1796 | 74 | return synthetic_child_sp; |
1797 | 74 | } |
1798 | | |
1799 | 139k | void ValueObject::CalculateSyntheticValue() { |
1800 | 139k | TargetSP target_sp(GetTargetSP()); |
1801 | 139k | if (target_sp && !target_sp->GetEnableSyntheticValue()) { |
1802 | 2 | m_synthetic_value = nullptr; |
1803 | 2 | return; |
1804 | 2 | } |
1805 | | |
1806 | 139k | lldb::SyntheticChildrenSP current_synth_sp(m_synthetic_children_sp); |
1807 | | |
1808 | 139k | if (!UpdateFormatsIfNeeded() && m_synthetic_value105k ) |
1809 | 17.1k | return; |
1810 | | |
1811 | 122k | if (m_synthetic_children_sp.get() == nullptr) |
1812 | 120k | return; |
1813 | | |
1814 | 1.84k | if (current_synth_sp == m_synthetic_children_sp && m_synthetic_value913 ) |
1815 | 9 | return; |
1816 | | |
1817 | 1.84k | m_synthetic_value = new ValueObjectSynthetic(*this, m_synthetic_children_sp); |
1818 | 1.84k | } |
1819 | | |
1820 | 79.8k | void ValueObject::CalculateDynamicValue(DynamicValueType use_dynamic) { |
1821 | 79.8k | if (use_dynamic == eNoDynamicValues) |
1822 | 0 | return; |
1823 | | |
1824 | 79.8k | if (!m_dynamic_value && !IsDynamic()) { |
1825 | 79.8k | ExecutionContext exe_ctx(GetExecutionContextRef()); |
1826 | 79.8k | Process *process = exe_ctx.GetProcessPtr(); |
1827 | 79.8k | if (process && process->IsPossibleDynamicValue(*this)78.0k ) { |
1828 | 1.21k | ClearDynamicTypeInformation(); |
1829 | 1.21k | m_dynamic_value = new ValueObjectDynamicValue(*this, use_dynamic); |
1830 | 1.21k | } |
1831 | 79.8k | } |
1832 | 79.8k | } |
1833 | | |
1834 | 80.7k | ValueObjectSP ValueObject::GetDynamicValue(DynamicValueType use_dynamic) { |
1835 | 80.7k | if (use_dynamic == eNoDynamicValues) |
1836 | 0 | return ValueObjectSP(); |
1837 | | |
1838 | 80.7k | if (!IsDynamic() && m_dynamic_value == nullptr) { |
1839 | 79.8k | CalculateDynamicValue(use_dynamic); |
1840 | 79.8k | } |
1841 | 80.7k | if (m_dynamic_value && m_dynamic_value->GetError().Success()2.13k ) |
1842 | 1.50k | return m_dynamic_value->GetSP(); |
1843 | 79.2k | else |
1844 | 79.2k | return ValueObjectSP(); |
1845 | 80.7k | } |
1846 | | |
1847 | 139k | ValueObjectSP ValueObject::GetSyntheticValue() { |
1848 | 139k | CalculateSyntheticValue(); |
1849 | | |
1850 | 139k | if (m_synthetic_value) |
1851 | 18.9k | return m_synthetic_value->GetSP(); |
1852 | 120k | else |
1853 | 120k | return ValueObjectSP(); |
1854 | 139k | } |
1855 | | |
1856 | 6.00k | bool ValueObject::HasSyntheticValue() { |
1857 | 6.00k | UpdateFormatsIfNeeded(); |
1858 | | |
1859 | 6.00k | if (m_synthetic_children_sp.get() == nullptr) |
1860 | 5.93k | return false; |
1861 | | |
1862 | 70 | CalculateSyntheticValue(); |
1863 | | |
1864 | 70 | return m_synthetic_value != nullptr; |
1865 | 6.00k | } |
1866 | | |
1867 | 2.90k | ValueObject *ValueObject::GetNonBaseClassParent() { |
1868 | 2.90k | if (GetParent()) { |
1869 | 1.87k | if (GetParent()->IsBaseClass()) |
1870 | 6 | return GetParent()->GetNonBaseClassParent(); |
1871 | 1.87k | else |
1872 | 1.87k | return GetParent(); |
1873 | 1.87k | } |
1874 | 1.02k | return nullptr; |
1875 | 2.90k | } |
1876 | | |
1877 | 0 | bool ValueObject::IsBaseClass(uint32_t &depth) { |
1878 | 0 | if (!IsBaseClass()) { |
1879 | 0 | depth = 0; |
1880 | 0 | return false; |
1881 | 0 | } |
1882 | 0 | if (GetParent()) { |
1883 | 0 | GetParent()->IsBaseClass(depth); |
1884 | 0 | depth = depth + 1; |
1885 | 0 | return true; |
1886 | 0 | } |
1887 | | // TODO: a base of no parent? weird.. |
1888 | 0 | depth = 1; |
1889 | 0 | return true; |
1890 | 0 | } |
1891 | | |
1892 | | void ValueObject::GetExpressionPath(Stream &s, |
1893 | 3.02k | GetExpressionPathFormat epformat) { |
1894 | | // synthetic children do not actually "exist" as part of the hierarchy, and |
1895 | | // sometimes they are consed up in ways that don't make sense from an |
1896 | | // underlying language/API standpoint. So, use a special code path here to |
1897 | | // return something that can hopefully be used in expression |
1898 | 3.02k | if (m_flags.m_is_synthetic_children_generated) { |
1899 | 4 | UpdateValueIfNeeded(); |
1900 | | |
1901 | 4 | if (m_value.GetValueType() == Value::ValueType::LoadAddress) { |
1902 | 2 | if (IsPointerOrReferenceType()) { |
1903 | 0 | s.Printf("((%s)0x%" PRIx64 ")", GetTypeName().AsCString("void"), |
1904 | 0 | GetValueAsUnsigned(0)); |
1905 | 0 | return; |
1906 | 2 | } else { |
1907 | 2 | uint64_t load_addr = |
1908 | 2 | m_value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS); |
1909 | 2 | if (load_addr != LLDB_INVALID_ADDRESS) { |
1910 | 2 | s.Printf("(*( (%s *)0x%" PRIx64 "))", GetTypeName().AsCString("void"), |
1911 | 2 | load_addr); |
1912 | 2 | return; |
1913 | 2 | } |
1914 | 2 | } |
1915 | 2 | } |
1916 | | |
1917 | 2 | if (CanProvideValue()) { |
1918 | 2 | s.Printf("((%s)%s)", GetTypeName().AsCString("void"), |
1919 | 2 | GetValueAsCString()); |
1920 | 2 | return; |
1921 | 2 | } |
1922 | | |
1923 | 0 | return; |
1924 | 2 | } |
1925 | | |
1926 | 3.01k | const bool is_deref_of_parent = IsDereferenceOfParent(); |
1927 | | |
1928 | 3.01k | if (is_deref_of_parent && |
1929 | 3.01k | epformat == eGetExpressionPathFormatDereferencePointers100 ) { |
1930 | | // this is the original format of GetExpressionPath() producing code like |
1931 | | // *(a_ptr).memberName, which is entirely fine, until you put this into |
1932 | | // StackFrame::GetValueForVariableExpressionPath() which prefers to see |
1933 | | // a_ptr->memberName. the eHonorPointers mode is meant to produce strings |
1934 | | // in this latter format |
1935 | 14 | s.PutCString("*("); |
1936 | 14 | } |
1937 | | |
1938 | 3.01k | ValueObject *parent = GetParent(); |
1939 | | |
1940 | 3.01k | if (parent) |
1941 | 1.98k | parent->GetExpressionPath(s, epformat); |
1942 | | |
1943 | | // if we are a deref_of_parent just because we are synthetic array members |
1944 | | // made up to allow ptr[%d] syntax to work in variable printing, then add our |
1945 | | // name ([%d]) to the expression path |
1946 | 3.01k | if (m_flags.m_is_array_item_for_pointer && |
1947 | 3.01k | epformat == eGetExpressionPathFormatHonorPointers17 ) |
1948 | 4 | s.PutCString(m_name.GetStringRef()); |
1949 | | |
1950 | 3.01k | if (!IsBaseClass()) { |
1951 | 3.00k | if (!is_deref_of_parent) { |
1952 | 2.90k | ValueObject *non_base_class_parent = GetNonBaseClassParent(); |
1953 | 2.90k | if (non_base_class_parent && |
1954 | 2.90k | !non_base_class_parent->GetName().IsEmpty()1.87k ) { |
1955 | 1.86k | CompilerType non_base_class_parent_compiler_type = |
1956 | 1.86k | non_base_class_parent->GetCompilerType(); |
1957 | 1.86k | if (non_base_class_parent_compiler_type) { |
1958 | 1.86k | if (parent && parent->IsDereferenceOfParent() && |
1959 | 1.86k | epformat == eGetExpressionPathFormatHonorPointers32 ) { |
1960 | 32 | s.PutCString("->"); |
1961 | 1.82k | } else { |
1962 | 1.82k | const uint32_t non_base_class_parent_type_info = |
1963 | 1.82k | non_base_class_parent_compiler_type.GetTypeInfo(); |
1964 | | |
1965 | 1.82k | if (non_base_class_parent_type_info & eTypeIsPointer) { |
1966 | 0 | s.PutCString("->"); |
1967 | 1.82k | } else if ((non_base_class_parent_type_info & eTypeHasChildren) && |
1968 | 1.82k | !(non_base_class_parent_type_info & eTypeIsArray)) { |
1969 | 1.81k | s.PutChar('.'); |
1970 | 1.81k | } |
1971 | 1.82k | } |
1972 | 1.86k | } |
1973 | 1.86k | } |
1974 | | |
1975 | 2.90k | const char *name = GetName().GetCString(); |
1976 | 2.90k | if (name) |
1977 | 2.89k | s.PutCString(name); |
1978 | 2.90k | } |
1979 | 3.00k | } |
1980 | | |
1981 | 3.01k | if (is_deref_of_parent && |
1982 | 3.01k | epformat == eGetExpressionPathFormatDereferencePointers100 ) { |
1983 | 14 | s.PutChar(')'); |
1984 | 14 | } |
1985 | 3.01k | } |
1986 | | |
1987 | | ValueObjectSP ValueObject::GetValueForExpressionPath( |
1988 | | llvm::StringRef expression, ExpressionPathScanEndReason *reason_to_stop, |
1989 | | ExpressionPathEndResultType *final_value_type, |
1990 | | const GetValueForExpressionPathOptions &options, |
1991 | 1.00k | ExpressionPathAftermath *final_task_on_target) { |
1992 | | |
1993 | 1.00k | ExpressionPathScanEndReason dummy_reason_to_stop = |
1994 | 1.00k | ValueObject::eExpressionPathScanEndReasonUnknown; |
1995 | 1.00k | ExpressionPathEndResultType dummy_final_value_type = |
1996 | 1.00k | ValueObject::eExpressionPathEndResultTypeInvalid; |
1997 | 1.00k | ExpressionPathAftermath dummy_final_task_on_target = |
1998 | 1.00k | ValueObject::eExpressionPathAftermathNothing; |
1999 | | |
2000 | 1.00k | ValueObjectSP ret_val = GetValueForExpressionPath_Impl( |
2001 | 1.00k | expression, reason_to_stop ? reason_to_stop811 : &dummy_reason_to_stop195 , |
2002 | 1.00k | final_value_type ? final_value_type811 : &dummy_final_value_type195 , options, |
2003 | 1.00k | final_task_on_target ? final_task_on_target811 |
2004 | 1.00k | : &dummy_final_task_on_target195 ); |
2005 | | |
2006 | 1.00k | if (!final_task_on_target || |
2007 | 1.00k | *final_task_on_target == ValueObject::eExpressionPathAftermathNothing811 ) |
2008 | 996 | return ret_val; |
2009 | | |
2010 | 10 | if (ret_val.get() && |
2011 | 10 | ((final_value_type ? *final_value_type : dummy_final_value_type0 ) == |
2012 | 10 | eExpressionPathEndResultTypePlain)) // I can only deref and takeaddress |
2013 | | // of plain objects |
2014 | 6 | { |
2015 | 6 | if ((final_task_on_target ? *final_task_on_target |
2016 | 6 | : dummy_final_task_on_target0 ) == |
2017 | 6 | ValueObject::eExpressionPathAftermathDereference) { |
2018 | 6 | Status error; |
2019 | 6 | ValueObjectSP final_value = ret_val->Dereference(error); |
2020 | 6 | if (error.Fail() || !final_value.get()) { |
2021 | 0 | if (reason_to_stop) |
2022 | 0 | *reason_to_stop = |
2023 | 0 | ValueObject::eExpressionPathScanEndReasonDereferencingFailed; |
2024 | 0 | if (final_value_type) |
2025 | 0 | *final_value_type = ValueObject::eExpressionPathEndResultTypeInvalid; |
2026 | 0 | return ValueObjectSP(); |
2027 | 6 | } else { |
2028 | 6 | if (final_task_on_target) |
2029 | 6 | *final_task_on_target = ValueObject::eExpressionPathAftermathNothing; |
2030 | 6 | return final_value; |
2031 | 6 | } |
2032 | 6 | } |
2033 | 0 | if (*final_task_on_target == |
2034 | 0 | ValueObject::eExpressionPathAftermathTakeAddress) { |
2035 | 0 | Status error; |
2036 | 0 | ValueObjectSP final_value = ret_val->AddressOf(error); |
2037 | 0 | if (error.Fail() || !final_value.get()) { |
2038 | 0 | if (reason_to_stop) |
2039 | 0 | *reason_to_stop = |
2040 | 0 | ValueObject::eExpressionPathScanEndReasonTakingAddressFailed; |
2041 | 0 | if (final_value_type) |
2042 | 0 | *final_value_type = ValueObject::eExpressionPathEndResultTypeInvalid; |
2043 | 0 | return ValueObjectSP(); |
2044 | 0 | } else { |
2045 | 0 | if (final_task_on_target) |
2046 | 0 | *final_task_on_target = ValueObject::eExpressionPathAftermathNothing; |
2047 | 0 | return final_value; |
2048 | 0 | } |
2049 | 0 | } |
2050 | 0 | } |
2051 | 4 | return ret_val; // final_task_on_target will still have its original value, so |
2052 | | // you know I did not do it |
2053 | 10 | } |
2054 | | |
2055 | | ValueObjectSP ValueObject::GetValueForExpressionPath_Impl( |
2056 | | llvm::StringRef expression, ExpressionPathScanEndReason *reason_to_stop, |
2057 | | ExpressionPathEndResultType *final_result, |
2058 | | const GetValueForExpressionPathOptions &options, |
2059 | 1.00k | ExpressionPathAftermath *what_next) { |
2060 | 1.00k | ValueObjectSP root = GetSP(); |
2061 | | |
2062 | 1.00k | if (!root) |
2063 | 0 | return nullptr; |
2064 | | |
2065 | 1.00k | llvm::StringRef remainder = expression; |
2066 | | |
2067 | 1.42k | while (true) { |
2068 | 1.42k | llvm::StringRef temp_expression = remainder; |
2069 | | |
2070 | 1.42k | CompilerType root_compiler_type = root->GetCompilerType(); |
2071 | 1.42k | CompilerType pointee_compiler_type; |
2072 | 1.42k | Flags pointee_compiler_type_info; |
2073 | | |
2074 | 1.42k | Flags root_compiler_type_info( |
2075 | 1.42k | root_compiler_type.GetTypeInfo(&pointee_compiler_type)); |
2076 | 1.42k | if (pointee_compiler_type) |
2077 | 376 | pointee_compiler_type_info.Reset(pointee_compiler_type.GetTypeInfo()); |
2078 | | |
2079 | 1.42k | if (temp_expression.empty()) { |
2080 | 226 | *reason_to_stop = ValueObject::eExpressionPathScanEndReasonEndOfString; |
2081 | 226 | return root; |
2082 | 226 | } |
2083 | | |
2084 | 1.20k | switch (temp_expression.front()) { |
2085 | 30 | case '-': { |
2086 | 30 | temp_expression = temp_expression.drop_front(); |
2087 | 30 | if (options.m_check_dot_vs_arrow_syntax && |
2088 | 30 | root_compiler_type_info.Test(eTypeIsPointer)0 ) // if you are trying to |
2089 | | // use -> on a |
2090 | | // non-pointer and I |
2091 | | // must catch the error |
2092 | 0 | { |
2093 | 0 | *reason_to_stop = |
2094 | 0 | ValueObject::eExpressionPathScanEndReasonArrowInsteadOfDot; |
2095 | 0 | *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; |
2096 | 0 | return ValueObjectSP(); |
2097 | 0 | } |
2098 | 30 | if (root_compiler_type_info.Test(eTypeIsObjC) && // if yo are trying to |
2099 | | // extract an ObjC IVar |
2100 | | // when this is forbidden |
2101 | 30 | root_compiler_type_info.Test(eTypeIsPointer)0 && |
2102 | 30 | options.m_no_fragile_ivar0 ) { |
2103 | 0 | *reason_to_stop = |
2104 | 0 | ValueObject::eExpressionPathScanEndReasonFragileIVarNotAllowed; |
2105 | 0 | *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; |
2106 | 0 | return ValueObjectSP(); |
2107 | 0 | } |
2108 | 30 | if (!temp_expression.startswith(">")) { |
2109 | 0 | *reason_to_stop = |
2110 | 0 | ValueObject::eExpressionPathScanEndReasonUnexpectedSymbol; |
2111 | 0 | *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; |
2112 | 0 | return ValueObjectSP(); |
2113 | 0 | } |
2114 | 30 | } |
2115 | 30 | [[fallthrough]]; |
2116 | 856 | case '.': // or fallthrough from -> |
2117 | 856 | { |
2118 | 856 | if (options.m_check_dot_vs_arrow_syntax && |
2119 | 856 | temp_expression.front() == '.'0 && |
2120 | 856 | root_compiler_type_info.Test(eTypeIsPointer)0 ) // if you are trying to |
2121 | | // use . on a pointer |
2122 | | // and I must catch the |
2123 | | // error |
2124 | 0 | { |
2125 | 0 | *reason_to_stop = |
2126 | 0 | ValueObject::eExpressionPathScanEndReasonDotInsteadOfArrow; |
2127 | 0 | *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; |
2128 | 0 | return nullptr; |
2129 | 0 | } |
2130 | 856 | temp_expression = temp_expression.drop_front(); // skip . or > |
2131 | | |
2132 | 856 | size_t next_sep_pos = temp_expression.find_first_of("-.[", 1); |
2133 | 856 | if (next_sep_pos == llvm::StringRef::npos) // if no other separator just |
2134 | | // expand this last layer |
2135 | 680 | { |
2136 | 680 | llvm::StringRef child_name = temp_expression; |
2137 | 680 | ValueObjectSP child_valobj_sp = |
2138 | 680 | root->GetChildMemberWithName(child_name); |
2139 | | |
2140 | 680 | if (child_valobj_sp.get()) // we know we are done, so just return |
2141 | 640 | { |
2142 | 640 | *reason_to_stop = |
2143 | 640 | ValueObject::eExpressionPathScanEndReasonEndOfString; |
2144 | 640 | *final_result = ValueObject::eExpressionPathEndResultTypePlain; |
2145 | 640 | return child_valobj_sp; |
2146 | 640 | } else { |
2147 | 40 | switch (options.m_synthetic_children_traversal) { |
2148 | 24 | case GetValueForExpressionPathOptions::SyntheticChildrenTraversal:: |
2149 | 24 | None: |
2150 | 24 | break; |
2151 | 0 | case GetValueForExpressionPathOptions::SyntheticChildrenTraversal:: |
2152 | 0 | FromSynthetic: |
2153 | 0 | if (root->IsSynthetic()) { |
2154 | 0 | child_valobj_sp = root->GetNonSyntheticValue(); |
2155 | 0 | if (child_valobj_sp.get()) |
2156 | 0 | child_valobj_sp = |
2157 | 0 | child_valobj_sp->GetChildMemberWithName(child_name); |
2158 | 0 | } |
2159 | 0 | break; |
2160 | 0 | case GetValueForExpressionPathOptions::SyntheticChildrenTraversal:: |
2161 | 0 | ToSynthetic: |
2162 | 0 | if (!root->IsSynthetic()) { |
2163 | 0 | child_valobj_sp = root->GetSyntheticValue(); |
2164 | 0 | if (child_valobj_sp.get()) |
2165 | 0 | child_valobj_sp = |
2166 | 0 | child_valobj_sp->GetChildMemberWithName(child_name); |
2167 | 0 | } |
2168 | 0 | break; |
2169 | 16 | case GetValueForExpressionPathOptions::SyntheticChildrenTraversal:: |
2170 | 16 | Both: |
2171 | 16 | if (root->IsSynthetic()) { |
2172 | 4 | child_valobj_sp = root->GetNonSyntheticValue(); |
2173 | 4 | if (child_valobj_sp.get()) |
2174 | 4 | child_valobj_sp = |
2175 | 4 | child_valobj_sp->GetChildMemberWithName(child_name); |
2176 | 12 | } else { |
2177 | 12 | child_valobj_sp = root->GetSyntheticValue(); |
2178 | 12 | if (child_valobj_sp.get()) |
2179 | 0 | child_valobj_sp = |
2180 | 0 | child_valobj_sp->GetChildMemberWithName(child_name); |
2181 | 12 | } |
2182 | 16 | break; |
2183 | 40 | } |
2184 | 40 | } |
2185 | | |
2186 | | // if we are here and options.m_no_synthetic_children is true, |
2187 | | // child_valobj_sp is going to be a NULL SP, so we hit the "else" |
2188 | | // branch, and return an error |
2189 | 40 | if (child_valobj_sp.get()) // if it worked, just return |
2190 | 4 | { |
2191 | 4 | *reason_to_stop = |
2192 | 4 | ValueObject::eExpressionPathScanEndReasonEndOfString; |
2193 | 4 | *final_result = ValueObject::eExpressionPathEndResultTypePlain; |
2194 | 4 | return child_valobj_sp; |
2195 | 36 | } else { |
2196 | 36 | *reason_to_stop = |
2197 | 36 | ValueObject::eExpressionPathScanEndReasonNoSuchChild; |
2198 | 36 | *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; |
2199 | 36 | return nullptr; |
2200 | 36 | } |
2201 | 40 | } else // other layers do expand |
2202 | 176 | { |
2203 | 176 | llvm::StringRef next_separator = temp_expression.substr(next_sep_pos); |
2204 | 176 | llvm::StringRef child_name = temp_expression.slice(0, next_sep_pos); |
2205 | | |
2206 | 176 | ValueObjectSP child_valobj_sp = |
2207 | 176 | root->GetChildMemberWithName(child_name); |
2208 | 176 | if (child_valobj_sp.get()) // store the new root and move on |
2209 | 176 | { |
2210 | 176 | root = child_valobj_sp; |
2211 | 176 | remainder = next_separator; |
2212 | 176 | *final_result = ValueObject::eExpressionPathEndResultTypePlain; |
2213 | 176 | continue; |
2214 | 176 | } else { |
2215 | 0 | switch (options.m_synthetic_children_traversal) { |
2216 | 0 | case GetValueForExpressionPathOptions::SyntheticChildrenTraversal:: |
2217 | 0 | None: |
2218 | 0 | break; |
2219 | 0 | case GetValueForExpressionPathOptions::SyntheticChildrenTraversal:: |
2220 | 0 | FromSynthetic: |
2221 | 0 | if (root->IsSynthetic()) { |
2222 | 0 | child_valobj_sp = root->GetNonSyntheticValue(); |
2223 | 0 | if (child_valobj_sp.get()) |
2224 | 0 | child_valobj_sp = |
2225 | 0 | child_valobj_sp->GetChildMemberWithName(child_name); |
2226 | 0 | } |
2227 | 0 | break; |
2228 | 0 | case GetValueForExpressionPathOptions::SyntheticChildrenTraversal:: |
2229 | 0 | ToSynthetic: |
2230 | 0 | if (!root->IsSynthetic()) { |
2231 | 0 | child_valobj_sp = root->GetSyntheticValue(); |
2232 | 0 | if (child_valobj_sp.get()) |
2233 | 0 | child_valobj_sp = |
2234 | 0 | child_valobj_sp->GetChildMemberWithName(child_name); |
2235 | 0 | } |
2236 | 0 | break; |
2237 | 0 | case GetValueForExpressionPathOptions::SyntheticChildrenTraversal:: |
2238 | 0 | Both: |
2239 | 0 | if (root->IsSynthetic()) { |
2240 | 0 | child_valobj_sp = root->GetNonSyntheticValue(); |
2241 | 0 | if (child_valobj_sp.get()) |
2242 | 0 | child_valobj_sp = |
2243 | 0 | child_valobj_sp->GetChildMemberWithName(child_name); |
2244 | 0 | } else { |
2245 | 0 | child_valobj_sp = root->GetSyntheticValue(); |
2246 | 0 | if (child_valobj_sp.get()) |
2247 | 0 | child_valobj_sp = |
2248 | 0 | child_valobj_sp->GetChildMemberWithName(child_name); |
2249 | 0 | } |
2250 | 0 | break; |
2251 | 0 | } |
2252 | 0 | } |
2253 | | |
2254 | | // if we are here and options.m_no_synthetic_children is true, |
2255 | | // child_valobj_sp is going to be a NULL SP, so we hit the "else" |
2256 | | // branch, and return an error |
2257 | 0 | if (child_valobj_sp.get()) // if it worked, move on |
2258 | 0 | { |
2259 | 0 | root = child_valobj_sp; |
2260 | 0 | remainder = next_separator; |
2261 | 0 | *final_result = ValueObject::eExpressionPathEndResultTypePlain; |
2262 | 0 | continue; |
2263 | 0 | } else { |
2264 | 0 | *reason_to_stop = |
2265 | 0 | ValueObject::eExpressionPathScanEndReasonNoSuchChild; |
2266 | 0 | *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; |
2267 | 0 | return nullptr; |
2268 | 0 | } |
2269 | 0 | } |
2270 | 0 | break; |
2271 | 856 | } |
2272 | 346 | case '[': { |
2273 | 346 | if (!root_compiler_type_info.Test(eTypeIsArray) && |
2274 | 346 | !root_compiler_type_info.Test(eTypeIsPointer)156 && |
2275 | 346 | !root_compiler_type_info.Test( |
2276 | 76 | eTypeIsVector)) // if this is not a T[] nor a T* |
2277 | 76 | { |
2278 | 76 | if (!root_compiler_type_info.Test( |
2279 | 76 | eTypeIsScalar)) // if this is not even a scalar... |
2280 | 30 | { |
2281 | 30 | if (options.m_synthetic_children_traversal == |
2282 | 30 | GetValueForExpressionPathOptions::SyntheticChildrenTraversal:: |
2283 | 30 | None) // ...only chance left is synthetic |
2284 | 0 | { |
2285 | 0 | *reason_to_stop = |
2286 | 0 | ValueObject::eExpressionPathScanEndReasonRangeOperatorInvalid; |
2287 | 0 | *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; |
2288 | 0 | return ValueObjectSP(); |
2289 | 0 | } |
2290 | 46 | } else if (!options.m_allow_bitfields_syntax) // if this is a scalar, |
2291 | | // check that we can |
2292 | | // expand bitfields |
2293 | 0 | { |
2294 | 0 | *reason_to_stop = |
2295 | 0 | ValueObject::eExpressionPathScanEndReasonRangeOperatorNotAllowed; |
2296 | 0 | *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; |
2297 | 0 | return ValueObjectSP(); |
2298 | 0 | } |
2299 | 76 | } |
2300 | 346 | if (temp_expression[1] == |
2301 | 346 | ']') // if this is an unbounded range it only works for arrays |
2302 | 28 | { |
2303 | 28 | if (!root_compiler_type_info.Test(eTypeIsArray)) { |
2304 | 8 | *reason_to_stop = |
2305 | 8 | ValueObject::eExpressionPathScanEndReasonEmptyRangeNotAllowed; |
2306 | 8 | *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; |
2307 | 8 | return nullptr; |
2308 | 8 | } else // even if something follows, we cannot expand unbounded ranges, |
2309 | | // just let the caller do it |
2310 | 20 | { |
2311 | 20 | *reason_to_stop = |
2312 | 20 | ValueObject::eExpressionPathScanEndReasonArrayRangeOperatorMet; |
2313 | 20 | *final_result = |
2314 | 20 | ValueObject::eExpressionPathEndResultTypeUnboundedRange; |
2315 | 20 | return root; |
2316 | 20 | } |
2317 | 28 | } |
2318 | | |
2319 | 318 | size_t close_bracket_position = temp_expression.find(']', 1); |
2320 | 318 | if (close_bracket_position == |
2321 | 318 | llvm::StringRef::npos) // if there is no ], this is a syntax error |
2322 | 0 | { |
2323 | 0 | *reason_to_stop = |
2324 | 0 | ValueObject::eExpressionPathScanEndReasonUnexpectedSymbol; |
2325 | 0 | *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; |
2326 | 0 | return nullptr; |
2327 | 0 | } |
2328 | | |
2329 | 318 | llvm::StringRef bracket_expr = |
2330 | 318 | temp_expression.slice(1, close_bracket_position); |
2331 | | |
2332 | | // If this was an empty expression it would have been caught by the if |
2333 | | // above. |
2334 | 318 | assert(!bracket_expr.empty()); |
2335 | | |
2336 | 318 | if (!bracket_expr.contains('-')) { |
2337 | | // if no separator, this is of the form [N]. Note that this cannot be |
2338 | | // an unbounded range of the form [], because that case was handled |
2339 | | // above with an unconditional return. |
2340 | 244 | unsigned long index = 0; |
2341 | 244 | if (bracket_expr.getAsInteger(0, index)) { |
2342 | 0 | *reason_to_stop = |
2343 | 0 | ValueObject::eExpressionPathScanEndReasonUnexpectedSymbol; |
2344 | 0 | *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; |
2345 | 0 | return nullptr; |
2346 | 0 | } |
2347 | | |
2348 | | // from here on we do have a valid index |
2349 | 244 | if (root_compiler_type_info.Test(eTypeIsArray)) { |
2350 | 158 | ValueObjectSP child_valobj_sp = root->GetChildAtIndex(index); |
2351 | 158 | if (!child_valobj_sp) |
2352 | 0 | child_valobj_sp = root->GetSyntheticArrayMember(index, true); |
2353 | 158 | if (!child_valobj_sp) |
2354 | 0 | if (root->HasSyntheticValue() && |
2355 | 0 | root->GetSyntheticValue()->GetNumChildren() > index) |
2356 | 0 | child_valobj_sp = |
2357 | 0 | root->GetSyntheticValue()->GetChildAtIndex(index); |
2358 | 158 | if (child_valobj_sp) { |
2359 | 158 | root = child_valobj_sp; |
2360 | 158 | remainder = |
2361 | 158 | temp_expression.substr(close_bracket_position + 1); // skip ] |
2362 | 158 | *final_result = ValueObject::eExpressionPathEndResultTypePlain; |
2363 | 158 | continue; |
2364 | 158 | } else { |
2365 | 0 | *reason_to_stop = |
2366 | 0 | ValueObject::eExpressionPathScanEndReasonNoSuchChild; |
2367 | 0 | *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; |
2368 | 0 | return nullptr; |
2369 | 0 | } |
2370 | 158 | } else if (86 root_compiler_type_info.Test(eTypeIsPointer)86 ) { |
2371 | 50 | if (*what_next == |
2372 | 50 | ValueObject:: |
2373 | 50 | eExpressionPathAftermathDereference && // if this is a |
2374 | | // ptr-to-scalar, I |
2375 | | // am accessing it |
2376 | | // by index and I |
2377 | | // would have |
2378 | | // deref'ed anyway, |
2379 | | // then do it now |
2380 | | // and use this as |
2381 | | // a bitfield |
2382 | 50 | pointee_compiler_type_info.Test(eTypeIsScalar)4 ) { |
2383 | 4 | Status error; |
2384 | 4 | root = root->Dereference(error); |
2385 | 4 | if (error.Fail() || !root) { |
2386 | 0 | *reason_to_stop = |
2387 | 0 | ValueObject::eExpressionPathScanEndReasonDereferencingFailed; |
2388 | 0 | *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; |
2389 | 0 | return nullptr; |
2390 | 4 | } else { |
2391 | 4 | *what_next = eExpressionPathAftermathNothing; |
2392 | 4 | continue; |
2393 | 4 | } |
2394 | 46 | } else { |
2395 | 46 | if (root->GetCompilerType().GetMinimumLanguage() == |
2396 | 46 | eLanguageTypeObjC && |
2397 | 46 | pointee_compiler_type_info.AllClear(eTypeIsPointer)0 && |
2398 | 46 | root->HasSyntheticValue()0 && |
2399 | 46 | (0 options.m_synthetic_children_traversal == |
2400 | 0 | GetValueForExpressionPathOptions:: |
2401 | 0 | SyntheticChildrenTraversal::ToSynthetic || |
2402 | 0 | options.m_synthetic_children_traversal == |
2403 | 0 | GetValueForExpressionPathOptions:: |
2404 | 0 | SyntheticChildrenTraversal::Both)) { |
2405 | 0 | root = root->GetSyntheticValue()->GetChildAtIndex(index); |
2406 | 0 | } else |
2407 | 46 | root = root->GetSyntheticArrayMember(index, true); |
2408 | 46 | if (!root) { |
2409 | 2 | *reason_to_stop = |
2410 | 2 | ValueObject::eExpressionPathScanEndReasonNoSuchChild; |
2411 | 2 | *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; |
2412 | 2 | return nullptr; |
2413 | 44 | } else { |
2414 | 44 | remainder = |
2415 | 44 | temp_expression.substr(close_bracket_position + 1); // skip ] |
2416 | 44 | *final_result = ValueObject::eExpressionPathEndResultTypePlain; |
2417 | 44 | continue; |
2418 | 44 | } |
2419 | 46 | } |
2420 | 50 | } else if (36 root_compiler_type_info.Test(eTypeIsScalar)36 ) { |
2421 | 6 | root = root->GetSyntheticBitFieldChild(index, index, true); |
2422 | 6 | if (!root) { |
2423 | 0 | *reason_to_stop = |
2424 | 0 | ValueObject::eExpressionPathScanEndReasonNoSuchChild; |
2425 | 0 | *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; |
2426 | 0 | return nullptr; |
2427 | 0 | } else // we do not know how to expand members of bitfields, so we |
2428 | | // just return and let the caller do any further processing |
2429 | 6 | { |
2430 | 6 | *reason_to_stop = ValueObject:: |
2431 | 6 | eExpressionPathScanEndReasonBitfieldRangeOperatorMet; |
2432 | 6 | *final_result = ValueObject::eExpressionPathEndResultTypeBitfield; |
2433 | 6 | return root; |
2434 | 6 | } |
2435 | 30 | } else if (root_compiler_type_info.Test(eTypeIsVector)) { |
2436 | 0 | root = root->GetChildAtIndex(index); |
2437 | 0 | if (!root) { |
2438 | 0 | *reason_to_stop = |
2439 | 0 | ValueObject::eExpressionPathScanEndReasonNoSuchChild; |
2440 | 0 | *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; |
2441 | 0 | return ValueObjectSP(); |
2442 | 0 | } else { |
2443 | 0 | remainder = |
2444 | 0 | temp_expression.substr(close_bracket_position + 1); // skip ] |
2445 | 0 | *final_result = ValueObject::eExpressionPathEndResultTypePlain; |
2446 | 0 | continue; |
2447 | 0 | } |
2448 | 30 | } else if (options.m_synthetic_children_traversal == |
2449 | 30 | GetValueForExpressionPathOptions:: |
2450 | 30 | SyntheticChildrenTraversal::ToSynthetic || |
2451 | 30 | options.m_synthetic_children_traversal == |
2452 | 30 | GetValueForExpressionPathOptions:: |
2453 | 30 | SyntheticChildrenTraversal::Both) { |
2454 | 30 | if (root->HasSyntheticValue()) |
2455 | 0 | root = root->GetSyntheticValue(); |
2456 | 30 | else if (!root->IsSynthetic()) { |
2457 | 0 | *reason_to_stop = |
2458 | 0 | ValueObject::eExpressionPathScanEndReasonSyntheticValueMissing; |
2459 | 0 | *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; |
2460 | 0 | return nullptr; |
2461 | 0 | } |
2462 | | // if we are here, then root itself is a synthetic VO.. should be |
2463 | | // good to go |
2464 | | |
2465 | 30 | if (!root) { |
2466 | 0 | *reason_to_stop = |
2467 | 0 | ValueObject::eExpressionPathScanEndReasonSyntheticValueMissing; |
2468 | 0 | *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; |
2469 | 0 | return nullptr; |
2470 | 0 | } |
2471 | 30 | root = root->GetChildAtIndex(index); |
2472 | 30 | if (!root) { |
2473 | 0 | *reason_to_stop = |
2474 | 0 | ValueObject::eExpressionPathScanEndReasonNoSuchChild; |
2475 | 0 | *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; |
2476 | 0 | return nullptr; |
2477 | 30 | } else { |
2478 | 30 | remainder = |
2479 | 30 | temp_expression.substr(close_bracket_position + 1); // skip ] |
2480 | 30 | *final_result = ValueObject::eExpressionPathEndResultTypePlain; |
2481 | 30 | continue; |
2482 | 30 | } |
2483 | 30 | } else { |
2484 | 0 | *reason_to_stop = |
2485 | 0 | ValueObject::eExpressionPathScanEndReasonNoSuchChild; |
2486 | 0 | *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; |
2487 | 0 | return nullptr; |
2488 | 0 | } |
2489 | 244 | } else { |
2490 | | // we have a low and a high index |
2491 | 74 | llvm::StringRef sleft, sright; |
2492 | 74 | unsigned long low_index, high_index; |
2493 | 74 | std::tie(sleft, sright) = bracket_expr.split('-'); |
2494 | 74 | if (sleft.getAsInteger(0, low_index) || |
2495 | 74 | sright.getAsInteger(0, high_index)) { |
2496 | 0 | *reason_to_stop = |
2497 | 0 | ValueObject::eExpressionPathScanEndReasonUnexpectedSymbol; |
2498 | 0 | *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; |
2499 | 0 | return nullptr; |
2500 | 0 | } |
2501 | | |
2502 | 74 | if (low_index > high_index) // swap indices if required |
2503 | 2 | std::swap(low_index, high_index); |
2504 | | |
2505 | 74 | if (root_compiler_type_info.Test( |
2506 | 74 | eTypeIsScalar)) // expansion only works for scalars |
2507 | 40 | { |
2508 | 40 | root = root->GetSyntheticBitFieldChild(low_index, high_index, true); |
2509 | 40 | if (!root) { |
2510 | 0 | *reason_to_stop = |
2511 | 0 | ValueObject::eExpressionPathScanEndReasonNoSuchChild; |
2512 | 0 | *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; |
2513 | 0 | return nullptr; |
2514 | 40 | } else { |
2515 | 40 | *reason_to_stop = ValueObject:: |
2516 | 40 | eExpressionPathScanEndReasonBitfieldRangeOperatorMet; |
2517 | 40 | *final_result = ValueObject::eExpressionPathEndResultTypeBitfield; |
2518 | 40 | return root; |
2519 | 40 | } |
2520 | 40 | } else if (34 root_compiler_type_info.Test( |
2521 | 34 | eTypeIsPointer) && // if this is a ptr-to-scalar, I am |
2522 | | // accessing it by index and I would |
2523 | | // have deref'ed anyway, then do it |
2524 | | // now and use this as a bitfield |
2525 | 34 | *what_next == |
2526 | 22 | ValueObject::eExpressionPathAftermathDereference && |
2527 | 34 | pointee_compiler_type_info.Test(eTypeIsScalar)10 ) { |
2528 | 10 | Status error; |
2529 | 10 | root = root->Dereference(error); |
2530 | 10 | if (error.Fail() || !root) { |
2531 | 0 | *reason_to_stop = |
2532 | 0 | ValueObject::eExpressionPathScanEndReasonDereferencingFailed; |
2533 | 0 | *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; |
2534 | 0 | return nullptr; |
2535 | 10 | } else { |
2536 | 10 | *what_next = ValueObject::eExpressionPathAftermathNothing; |
2537 | 10 | continue; |
2538 | 10 | } |
2539 | 24 | } else { |
2540 | 24 | *reason_to_stop = |
2541 | 24 | ValueObject::eExpressionPathScanEndReasonArrayRangeOperatorMet; |
2542 | 24 | *final_result = ValueObject::eExpressionPathEndResultTypeBoundedRange; |
2543 | 24 | return root; |
2544 | 24 | } |
2545 | 74 | } |
2546 | 0 | break; |
2547 | 318 | } |
2548 | 0 | default: // some non-separator is in the way |
2549 | 0 | { |
2550 | 0 | *reason_to_stop = |
2551 | 0 | ValueObject::eExpressionPathScanEndReasonUnexpectedSymbol; |
2552 | 0 | *final_result = ValueObject::eExpressionPathEndResultTypeInvalid; |
2553 | 0 | return nullptr; |
2554 | 318 | } |
2555 | 1.20k | } |
2556 | 1.20k | } |
2557 | 1.00k | } |
2558 | | |
2559 | 17.7k | void ValueObject::Dump(Stream &s) { Dump(s, DumpValueObjectOptions(*this)); } |
2560 | | |
2561 | 27.0k | void ValueObject::Dump(Stream &s, const DumpValueObjectOptions &options) { |
2562 | 27.0k | ValueObjectPrinter printer(this, &s, options); |
2563 | 27.0k | printer.PrintValueObject(); |
2564 | 27.0k | } |
2565 | | |
2566 | 273 | ValueObjectSP ValueObject::CreateConstantValue(ConstString name) { |
2567 | 273 | ValueObjectSP valobj_sp; |
2568 | | |
2569 | 273 | if (UpdateValueIfNeeded(false) && m_error.Success()) { |
2570 | 273 | ExecutionContext exe_ctx(GetExecutionContextRef()); |
2571 | | |
2572 | 273 | DataExtractor data; |
2573 | 273 | data.SetByteOrder(m_data.GetByteOrder()); |
2574 | 273 | data.SetAddressByteSize(m_data.GetAddressByteSize()); |
2575 | | |
2576 | 273 | if (IsBitfield()) { |
2577 | 0 | Value v(Scalar(GetValueAsUnsigned(UINT64_MAX))); |
2578 | 0 | m_error = v.GetValueAsData(&exe_ctx, data, GetModule().get()); |
2579 | 0 | } else |
2580 | 273 | m_error = m_value.GetValueAsData(&exe_ctx, data, GetModule().get()); |
2581 | | |
2582 | 273 | valobj_sp = ValueObjectConstResult::Create( |
2583 | 273 | exe_ctx.GetBestExecutionContextScope(), GetCompilerType(), name, data, |
2584 | 273 | GetAddressOf()); |
2585 | 273 | } |
2586 | | |
2587 | 273 | if (!valobj_sp) { |
2588 | 0 | ExecutionContext exe_ctx(GetExecutionContextRef()); |
2589 | 0 | valobj_sp = ValueObjectConstResult::Create( |
2590 | 0 | exe_ctx.GetBestExecutionContextScope(), m_error); |
2591 | 0 | } |
2592 | 273 | return valobj_sp; |
2593 | 273 | } |
2594 | | |
2595 | | ValueObjectSP ValueObject::GetQualifiedRepresentationIfAvailable( |
2596 | 268k | lldb::DynamicValueType dynValue, bool synthValue) { |
2597 | 268k | ValueObjectSP result_sp; |
2598 | 268k | switch (dynValue) { |
2599 | 1.16k | case lldb::eDynamicCanRunTarget: |
2600 | 9.00k | case lldb::eDynamicDontRunTarget: { |
2601 | 9.00k | if (!IsDynamic()) |
2602 | 6.25k | result_sp = GetDynamicValue(dynValue); |
2603 | 9.00k | } break; |
2604 | 259k | case lldb::eNoDynamicValues: { |
2605 | 259k | if (IsDynamic()) |
2606 | 1.38k | result_sp = GetStaticValue(); |
2607 | 259k | } break; |
2608 | 268k | } |
2609 | 268k | if (!result_sp) |
2610 | 266k | result_sp = GetSP(); |
2611 | 268k | assert(result_sp); |
2612 | | |
2613 | 268k | bool is_synthetic = result_sp->IsSynthetic(); |
2614 | 268k | if (synthValue && !is_synthetic11.4k ) { |
2615 | 6.77k | if (auto synth_sp = result_sp->GetSyntheticValue()) |
2616 | 202 | return synth_sp; |
2617 | 6.77k | } |
2618 | 267k | if (!synthValue && is_synthetic256k ) { |
2619 | 39 | if (auto non_synth_sp = result_sp->GetNonSyntheticValue()) |
2620 | 39 | return non_synth_sp; |
2621 | 39 | } |
2622 | | |
2623 | 267k | return result_sp; |
2624 | 267k | } |
2625 | | |
2626 | 1.58k | ValueObjectSP ValueObject::Dereference(Status &error) { |
2627 | 1.58k | if (m_deref_valobj) |
2628 | 279 | return m_deref_valobj->GetSP(); |
2629 | | |
2630 | 1.30k | const bool is_pointer_or_reference_type = IsPointerOrReferenceType(); |
2631 | 1.30k | if (is_pointer_or_reference_type) { |
2632 | 1.28k | bool omit_empty_base_classes = true; |
2633 | 1.28k | bool ignore_array_bounds = false; |
2634 | | |
2635 | 1.28k | std::string child_name_str; |
2636 | 1.28k | uint32_t child_byte_size = 0; |
2637 | 1.28k | int32_t child_byte_offset = 0; |
2638 | 1.28k | uint32_t child_bitfield_bit_size = 0; |
2639 | 1.28k | uint32_t child_bitfield_bit_offset = 0; |
2640 | 1.28k | bool child_is_base_class = false; |
2641 | 1.28k | bool child_is_deref_of_parent = false; |
2642 | 1.28k | const bool transparent_pointers = false; |
2643 | 1.28k | CompilerType compiler_type = GetCompilerType(); |
2644 | 1.28k | CompilerType child_compiler_type; |
2645 | 1.28k | uint64_t language_flags = 0; |
2646 | | |
2647 | 1.28k | ExecutionContext exe_ctx(GetExecutionContextRef()); |
2648 | | |
2649 | 1.28k | child_compiler_type = compiler_type.GetChildCompilerTypeAtIndex( |
2650 | 1.28k | &exe_ctx, 0, transparent_pointers, omit_empty_base_classes, |
2651 | 1.28k | ignore_array_bounds, child_name_str, child_byte_size, child_byte_offset, |
2652 | 1.28k | child_bitfield_bit_size, child_bitfield_bit_offset, child_is_base_class, |
2653 | 1.28k | child_is_deref_of_parent, this, language_flags); |
2654 | 1.28k | if (child_compiler_type && child_byte_size1.27k ) { |
2655 | 1.27k | ConstString child_name; |
2656 | 1.27k | if (!child_name_str.empty()) |
2657 | 1.27k | child_name.SetCString(child_name_str.c_str()); |
2658 | | |
2659 | 1.27k | m_deref_valobj = new ValueObjectChild( |
2660 | 1.27k | *this, child_compiler_type, child_name, child_byte_size, |
2661 | 1.27k | child_byte_offset, child_bitfield_bit_size, child_bitfield_bit_offset, |
2662 | 1.27k | child_is_base_class, child_is_deref_of_parent, eAddressTypeInvalid, |
2663 | 1.27k | language_flags); |
2664 | 1.27k | } |
2665 | | |
2666 | | // In case of incomplete child compiler type, use the pointee type and try |
2667 | | // to recreate a new ValueObjectChild using it. |
2668 | 1.28k | if (!m_deref_valobj) { |
2669 | | // FIXME(#59012): C++ stdlib formatters break with incomplete types (e.g. |
2670 | | // `std::vector<int> &`). Remove ObjC restriction once that's resolved. |
2671 | 11 | if (Language::LanguageIsObjC(GetPreferredDisplayLanguage()) && |
2672 | 11 | HasSyntheticValue()4 ) { |
2673 | 4 | child_compiler_type = compiler_type.GetPointeeType(); |
2674 | | |
2675 | 4 | if (child_compiler_type) { |
2676 | 4 | ConstString child_name; |
2677 | 4 | if (!child_name_str.empty()) |
2678 | 4 | child_name.SetCString(child_name_str.c_str()); |
2679 | | |
2680 | 4 | m_deref_valobj = new ValueObjectChild( |
2681 | 4 | *this, child_compiler_type, child_name, child_byte_size, |
2682 | 4 | child_byte_offset, child_bitfield_bit_size, |
2683 | 4 | child_bitfield_bit_offset, child_is_base_class, |
2684 | 4 | child_is_deref_of_parent, eAddressTypeInvalid, language_flags); |
2685 | 4 | } |
2686 | 4 | } |
2687 | 11 | } |
2688 | | |
2689 | 1.28k | } else if (15 HasSyntheticValue()15 ) { |
2690 | 9 | m_deref_valobj = |
2691 | 9 | GetSyntheticValue()->GetChildMemberWithName("$$dereference$$").get(); |
2692 | 9 | } else if (6 IsSynthetic()6 ) { |
2693 | 2 | m_deref_valobj = GetChildMemberWithName("$$dereference$$").get(); |
2694 | 2 | } |
2695 | | |
2696 | 1.30k | if (m_deref_valobj) { |
2697 | 1.29k | error.Clear(); |
2698 | 1.29k | return m_deref_valobj->GetSP(); |
2699 | 1.29k | } else { |
2700 | 11 | StreamString strm; |
2701 | 11 | GetExpressionPath(strm); |
2702 | | |
2703 | 11 | if (is_pointer_or_reference_type) |
2704 | 7 | error.SetErrorStringWithFormat("dereference failed: (%s) %s", |
2705 | 7 | GetTypeName().AsCString("<invalid type>"), |
2706 | 7 | strm.GetData()); |
2707 | 4 | else |
2708 | 4 | error.SetErrorStringWithFormat("not a pointer or reference type: (%s) %s", |
2709 | 4 | GetTypeName().AsCString("<invalid type>"), |
2710 | 4 | strm.GetData()); |
2711 | 11 | return ValueObjectSP(); |
2712 | 11 | } |
2713 | 1.30k | } |
2714 | | |
2715 | 196 | ValueObjectSP ValueObject::AddressOf(Status &error) { |
2716 | 196 | if (m_addr_of_valobj_sp) |
2717 | 66 | return m_addr_of_valobj_sp; |
2718 | | |
2719 | 130 | AddressType address_type = eAddressTypeInvalid; |
2720 | 130 | const bool scalar_is_load_address = false; |
2721 | 130 | addr_t addr = GetAddressOf(scalar_is_load_address, &address_type); |
2722 | 130 | error.Clear(); |
2723 | 130 | if (addr != LLDB_INVALID_ADDRESS && address_type != eAddressTypeHost124 ) { |
2724 | 124 | switch (address_type) { |
2725 | 0 | case eAddressTypeInvalid: { |
2726 | 0 | StreamString expr_path_strm; |
2727 | 0 | GetExpressionPath(expr_path_strm); |
2728 | 0 | error.SetErrorStringWithFormat("'%s' is not in memory", |
2729 | 0 | expr_path_strm.GetData()); |
2730 | 0 | } break; |
2731 | | |
2732 | 0 | case eAddressTypeFile: |
2733 | 124 | case eAddressTypeLoad: { |
2734 | 124 | CompilerType compiler_type = GetCompilerType(); |
2735 | 124 | if (compiler_type) { |
2736 | 124 | std::string name(1, '&'); |
2737 | 124 | name.append(m_name.AsCString("")); |
2738 | 124 | ExecutionContext exe_ctx(GetExecutionContextRef()); |
2739 | 124 | m_addr_of_valobj_sp = ValueObjectConstResult::Create( |
2740 | 124 | exe_ctx.GetBestExecutionContextScope(), |
2741 | 124 | compiler_type.GetPointerType(), ConstString(name.c_str()), addr, |
2742 | 124 | eAddressTypeInvalid, m_data.GetAddressByteSize()); |
2743 | 124 | } |
2744 | 124 | } break; |
2745 | 0 | default: |
2746 | 0 | break; |
2747 | 124 | } |
2748 | 124 | } else { |
2749 | 6 | StreamString expr_path_strm; |
2750 | 6 | GetExpressionPath(expr_path_strm); |
2751 | 6 | error.SetErrorStringWithFormat("'%s' doesn't have a valid address", |
2752 | 6 | expr_path_strm.GetData()); |
2753 | 6 | } |
2754 | | |
2755 | 130 | return m_addr_of_valobj_sp; |
2756 | 130 | } |
2757 | | |
2758 | 79 | ValueObjectSP ValueObject::DoCast(const CompilerType &compiler_type) { |
2759 | 79 | return ValueObjectCast::Create(*this, GetName(), compiler_type); |
2760 | 79 | } |
2761 | | |
2762 | 85 | ValueObjectSP ValueObject::Cast(const CompilerType &compiler_type) { |
2763 | | // Only allow casts if the original type is equal or larger than the cast |
2764 | | // type. We don't know how to fetch more data for all the ConstResult types, |
2765 | | // so we can't guarantee this will work: |
2766 | 85 | Status error; |
2767 | 85 | CompilerType my_type = GetCompilerType(); |
2768 | | |
2769 | 85 | ExecutionContextScope *exe_scope |
2770 | 85 | = ExecutionContext(GetExecutionContextRef()) |
2771 | 85 | .GetBestExecutionContextScope(); |
2772 | 85 | if (compiler_type.GetByteSize(exe_scope) |
2773 | 85 | <= GetCompilerType().GetByteSize(exe_scope)) { |
2774 | 83 | return DoCast(compiler_type); |
2775 | 83 | } |
2776 | 2 | error.SetErrorString("Can only cast to a type that is equal to or smaller " |
2777 | 2 | "than the orignal type."); |
2778 | | |
2779 | 2 | return ValueObjectConstResult::Create( |
2780 | 2 | ExecutionContext(GetExecutionContextRef()).GetBestExecutionContextScope(), |
2781 | 2 | error); |
2782 | 85 | } |
2783 | | |
2784 | 450 | lldb::ValueObjectSP ValueObject::Clone(ConstString new_name) { |
2785 | 450 | return ValueObjectCast::Create(*this, new_name, GetCompilerType()); |
2786 | 450 | } |
2787 | | |
2788 | | ValueObjectSP ValueObject::CastPointerType(const char *name, |
2789 | 0 | CompilerType &compiler_type) { |
2790 | 0 | ValueObjectSP valobj_sp; |
2791 | 0 | AddressType address_type; |
2792 | 0 | addr_t ptr_value = GetPointerValue(&address_type); |
2793 | |
|
2794 | 0 | if (ptr_value != LLDB_INVALID_ADDRESS) { |
2795 | 0 | Address ptr_addr(ptr_value); |
2796 | 0 | ExecutionContext exe_ctx(GetExecutionContextRef()); |
2797 | 0 | valobj_sp = ValueObjectMemory::Create( |
2798 | 0 | exe_ctx.GetBestExecutionContextScope(), name, ptr_addr, compiler_type); |
2799 | 0 | } |
2800 | 0 | return valobj_sp; |
2801 | 0 | } |
2802 | | |
2803 | 0 | ValueObjectSP ValueObject::CastPointerType(const char *name, TypeSP &type_sp) { |
2804 | 0 | ValueObjectSP valobj_sp; |
2805 | 0 | AddressType address_type; |
2806 | 0 | addr_t ptr_value = GetPointerValue(&address_type); |
2807 | |
|
2808 | 0 | if (ptr_value != LLDB_INVALID_ADDRESS) { |
2809 | 0 | Address ptr_addr(ptr_value); |
2810 | 0 | ExecutionContext exe_ctx(GetExecutionContextRef()); |
2811 | 0 | valobj_sp = ValueObjectMemory::Create( |
2812 | 0 | exe_ctx.GetBestExecutionContextScope(), name, ptr_addr, type_sp); |
2813 | 0 | } |
2814 | 0 | return valobj_sp; |
2815 | 0 | } |
2816 | | |
2817 | 0 | ValueObject::EvaluationPoint::EvaluationPoint() : m_mod_id(), m_exe_ctx_ref() {} |
2818 | | |
2819 | | ValueObject::EvaluationPoint::EvaluationPoint(ExecutionContextScope *exe_scope, |
2820 | | bool use_selected) |
2821 | 58.2k | : m_mod_id(), m_exe_ctx_ref() { |
2822 | 58.2k | ExecutionContext exe_ctx(exe_scope); |
2823 | 58.2k | TargetSP target_sp(exe_ctx.GetTargetSP()); |
2824 | 58.2k | if (target_sp) { |
2825 | 58.2k | m_exe_ctx_ref.SetTargetSP(target_sp); |
2826 | 58.2k | ProcessSP process_sp(exe_ctx.GetProcessSP()); |
2827 | 58.2k | if (!process_sp) |
2828 | 1.49k | process_sp = target_sp->GetProcessSP(); |
2829 | | |
2830 | 58.2k | if (process_sp) { |
2831 | 56.9k | m_mod_id = process_sp->GetModID(); |
2832 | 56.9k | m_exe_ctx_ref.SetProcessSP(process_sp); |
2833 | | |
2834 | 56.9k | ThreadSP thread_sp(exe_ctx.GetThreadSP()); |
2835 | | |
2836 | 56.9k | if (!thread_sp) { |
2837 | 575 | if (use_selected) |
2838 | 0 | thread_sp = process_sp->GetThreadList().GetSelectedThread(); |
2839 | 575 | } |
2840 | | |
2841 | 56.9k | if (thread_sp) { |
2842 | 56.3k | m_exe_ctx_ref.SetThreadSP(thread_sp); |
2843 | | |
2844 | 56.3k | StackFrameSP frame_sp(exe_ctx.GetFrameSP()); |
2845 | 56.3k | if (!frame_sp) { |
2846 | 86 | if (use_selected) |
2847 | 0 | frame_sp = thread_sp->GetSelectedFrame(DoNoSelectMostRelevantFrame); |
2848 | 86 | } |
2849 | 56.3k | if (frame_sp) |
2850 | 56.2k | m_exe_ctx_ref.SetFrameSP(frame_sp); |
2851 | 56.3k | } |
2852 | 56.9k | } |
2853 | 58.2k | } |
2854 | 58.2k | } |
2855 | | |
2856 | | ValueObject::EvaluationPoint::EvaluationPoint( |
2857 | | const ValueObject::EvaluationPoint &rhs) |
2858 | 51.2k | : m_mod_id(), m_exe_ctx_ref(rhs.m_exe_ctx_ref) {} |
2859 | | |
2860 | 89.3k | ValueObject::EvaluationPoint::~EvaluationPoint() = default; |
2861 | | |
2862 | | // This function checks the EvaluationPoint against the current process state. |
2863 | | // If the current state matches the evaluation point, or the evaluation point |
2864 | | // is already invalid, then we return false, meaning "no change". If the |
2865 | | // current state is different, we update our state, and return true meaning |
2866 | | // "yes, change". If we did see a change, we also set m_needs_update to true, |
2867 | | // so future calls to NeedsUpdate will return true. exe_scope will be set to |
2868 | | // the current execution context scope. |
2869 | | |
2870 | | bool ValueObject::EvaluationPoint::SyncWithProcessState( |
2871 | 663k | bool accept_invalid_exe_ctx) { |
2872 | | // Start with the target, if it is NULL, then we're obviously not going to |
2873 | | // get any further: |
2874 | 663k | const bool thread_and_frame_only_if_stopped = true; |
2875 | 663k | ExecutionContext exe_ctx( |
2876 | 663k | m_exe_ctx_ref.Lock(thread_and_frame_only_if_stopped)); |
2877 | | |
2878 | 663k | if (exe_ctx.GetTargetPtr() == nullptr) |
2879 | 0 | return false; |
2880 | | |
2881 | | // If we don't have a process nothing can change. |
2882 | 663k | Process *process = exe_ctx.GetProcessPtr(); |
2883 | 663k | if (process == nullptr) |
2884 | 10.5k | return false; |
2885 | | |
2886 | | // If our stop id is the current stop ID, nothing has changed: |
2887 | 653k | ProcessModID current_mod_id = process->GetModID(); |
2888 | | |
2889 | | // If the current stop id is 0, either we haven't run yet, or the process |
2890 | | // state has been cleared. In either case, we aren't going to be able to sync |
2891 | | // with the process state. |
2892 | 653k | if (current_mod_id.GetStopID() == 0) |
2893 | 0 | return false; |
2894 | | |
2895 | 653k | bool changed = false; |
2896 | 653k | const bool was_valid = m_mod_id.IsValid(); |
2897 | 653k | if (was_valid) { |
2898 | 653k | if (m_mod_id == current_mod_id) { |
2899 | | // Everything is already up to date in this object, no need to update the |
2900 | | // execution context scope. |
2901 | 602k | changed = false; |
2902 | 602k | } else { |
2903 | 50.5k | m_mod_id = current_mod_id; |
2904 | 50.5k | m_needs_update = true; |
2905 | 50.5k | changed = true; |
2906 | 50.5k | } |
2907 | 653k | } |
2908 | | |
2909 | | // Now re-look up the thread and frame in case the underlying objects have |
2910 | | // gone away & been recreated. That way we'll be sure to return a valid |
2911 | | // exe_scope. If we used to have a thread or a frame but can't find it |
2912 | | // anymore, then mark ourselves as invalid. |
2913 | | |
2914 | 653k | if (!accept_invalid_exe_ctx) { |
2915 | 546k | if (m_exe_ctx_ref.HasThreadRef()) { |
2916 | 542k | ThreadSP thread_sp(m_exe_ctx_ref.GetThreadSP()); |
2917 | 542k | if (thread_sp) { |
2918 | 542k | if (m_exe_ctx_ref.HasFrameRef()) { |
2919 | 541k | StackFrameSP frame_sp(m_exe_ctx_ref.GetFrameSP()); |
2920 | 541k | if (!frame_sp) { |
2921 | | // We used to have a frame, but now it is gone |
2922 | 282 | SetInvalid(); |
2923 | 282 | changed = was_valid; |
2924 | 282 | } |
2925 | 541k | } |
2926 | 542k | } else { |
2927 | | // We used to have a thread, but now it is gone |
2928 | 0 | SetInvalid(); |
2929 | 0 | changed = was_valid; |
2930 | 0 | } |
2931 | 542k | } |
2932 | 546k | } |
2933 | | |
2934 | 653k | return changed; |
2935 | 653k | } |
2936 | | |
2937 | 97.3k | void ValueObject::EvaluationPoint::SetUpdated() { |
2938 | 97.3k | ProcessSP process_sp(m_exe_ctx_ref.GetProcessSP()); |
2939 | 97.3k | if (process_sp) |
2940 | 95.6k | m_mod_id = process_sp->GetModID(); |
2941 | 97.3k | m_needs_update = false; |
2942 | 97.3k | } |
2943 | | |
2944 | 375k | void ValueObject::ClearUserVisibleData(uint32_t clear_mask) { |
2945 | 375k | if ((clear_mask & eClearUserVisibleDataItemsValue) == |
2946 | 375k | eClearUserVisibleDataItemsValue) |
2947 | 146k | m_value_str.clear(); |
2948 | | |
2949 | 375k | if ((clear_mask & eClearUserVisibleDataItemsLocation) == |
2950 | 375k | eClearUserVisibleDataItemsLocation) |
2951 | 65.6k | m_location_str.clear(); |
2952 | | |
2953 | 375k | if ((clear_mask & eClearUserVisibleDataItemsSummary) == |
2954 | 375k | eClearUserVisibleDataItemsSummary) |
2955 | 297k | m_summary_str.clear(); |
2956 | | |
2957 | 375k | if ((clear_mask & eClearUserVisibleDataItemsDescription) == |
2958 | 375k | eClearUserVisibleDataItemsDescription) |
2959 | 225k | m_object_desc_str.clear(); |
2960 | | |
2961 | 375k | if ((clear_mask & eClearUserVisibleDataItemsSyntheticChildren) == |
2962 | 375k | eClearUserVisibleDataItemsSyntheticChildren) { |
2963 | 3.59k | if (m_synthetic_value) |
2964 | 59 | m_synthetic_value = nullptr; |
2965 | 3.59k | } |
2966 | 375k | } |
2967 | | |
2968 | 0 | SymbolContextScope *ValueObject::GetSymbolContextScope() { |
2969 | 0 | if (m_parent) { |
2970 | 0 | if (!m_parent->IsPointerOrReferenceType()) |
2971 | 0 | return m_parent->GetSymbolContextScope(); |
2972 | 0 | } |
2973 | 0 | return nullptr; |
2974 | 0 | } |
2975 | | |
2976 | | lldb::ValueObjectSP |
2977 | | ValueObject::CreateValueObjectFromExpression(llvm::StringRef name, |
2978 | | llvm::StringRef expression, |
2979 | 9 | const ExecutionContext &exe_ctx) { |
2980 | 9 | return CreateValueObjectFromExpression(name, expression, exe_ctx, |
2981 | 9 | EvaluateExpressionOptions()); |
2982 | 9 | } |
2983 | | |
2984 | | lldb::ValueObjectSP ValueObject::CreateValueObjectFromExpression( |
2985 | | llvm::StringRef name, llvm::StringRef expression, |
2986 | 918 | const ExecutionContext &exe_ctx, const EvaluateExpressionOptions &options) { |
2987 | 918 | lldb::ValueObjectSP retval_sp; |
2988 | 918 | lldb::TargetSP target_sp(exe_ctx.GetTargetSP()); |
2989 | 918 | if (!target_sp) |
2990 | 0 | return retval_sp; |
2991 | 918 | if (expression.empty()) |
2992 | 2 | return retval_sp; |
2993 | 916 | target_sp->EvaluateExpression(expression, exe_ctx.GetFrameSP().get(), |
2994 | 916 | retval_sp, options); |
2995 | 916 | if (retval_sp && !name.empty()) |
2996 | 916 | retval_sp->SetName(ConstString(name)); |
2997 | 916 | return retval_sp; |
2998 | 918 | } |
2999 | | |
3000 | | lldb::ValueObjectSP ValueObject::CreateValueObjectFromAddress( |
3001 | | llvm::StringRef name, uint64_t address, const ExecutionContext &exe_ctx, |
3002 | 706 | CompilerType type) { |
3003 | 706 | if (type) { |
3004 | 705 | CompilerType pointer_type(type.GetPointerType()); |
3005 | 705 | if (pointer_type) { |
3006 | 705 | lldb::DataBufferSP buffer( |
3007 | 705 | new lldb_private::DataBufferHeap(&address, sizeof(lldb::addr_t))); |
3008 | 705 | lldb::ValueObjectSP ptr_result_valobj_sp(ValueObjectConstResult::Create( |
3009 | 705 | exe_ctx.GetBestExecutionContextScope(), pointer_type, |
3010 | 705 | ConstString(name), buffer, exe_ctx.GetByteOrder(), |
3011 | 705 | exe_ctx.GetAddressByteSize())); |
3012 | 705 | if (ptr_result_valobj_sp) { |
3013 | 705 | ptr_result_valobj_sp->GetValue().SetValueType( |
3014 | 705 | Value::ValueType::LoadAddress); |
3015 | 705 | Status err; |
3016 | 705 | ptr_result_valobj_sp = ptr_result_valobj_sp->Dereference(err); |
3017 | 705 | if (ptr_result_valobj_sp && !name.empty()) |
3018 | 705 | ptr_result_valobj_sp->SetName(ConstString(name)); |
3019 | 705 | } |
3020 | 705 | return ptr_result_valobj_sp; |
3021 | 705 | } |
3022 | 705 | } |
3023 | 1 | return lldb::ValueObjectSP(); |
3024 | 706 | } |
3025 | | |
3026 | | lldb::ValueObjectSP ValueObject::CreateValueObjectFromData( |
3027 | | llvm::StringRef name, const DataExtractor &data, |
3028 | 9.09k | const ExecutionContext &exe_ctx, CompilerType type) { |
3029 | 9.09k | lldb::ValueObjectSP new_value_sp; |
3030 | 9.09k | new_value_sp = ValueObjectConstResult::Create( |
3031 | 9.09k | exe_ctx.GetBestExecutionContextScope(), type, ConstString(name), data, |
3032 | 9.09k | LLDB_INVALID_ADDRESS); |
3033 | 9.09k | new_value_sp->SetAddressTypeOfChildren(eAddressTypeLoad); |
3034 | 9.09k | if (new_value_sp && !name.empty()) |
3035 | 9.09k | new_value_sp->SetName(ConstString(name)); |
3036 | 9.09k | return new_value_sp; |
3037 | 9.09k | } |
3038 | | |
3039 | 122k | ModuleSP ValueObject::GetModule() { |
3040 | 122k | ValueObject *root(GetRoot()); |
3041 | 122k | if (root != this) |
3042 | 75.9k | return root->GetModule(); |
3043 | 46.9k | return lldb::ModuleSP(); |
3044 | 122k | } |
3045 | | |
3046 | 280k | ValueObject *ValueObject::GetRoot() { |
3047 | 280k | if (m_root) |
3048 | 199k | return m_root; |
3049 | 116M | return (m_root = FollowParentChain([](ValueObject *vo) -> bool 81.1k { |
3050 | 116M | return (vo->m_parent != nullptr); |
3051 | 116M | })); |
3052 | 280k | } |
3053 | | |
3054 | | ValueObject * |
3055 | 126k | ValueObject::FollowParentChain(std::function<bool(ValueObject *)> f) { |
3056 | 126k | ValueObject *vo = this; |
3057 | 232M | while (vo) { |
3058 | 232M | if (!f(vo)) |
3059 | 81.9k | break; |
3060 | 232M | vo = vo->m_parent; |
3061 | 232M | } |
3062 | 126k | return vo; |
3063 | 126k | } |
3064 | | |
3065 | 33.5k | AddressType ValueObject::GetAddressTypeOfChildren() { |
3066 | 33.5k | if (m_address_type_of_ptr_or_ref_children == eAddressTypeInvalid) { |
3067 | 1.67k | ValueObject *root(GetRoot()); |
3068 | 1.67k | if (root != this) |
3069 | 1.67k | return root->GetAddressTypeOfChildren(); |
3070 | 1.67k | } |
3071 | 31.9k | return m_address_type_of_ptr_or_ref_children; |
3072 | 33.5k | } |
3073 | | |
3074 | 157k | lldb::DynamicValueType ValueObject::GetDynamicValueType() { |
3075 | 157k | ValueObject *with_dv_info = this; |
3076 | 231M | while (with_dv_info) { |
3077 | 231M | if (with_dv_info->HasDynamicValueTypeInfo()) |
3078 | 4.32k | return with_dv_info->GetDynamicValueTypeImpl(); |
3079 | 231M | with_dv_info = with_dv_info->m_parent; |
3080 | 231M | } |
3081 | 153k | return lldb::eNoDynamicValues; |
3082 | 157k | } |
3083 | | |
3084 | 67.8k | lldb::Format ValueObject::GetFormat() const { |
3085 | 67.8k | const ValueObject *with_fmt_info = this; |
3086 | 197k | while (with_fmt_info) { |
3087 | 130k | if (with_fmt_info->m_format != lldb::eFormatDefault) |
3088 | 1.01k | return with_fmt_info->m_format; |
3089 | 129k | with_fmt_info = with_fmt_info->m_parent; |
3090 | 129k | } |
3091 | 66.8k | return m_format; |
3092 | 67.8k | } |
3093 | | |
3094 | 41.5k | lldb::LanguageType ValueObject::GetPreferredDisplayLanguage() { |
3095 | 41.5k | lldb::LanguageType type = m_preferred_display_language; |
3096 | 41.5k | if (m_preferred_display_language == lldb::eLanguageTypeUnknown) { |
3097 | 15.4k | if (GetRoot()) { |
3098 | 15.4k | if (GetRoot() == this) { |
3099 | 8.18k | if (StackFrameSP frame_sp = GetFrameSP()) { |
3100 | 7.00k | const SymbolContext &sc( |
3101 | 7.00k | frame_sp->GetSymbolContext(eSymbolContextCompUnit)); |
3102 | 7.00k | if (CompileUnit *cu = sc.comp_unit) |
3103 | 7.00k | type = cu->GetLanguage(); |
3104 | 7.00k | } |
3105 | 8.18k | } else { |
3106 | 7.31k | type = GetRoot()->GetPreferredDisplayLanguage(); |
3107 | 7.31k | } |
3108 | 15.4k | } |
3109 | 15.4k | } |
3110 | 41.5k | return (m_preferred_display_language = type); // only compute it once |
3111 | 41.5k | } |
3112 | | |
3113 | 11.1k | void ValueObject::SetPreferredDisplayLanguageIfNeeded(lldb::LanguageType lt) { |
3114 | 11.1k | if (m_preferred_display_language == lldb::eLanguageTypeUnknown) |
3115 | 10.1k | SetPreferredDisplayLanguage(lt); |
3116 | 11.1k | } |
3117 | | |
3118 | 112k | bool ValueObject::CanProvideValue() { |
3119 | | // we need to support invalid types as providers of values because some bare- |
3120 | | // board debugging scenarios have no notion of types, but still manage to |
3121 | | // have raw numeric values for things like registers. sigh. |
3122 | 112k | CompilerType type = GetCompilerType(); |
3123 | 112k | return (!type.IsValid()) || (0 != (type.GetTypeInfo() & eTypeHasValue))111k ; |
3124 | 112k | } |
3125 | | |
3126 | | |
3127 | | |
3128 | 3 | ValueObjectSP ValueObject::Persist() { |
3129 | 3 | if (!UpdateValueIfNeeded()) |
3130 | 0 | return nullptr; |
3131 | | |
3132 | 3 | TargetSP target_sp(GetTargetSP()); |
3133 | 3 | if (!target_sp) |
3134 | 0 | return nullptr; |
3135 | | |
3136 | 3 | PersistentExpressionState *persistent_state = |
3137 | 3 | target_sp->GetPersistentExpressionStateForLanguage( |
3138 | 3 | GetPreferredDisplayLanguage()); |
3139 | | |
3140 | 3 | if (!persistent_state) |
3141 | 0 | return nullptr; |
3142 | | |
3143 | 3 | ConstString name = persistent_state->GetNextPersistentVariableName(); |
3144 | | |
3145 | 3 | ValueObjectSP const_result_sp = |
3146 | 3 | ValueObjectConstResult::Create(target_sp.get(), GetValue(), name); |
3147 | | |
3148 | 3 | ExpressionVariableSP persistent_var_sp = |
3149 | 3 | persistent_state->CreatePersistentVariable(const_result_sp); |
3150 | 3 | persistent_var_sp->m_live_sp = persistent_var_sp->m_frozen_sp; |
3151 | 3 | persistent_var_sp->m_flags |= ExpressionVariable::EVIsProgramReference; |
3152 | | |
3153 | 3 | return persistent_var_sp->GetValueObject(); |
3154 | 3 | } |
3155 | | |
3156 | 7 | lldb::ValueObjectSP ValueObject::GetVTable() { |
3157 | 7 | return ValueObjectVTable::Create(*this); |
3158 | 7 | } |