LLDB mainline
Materializer.cpp
Go to the documentation of this file.
1//===-- Materializer.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
12#include "lldb/Symbol/Symbol.h"
13#include "lldb/Symbol/Type.h"
18#include "lldb/Target/Target.h"
19#include "lldb/Target/Thread.h"
21#include "lldb/Utility/Log.h"
25#include "lldb/lldb-forward.h"
26
27#include <memory>
28#include <optional>
29
30using namespace lldb_private;
31
32// FIXME: these should be retrieved from the target
33// instead of being hard-coded. Currently we
34// assume that persistent vars are materialized
35// as references, and thus pick the size of a
36// 64-bit pointer.
37static constexpr uint32_t g_default_var_alignment = 8;
38static constexpr uint32_t g_default_var_byte_size = 8;
39
41 uint32_t size = entity.GetSize();
42 uint32_t alignment = entity.GetAlignment();
43
44 uint32_t ret;
45
46 if (m_current_offset == 0)
47 m_struct_alignment = alignment;
48
49 if (m_current_offset % alignment)
50 m_current_offset += (alignment - (m_current_offset % alignment));
51
52 ret = m_current_offset;
53
54 m_current_offset += size;
55
56 return ret;
57}
58
60public:
63 : Entity(), m_persistent_variable_sp(persistent_variable_sp),
64 m_delegate(delegate) {
65 // Hard-coding to maximum size of a pointer since persistent variables are
66 // materialized by reference
69 }
70
73
74 // Allocate a spare memory area to store the persistent variable's
75 // contents.
76
77 const bool zero_memory = false;
79 auto address_or_error = map.Malloc(
80 llvm::expectedToOptional(m_persistent_variable_sp->GetByteSize())
81 .value_or(0),
82 8, lldb::ePermissionsReadable | lldb::ePermissionsWritable,
83 IRMemoryMap::eAllocationPolicyMirror, zero_memory, &used_policy);
84 if (!address_or_error) {
86 "couldn't allocate a memory area to store %s: %s",
87 m_persistent_variable_sp->GetName().GetCString(),
88 toString(address_or_error.takeError()).c_str());
89 return;
90 }
91 lldb::addr_t mem = *address_or_error;
92
93 LLDB_LOGF(log, "Allocated %s (0x%" PRIx64 ") successfully",
94 m_persistent_variable_sp->GetName().GetCString(), mem);
95
96 // Put the location of the spare memory into the live data of the
97 // ValueObject.
98
101 m_persistent_variable_sp->GetCompilerType(),
103 map.GetAddressByteSize());
104
105 if (used_policy == IRMemoryMap::eAllocationPolicyMirror) {
106 if (m_persistent_variable_sp->m_flags &
108 // Clear the flag if the variable will never be deallocated.
109 Status leak_error;
110 map.Leak(mem, leak_error);
111 m_persistent_variable_sp->m_flags &=
112 ~ExpressionVariable::EVNeedsAllocation;
113 }
114 } else {
115 // If we cannot allocate memory in the process,
116 // - clear the 'EVKeepInTarget' flag to ensure that 'm_live_sp' is reset
117 // during dematerialization,
118 m_persistent_variable_sp->m_flags &= ~ExpressionVariable::EVKeepInTarget;
119 // - set the 'EVNeedsFreezeDry' flag so that the value is copied to
120 // 'm_frozen_sp' during dematerialization.
122 }
123
124 // Write the contents of the variable to the area.
125
126 Status write_error;
127
128 map.WriteMemory(
129 mem, m_persistent_variable_sp->GetValueBytes(),
130 llvm::expectedToOptional(m_persistent_variable_sp->GetByteSize())
131 .value_or(0),
132 write_error);
133
134 if (!write_error.Success()) {
136 "couldn't write {0} to the target: {1}",
137 m_persistent_variable_sp->GetName(), write_error.AsCString());
138 return;
139 }
140 }
141
143 Status deallocate_error;
144
145 map.Free((lldb::addr_t)m_persistent_variable_sp->m_live_sp->GetValue()
146 .GetScalar()
147 .ULongLong(),
148 deallocate_error);
149
150 m_persistent_variable_sp->m_live_sp.reset();
151
152 if (!deallocate_error.Success()) {
154 "couldn't deallocate memory for %s: %s",
155 m_persistent_variable_sp->GetName().GetCString(),
156 deallocate_error.AsCString());
157 }
158 }
159
161 lldb::addr_t process_address, Status &err) override {
163
164 const lldb::addr_t load_addr = process_address + m_offset;
165
166 LLDB_LOG(log,
167 "EntityPersistentVariable::Materialize [address = {0:x}, m_name = "
168 "{1}, m_flags = {2:x}]",
169 (uint64_t)load_addr, m_persistent_variable_sp->GetName(),
170 m_persistent_variable_sp->m_flags);
171
172 if (m_persistent_variable_sp->m_flags &
174 MakeAllocation(map, err);
175 m_persistent_variable_sp->m_flags |=
177
178 if (!err.Success())
179 return;
180 }
181
182 if ((m_persistent_variable_sp->m_flags &
184 m_persistent_variable_sp->m_live_sp) ||
185 m_persistent_variable_sp->m_flags &
187 Status write_error;
188
190 load_addr,
191 m_persistent_variable_sp->m_live_sp->GetValue().GetScalar(),
192 map.GetAddressByteSize(), write_error);
193
194 if (!write_error.Success()) {
196 "couldn't write the location of {0} to memory: {1}",
197 m_persistent_variable_sp->GetName(), write_error.AsCString());
198 }
199 } else {
201 "no materialization happened for persistent variable {0}",
202 m_persistent_variable_sp->GetName());
203 return;
204 }
205 }
206
208 lldb::addr_t process_address, lldb::addr_t frame_top,
209 lldb::addr_t frame_bottom, Status &err) override {
211
212 const lldb::addr_t load_addr = process_address + m_offset;
213
214 LLDB_LOG(log,
215 "EntityPersistentVariable::Dematerialize [address = {0:x}, m_name "
216 "= {1}, m_flags = {2}]",
217 (uint64_t)process_address + m_offset,
218 m_persistent_variable_sp->GetName(),
219 m_persistent_variable_sp->m_flags);
220
221 if (m_delegate) {
222 m_delegate->DidDematerialize(m_persistent_variable_sp);
223 }
224
225 if ((m_persistent_variable_sp->m_flags &
227 (m_persistent_variable_sp->m_flags &
229 if (m_persistent_variable_sp->m_flags &
231 !m_persistent_variable_sp->m_live_sp) {
232 // If the reference comes from the program, then the
233 // ClangExpressionVariable's live variable data hasn't been set up yet.
234 // Do this now.
235
236 lldb::addr_t location;
237 Status read_error;
238
239 map.ReadPointerFromMemory(&location, load_addr, read_error);
240
241 if (!read_error.Success()) {
243 "couldn't read the address of program-allocated variable %s: %s",
244 m_persistent_variable_sp->GetName().GetCString(),
245 read_error.AsCString());
246 return;
247 }
248
251 m_persistent_variable_sp.get()->GetCompilerType(),
252 m_persistent_variable_sp->GetName(), location, eAddressTypeLoad,
253 llvm::expectedToOptional(m_persistent_variable_sp->GetByteSize())
254 .value_or(0));
255
256 if (frame_top != LLDB_INVALID_ADDRESS &&
257 frame_bottom != LLDB_INVALID_ADDRESS && location >= frame_bottom &&
258 location <= frame_top) {
259 // If the variable is resident in the stack frame created by the
260 // expression, then it cannot be relied upon to stay around. We
261 // treat it as needing reallocation.
262 m_persistent_variable_sp->m_flags |=
264 m_persistent_variable_sp->m_flags |=
266 m_persistent_variable_sp->m_flags |=
268 m_persistent_variable_sp->m_flags &=
269 ~ExpressionVariable::EVIsProgramReference;
270 }
271 }
272
273 lldb::addr_t mem = m_persistent_variable_sp->m_live_sp->GetValue()
274 .GetScalar()
275 .ULongLong();
276
277 if (!m_persistent_variable_sp->m_live_sp) {
279 "couldn't find the memory area used to store %s",
280 m_persistent_variable_sp->GetName().GetCString());
281 return;
282 }
283
284 if (m_persistent_variable_sp->m_live_sp->GetValue()
285 .GetValueAddressType() != eAddressTypeLoad) {
287 "the address of the memory area for %s is in an incorrect format",
288 m_persistent_variable_sp->GetName().GetCString());
289 return;
290 }
291
292 if (m_persistent_variable_sp->m_flags &
294 m_persistent_variable_sp->m_flags &
296 LLDB_LOGF(log, "Dematerializing %s from 0x%" PRIx64 " (size = %llu)",
297 m_persistent_variable_sp->GetName().GetCString(),
298 (uint64_t)mem,
299 (unsigned long long)llvm::expectedToOptional(
300 m_persistent_variable_sp->GetByteSize())
301 .value_or(0));
302
303 // Read the contents of the spare memory area
304
305 m_persistent_variable_sp->ValueUpdated();
306
307 Status read_error;
308
309 map.ReadMemory(
310 m_persistent_variable_sp->GetValueBytes(), mem,
311 llvm::expectedToOptional(m_persistent_variable_sp->GetByteSize())
312 .value_or(0),
313 read_error);
314
315 if (!read_error.Success()) {
317 "couldn't read the contents of %s from memory: %s",
318 m_persistent_variable_sp->GetName().GetCString(),
319 read_error.AsCString());
320 return;
321 }
322
323 m_persistent_variable_sp->m_flags &=
324 ~ExpressionVariable::EVNeedsFreezeDry;
325 }
326 } else {
328 "no dematerialization happened for persistent variable {0}",
329 m_persistent_variable_sp->GetName());
330 return;
331 }
332
333 if (m_persistent_variable_sp->m_flags &
335 !(m_persistent_variable_sp->m_flags &
337 DestroyAllocation(map, err);
338 if (!err.Success())
339 return;
340 }
341 }
342
343 void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
344 Log *log) override {
345 StreamString dump_stream;
346
347 Status err;
348
349 const lldb::addr_t load_addr = process_address + m_offset;
350
351 dump_stream.Format("{0:x}: EntityPersistentVariable ({1})\n", load_addr,
352 m_persistent_variable_sp->GetName());
353
354 {
355 dump_stream.Printf("Pointer:\n");
356
357 DataBufferHeap data(m_size, 0);
358
359 map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
360
361 if (!err.Success()) {
362 dump_stream.Printf(" <could not be read>\n");
363 } else {
364 DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
365 load_addr);
366
367 dump_stream.PutChar('\n');
368 }
369 }
370
371 {
372 dump_stream.Printf("Target:\n");
373
374 lldb::addr_t target_address;
375
376 map.ReadPointerFromMemory(&target_address, load_addr, err);
377
378 if (!err.Success()) {
379 dump_stream.Printf(" <could not be read>\n");
380 } else {
381 DataBufferHeap data(
382 llvm::expectedToOptional(m_persistent_variable_sp->GetByteSize())
383 .value_or(0),
384 0);
385
386 map.ReadMemory(
387 data.GetBytes(), target_address,
388 llvm::expectedToOptional(m_persistent_variable_sp->GetByteSize())
389 .value_or(0),
390 err);
391
392 if (!err.Success()) {
393 dump_stream.Printf(" <could not be read>\n");
394 } else {
395 DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
396 target_address);
397
398 dump_stream.PutChar('\n');
399 }
400 }
401 }
402
403 log->PutString(dump_stream.GetString());
404 }
405
406 void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {}
407
408private:
411};
412
414 lldb::ExpressionVariableSP &persistent_variable_sp,
415 PersistentVariableDelegate *delegate, Status &err) {
416 EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
417 *iter = std::make_unique<EntityPersistentVariable>(persistent_variable_sp,
418 delegate);
419 uint32_t ret = AddStructMember(**iter);
420 (*iter)->SetOffset(ret);
421 return ret;
422}
423
424/// Base class for materialization of Variables and ValueObjects.
425///
426/// Subclasses specify how to obtain the Value which is to be
427/// materialized.
429public:
430 virtual ~EntityVariableBase() = default;
431
433 // Hard-coding to maximum size of a pointer since all variables are
434 // materialized by reference
437 }
438
440 lldb::addr_t process_address, Status &err) override {
442
443 const lldb::addr_t load_addr = process_address + m_offset;
444 LLDB_LOGF(log,
445 "EntityVariable::Materialize [address = 0x%" PRIx64
446 ", m_variable_sp = %s]",
447 (uint64_t)load_addr, GetName().GetCString());
448
449 ExecutionContextScope *scope = frame_sp.get();
450
451 if (!scope)
452 scope = map.GetBestExecutionContextScope();
453
454 lldb::ValueObjectSP valobj_sp = SetupValueObject(scope);
455
456 if (!valobj_sp) {
458 "couldn't get a value object for variable {0}", GetName());
459 return;
460 }
461
462 Status valobj_error = valobj_sp->GetError().Clone();
463
464 if (valobj_error.Fail()) {
466 "couldn't get the value of variable {0}: {1}", GetName(),
467 valobj_error.AsCString());
468 return;
469 }
470
471 if (m_is_reference) {
472 DataExtractor valobj_extractor;
473 Status extract_error;
474 valobj_sp->GetData(valobj_extractor, extract_error);
475
476 if (!extract_error.Success()) {
478 "couldn't read contents of reference variable {0}: {1}", GetName(),
479 extract_error.AsCString());
480 return;
481 }
482
483 lldb::offset_t offset = 0;
484 lldb::addr_t reference_addr = valobj_extractor.GetAddress(&offset);
485
486 Status write_error;
487 map.WritePointerToMemory(load_addr, reference_addr, write_error);
488
489 if (!write_error.Success()) {
491 "couldn't write the contents of reference variable {0} to memory: "
492 "{0}",
493 GetName(), write_error.AsCString());
494 return;
495 }
496 } else {
497 lldb::addr_t addr_of_valobj =
498 valobj_sp->GetAddressOf(/*scalar_is_load_address=*/false).address;
499 if (addr_of_valobj != LLDB_INVALID_ADDRESS) {
500 Status write_error;
501 map.WritePointerToMemory(load_addr, addr_of_valobj, write_error);
502
503 if (!write_error.Success()) {
505 "couldn't write the address of variable {0} to memory: {1}",
506 GetName(), write_error.AsCString());
507 return;
508 }
509 } else {
510 DataExtractor data;
511 Status extract_error;
512 valobj_sp->GetData(data, extract_error);
513 if (!extract_error.Success()) {
515 "couldn't get the value of {0}: {1}", GetName(),
516 extract_error.AsCString());
517 return;
518 }
519
522 "trying to create a temporary region for {0} but one exists",
523 GetName());
524 return;
525 }
526
527 if (data.GetByteSize() <
528 llvm::expectedToOptional(GetByteSize(scope)).value_or(0)) {
529 if (data.GetByteSize() == 0 && !LocationExpressionIsValid()) {
531 "the variable '{0}' has no location, "
532 "it may have been optimized out",
533 GetName());
534 } else {
536 "size of variable {0} ({1}) is larger than the ValueObject's "
537 "size ({2})",
538 GetName(),
539 llvm::expectedToOptional(GetByteSize(scope)).value_or(0),
540 data.GetByteSize());
541 }
542 return;
543 }
544
545 std::optional<size_t> opt_bit_align = GetTypeBitAlign(scope);
546 if (!opt_bit_align) {
548 "can't get the type alignment for {0}", GetName());
549 return;
550 }
551
552 size_t byte_align = (*opt_bit_align + 7) / 8;
553
554 const bool zero_memory = false;
555 if (auto address_or_error = map.Malloc(
556 data.GetByteSize(), byte_align,
557 lldb::ePermissionsReadable | lldb::ePermissionsWritable,
559 m_temporary_allocation = *address_or_error;
560 } else {
562 "couldn't allocate a temporary region for {0}: {1}", GetName(),
563 toString(address_or_error.takeError()));
564 return;
565 }
566
568
569 m_original_data = std::make_shared<DataBufferHeap>(data.GetDataStart(),
570 data.GetByteSize());
571
572 Status write_error;
573
575 data.GetByteSize(), write_error);
576
577 if (!write_error.Success()) {
579 "couldn't write to the temporary region for {0}: {1}", GetName(),
580 write_error.AsCString());
581 return;
582 }
583
584 Status pointer_write_error;
585
587 pointer_write_error);
588
589 if (!pointer_write_error.Success()) {
591 "couldn't write the address of the temporary region for {0}: {1}",
592 GetName(), pointer_write_error.AsCString());
593 }
594 }
595 }
596 }
597
599 lldb::addr_t process_address, lldb::addr_t frame_top,
600 lldb::addr_t frame_bottom, Status &err) override {
602
603 const lldb::addr_t load_addr = process_address + m_offset;
604 LLDB_LOG(
605 log,
606 "EntityVariable::Dematerialize [address = {0:x}, m_variable_sp = {1}]",
607 (uint64_t)load_addr, GetName());
608
610 ExecutionContextScope *scope = frame_sp.get();
611
612 if (!scope)
613 scope = map.GetBestExecutionContextScope();
614
615 lldb::ValueObjectSP valobj_sp = SetupValueObject(scope);
616
617 if (!valobj_sp) {
619 "couldn't get a value object for variable {0}", GetName());
620 return;
621 }
622
624
625 Status extract_error;
626
627 map.GetMemoryData(
629 llvm::expectedToOptional(valobj_sp->GetByteSize()).value_or(0),
630 extract_error);
631
632 if (!extract_error.Success()) {
634 "couldn't get the data for variable {0}", GetName());
635 return;
636 }
637
638 bool actually_write = true;
639
640 if (m_original_data) {
641 if ((data.GetByteSize() == m_original_data->GetByteSize()) &&
642 !memcmp(m_original_data->GetBytes(), data.GetDataStart(),
643 data.GetByteSize())) {
644 actually_write = false;
645 }
646 }
647
648 Status set_error;
649
650 if (actually_write) {
651 valobj_sp->SetData(data, set_error);
652
653 if (!set_error.Success()) {
655 "couldn't write the new contents of {0} back into the variable",
656 GetName());
657 return;
658 }
659 }
660
661 Status free_error;
662
663 map.Free(m_temporary_allocation, free_error);
664
665 if (!free_error.Success()) {
667 "couldn't free the temporary region for {0}: {1}", GetName(),
668 free_error.AsCString());
669 return;
670 }
671
672 m_original_data.reset();
675 }
676 }
677
678 void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
679 Log *log) override {
680 StreamString dump_stream;
681
682 const lldb::addr_t load_addr = process_address + m_offset;
683 dump_stream.Printf("0x%" PRIx64 ": EntityVariable\n", load_addr);
684
685 Status err;
686
688
689 {
690 dump_stream.Printf("Pointer:\n");
691
692 DataBufferHeap data(m_size, 0);
693
694 map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
695
696 if (!err.Success()) {
697 dump_stream.Printf(" <could not be read>\n");
698 } else {
699 DataExtractor extractor(data.GetBytes(), data.GetByteSize(),
700 map.GetByteOrder(), map.GetAddressByteSize());
701
702 DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
703 load_addr);
704
705 lldb::offset_t offset = 0;
706
707 ptr = extractor.GetAddress(&offset);
708
709 dump_stream.PutChar('\n');
710 }
711 }
712
714 dump_stream.Printf("Points to process memory:\n");
715 } else {
716 dump_stream.Printf("Temporary allocation:\n");
717 }
718
719 if (ptr == LLDB_INVALID_ADDRESS) {
720 dump_stream.Printf(" <could not be be found>\n");
721 } else {
723
726
727 if (!err.Success()) {
728 dump_stream.Printf(" <could not be read>\n");
729 } else {
730 DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
731 load_addr);
732
733 dump_stream.PutChar('\n');
734 }
735 }
736
737 log->PutString(dump_stream.GetString());
738 }
739
740 void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {
742 Status free_error;
743
744 map.Free(m_temporary_allocation, free_error);
745
748 }
749 }
750
751private:
752 virtual ConstString GetName() const = 0;
753
754 /// Creates and returns ValueObject tied to this variable
755 /// and prepares Entity for materialization.
756 ///
757 /// Called each time the Materializer (de)materializes a
758 /// variable. We re-create the ValueObject based on the
759 /// current ExecutionContextScope since clients such as
760 /// conditional breakpoints may materialize the same
761 /// EntityVariable multiple times with different frames.
762 ///
763 /// Each subsequent use of the EntityVariableBase interface
764 /// will query the newly created ValueObject until this
765 /// function is called again.
766 virtual lldb::ValueObjectSP
768
769 /// Returns size in bytes of the type associated with this variable
770 ///
771 /// \returns On success, returns byte size of the type associated
772 /// with this variable. Returns std::nullopt otherwise.
773 virtual llvm::Expected<uint64_t>
775
776 /// Returns 'true' if the location expression associated with this variable
777 /// is valid.
778 virtual bool LocationExpressionIsValid() const = 0;
779
780 /// Returns alignment of the type associated with this variable in bits.
781 ///
782 /// \returns On success, returns alignment in bits for the type associated
783 /// with this variable. Returns std::nullopt otherwise.
784 virtual std::optional<size_t>
786
787protected:
788 bool m_is_reference = false;
792};
793
794/// Represents an Entity constructed from a VariableSP.
795///
796/// This class is used for materialization of variables for which
797/// the user has a VariableSP on hand. The ValueObject is then
798/// derived from the associated DWARF location expression when needed
799/// by the Materializer.
801public:
802 EntityVariable(lldb::VariableSP &variable_sp) : m_variable_sp(variable_sp) {
804 m_variable_sp->GetType()->GetForwardCompilerType().IsReferenceType();
805 }
806
807 ConstString GetName() const override { return m_variable_sp->GetName(); }
808
810 assert(m_variable_sp != nullptr);
812 }
813
814 llvm::Expected<uint64_t>
815 GetByteSize(ExecutionContextScope *scope) const override {
816 return m_variable_sp->GetType()->GetByteSize(scope);
817 }
818
819 bool LocationExpressionIsValid() const override {
820 return m_variable_sp->LocationExpressionList().IsValid();
821 }
822
823 std::optional<size_t>
824 GetTypeBitAlign(ExecutionContextScope *scope) const override {
825 return m_variable_sp->GetType()->GetLayoutCompilerType().GetTypeBitAlign(
826 scope);
827 }
828
829private:
830 lldb::VariableSP m_variable_sp; ///< Variable that this entity is based on.
831};
832
833/// Represents an Entity constructed from a VariableSP.
834///
835/// This class is used for materialization of variables for
836/// which the user does not have a VariableSP available (e.g.,
837/// when materializing ivars).
839public:
841 : m_name(name), m_valobj_provider(std::move(provider)) {
842 assert(m_valobj_provider);
843 }
844
845 ConstString GetName() const override { return m_name; }
846
850
851 if (m_valobj_sp)
852 m_is_reference = m_valobj_sp->GetCompilerType().IsReferenceType();
853
854 return m_valobj_sp;
855 }
856
857 llvm::Expected<uint64_t>
858 GetByteSize(ExecutionContextScope *scope) const override {
859 if (m_valobj_sp)
860 return m_valobj_sp->GetCompilerType().GetByteSize(scope);
861
862 return llvm::createStringError("no value object");
863 }
864
865 bool LocationExpressionIsValid() const override {
866 if (m_valobj_sp)
867 return m_valobj_sp->GetError().Success();
868
869 return false;
870 }
871
872 std::optional<size_t>
873 GetTypeBitAlign(ExecutionContextScope *scope) const override {
874 if (m_valobj_sp)
875 return m_valobj_sp->GetCompilerType().GetTypeBitAlign(scope);
876
877 return {};
878 }
879
880private:
884};
885
887 EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
888 *iter = std::make_unique<EntityVariable>(variable_sp);
889 uint32_t ret = AddStructMember(**iter);
890 (*iter)->SetOffset(ret);
891 return ret;
892}
893
895 ValueObjectProviderTy valobj_provider,
896 Status &err) {
897 assert(valobj_provider);
898 EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
899 *iter = std::make_unique<EntityValueObject>(name, std::move(valobj_provider));
900 uint32_t ret = AddStructMember(**iter);
901 (*iter)->SetOffset(ret);
902 return ret;
903}
904
906public:
907 EntityResultVariable(const CompilerType &type, bool is_program_reference,
908 bool keep_in_memory,
910 : Entity(), m_type(type), m_is_program_reference(is_program_reference),
911 m_keep_in_memory(keep_in_memory), m_delegate(delegate) {
912 // Hard-coding to maximum size of a pointer since all results are
913 // materialized by reference
916 }
917
919 lldb::addr_t process_address, Status &err) override {
923 "Trying to create a temporary region for the result "
924 "but one exists");
925 return;
926 }
927
928 const lldb::addr_t load_addr = process_address + m_offset;
929
930 ExecutionContextScope *exe_scope = frame_sp.get();
931 if (!exe_scope)
932 exe_scope = map.GetBestExecutionContextScope();
933
934 auto byte_size_or_err = m_type.GetByteSize(exe_scope);
935 if (!byte_size_or_err) {
936 err = Status::FromError(byte_size_or_err.takeError());
937 return;
938 }
939 auto byte_size = *byte_size_or_err;
940
941 std::optional<size_t> opt_bit_align = m_type.GetTypeBitAlign(exe_scope);
942 if (!opt_bit_align) {
944 "can't get the alignment of type \"{0}\"", m_type.GetTypeName());
945 return;
946 }
947
948 size_t byte_align = (*opt_bit_align + 7) / 8;
949
950 const bool zero_memory = true;
951 if (auto address_or_error = map.Malloc(
952 byte_size, byte_align,
953 lldb::ePermissionsReadable | lldb::ePermissionsWritable,
955 m_temporary_allocation = *address_or_error;
956 } else {
958 "couldn't allocate a temporary region for the result: %s",
959 toString(address_or_error.takeError()).c_str());
960 return;
961 }
962
963 m_temporary_allocation_size = byte_size;
964
965 Status pointer_write_error;
966
968 pointer_write_error);
969
970 if (!pointer_write_error.Success()) {
972 "couldn't write the address of the "
973 "temporary region for the result: %s",
974 pointer_write_error.AsCString());
975 }
976 }
977 }
978
980 lldb::addr_t process_address, lldb::addr_t frame_top,
981 lldb::addr_t frame_bottom, Status &err) override {
982 err.Clear();
983
984 ExecutionContextScope *exe_scope = frame_sp.get();
985 if (!exe_scope)
986 exe_scope = map.GetBestExecutionContextScope();
987
988 if (!exe_scope) {
990 "Couldn't dematerialize a result variable: invalid "
991 "execution context scope");
992 return;
993 }
994
995 lldb::addr_t address;
996 Status read_error;
997 const lldb::addr_t load_addr = process_address + m_offset;
998
999 map.ReadPointerFromMemory(&address, load_addr, read_error);
1000
1001 if (!read_error.Success()) {
1003 "Couldn't dematerialize a result variable: couldn't "
1004 "read its address");
1005 return;
1006 }
1007
1008 lldb::TargetSP target_sp = exe_scope->CalculateTarget();
1009
1010 if (!target_sp) {
1012 "Couldn't dematerialize a result variable: no target");
1013 return;
1014 }
1015
1016 auto type_system_or_err =
1017 target_sp->GetScratchTypeSystemForLanguage(m_type.GetMinimumLanguage());
1018
1019 if (auto error = type_system_or_err.takeError()) {
1021 "Couldn't dematerialize a result variable: "
1022 "couldn't get the corresponding type "
1023 "system: %s",
1024 llvm::toString(std::move(error)).c_str());
1025 return;
1026 }
1027 auto ts = *type_system_or_err;
1028 if (!ts) {
1030 "Couldn't dematerialize a result variable: "
1031 "couldn't corresponding type system is "
1032 "no longer live.");
1033 return;
1034 }
1035 PersistentExpressionState *persistent_state =
1036 ts->GetPersistentExpressionState();
1037
1038 if (!persistent_state) {
1040 "Couldn't dematerialize a result variable: "
1041 "corresponding type system doesn't handle persistent "
1042 "variables");
1043 return;
1044 }
1045
1046 ConstString name = m_delegate
1047 ? m_delegate->GetName()
1048 : persistent_state->GetNextPersistentVariableName();
1049
1051 exe_scope, name, m_type, map.GetByteOrder(), map.GetAddressByteSize());
1052
1053 if (!ret) {
1055 "couldn't dematerialize a result variable: failed to make persistent "
1056 "variable {0}",
1057 name);
1058 return;
1059 }
1060
1061 lldb::ProcessSP process_sp =
1063
1064 if (m_delegate) {
1065 m_delegate->DidDematerialize(ret);
1066 }
1067
1068 bool can_persist = m_is_program_reference &&
1069 !(address >= frame_bottom && address < frame_top);
1070
1071 if (can_persist && m_keep_in_memory) {
1072 ret->m_live_sp = ValueObjectConstResult::Create(exe_scope, m_type, name,
1073 address, eAddressTypeLoad,
1074 map.GetAddressByteSize());
1075 }
1076
1077 ret->ValueUpdated();
1078
1079 const size_t pvar_byte_size =
1080 llvm::expectedToOptional(ret->GetByteSize()).value_or(0);
1081 uint8_t *pvar_data = ret->GetValueBytes();
1082
1083 map.ReadMemory(pvar_data, address, pvar_byte_size, read_error);
1084
1085 if (!read_error.Success()) {
1087 "Couldn't dematerialize a result variable: couldn't read its memory");
1088 return;
1089 }
1090
1091 if (!can_persist || !m_keep_in_memory) {
1093
1095 Status free_error;
1096 map.Free(m_temporary_allocation, free_error);
1097 }
1098 } else {
1099 ret->m_flags |= m_is_program_reference
1102 }
1103
1106 }
1107
1108 void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
1109 Log *log) override {
1110 StreamString dump_stream;
1111
1112 const lldb::addr_t load_addr = process_address + m_offset;
1113
1114 dump_stream.Printf("0x%" PRIx64 ": EntityResultVariable\n", load_addr);
1115
1116 Status err;
1117
1119
1120 {
1121 dump_stream.Printf("Pointer:\n");
1122
1123 DataBufferHeap data(m_size, 0);
1124
1125 map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
1126
1127 if (!err.Success()) {
1128 dump_stream.Printf(" <could not be read>\n");
1129 } else {
1130 DataExtractor extractor(data.GetBytes(), data.GetByteSize(),
1131 map.GetByteOrder(), map.GetAddressByteSize());
1132
1133 DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
1134 load_addr);
1135
1136 lldb::offset_t offset = 0;
1137
1138 ptr = extractor.GetAddress(&offset);
1139
1140 dump_stream.PutChar('\n');
1141 }
1142 }
1143
1145 dump_stream.Printf("Points to process memory:\n");
1146 } else {
1147 dump_stream.Printf("Temporary allocation:\n");
1148 }
1149
1150 if (ptr == LLDB_INVALID_ADDRESS) {
1151 dump_stream.Printf(" <could not be be found>\n");
1152 } else {
1154
1157
1158 if (!err.Success()) {
1159 dump_stream.Printf(" <could not be read>\n");
1160 } else {
1161 DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
1162 load_addr);
1163
1164 dump_stream.PutChar('\n');
1165 }
1166 }
1167
1168 log->PutString(dump_stream.GetString());
1169 }
1170
1171 void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {
1173 Status free_error;
1174
1175 map.Free(m_temporary_allocation, free_error);
1176 }
1177
1180 }
1181
1182private:
1184 /// This is used both to control whether this result entity can (and should)
1185 /// track the value in inferior memory, as well as to control whether LLDB
1186 /// needs to allocate memory for the variable during materialization.
1189
1193};
1194
1196 bool is_program_reference,
1197 bool keep_in_memory,
1199 Status &err) {
1200 EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
1201 *iter = std::make_unique<EntityResultVariable>(type, is_program_reference,
1202 keep_in_memory, delegate);
1203 uint32_t ret = AddStructMember(**iter);
1204 (*iter)->SetOffset(ret);
1205 return ret;
1206}
1207
1209public:
1210 EntitySymbol(const Symbol &symbol) : Entity(), m_symbol(symbol) {
1211 // Hard-coding to maximum size of a symbol
1214 }
1215
1217 lldb::addr_t process_address, Status &err) override {
1219
1220 const lldb::addr_t load_addr = process_address + m_offset;
1221
1222 LLDB_LOG(log, "EntitySymbol::Materialize [address = {0}, m_symbol = {1}]",
1223 (uint64_t)load_addr, m_symbol.GetName());
1224
1225 const Address sym_address = m_symbol.GetAddress();
1226
1227 ExecutionContextScope *exe_scope = frame_sp.get();
1228 if (!exe_scope)
1229 exe_scope = map.GetBestExecutionContextScope();
1230
1231 lldb::TargetSP target_sp;
1232
1233 if (exe_scope)
1234 target_sp = map.GetBestExecutionContextScope()->CalculateTarget();
1235
1236 if (!target_sp) {
1238 "couldn't resolve symbol {0} because there is no target",
1239 m_symbol.GetName());
1240 return;
1241 }
1242
1243 lldb::addr_t resolved_address = sym_address.GetLoadAddress(target_sp.get());
1244
1245 if (resolved_address == LLDB_INVALID_ADDRESS)
1246 resolved_address = sym_address.GetFileAddress();
1247
1248 Status pointer_write_error;
1249
1250 map.WritePointerToMemory(load_addr, resolved_address, pointer_write_error);
1251
1252 if (!pointer_write_error.Success()) {
1254 "couldn't write the address of symbol {0}: {1}", m_symbol.GetName(),
1255 pointer_write_error.AsCString());
1256 return;
1257 }
1258 }
1259
1261 lldb::addr_t process_address, lldb::addr_t frame_top,
1262 lldb::addr_t frame_bottom, Status &err) override {
1264
1265 const lldb::addr_t load_addr = process_address + m_offset;
1266
1267 LLDB_LOG(log,
1268 "EntitySymbol::Dematerialize [address = {0:x}, m_symbol = {1}]",
1269 (uint64_t)load_addr, m_symbol.GetName());
1270
1271 // no work needs to be done
1272 }
1273
1274 void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
1275 Log *log) override {
1276 StreamString dump_stream;
1277
1278 Status err;
1279
1280 const lldb::addr_t load_addr = process_address + m_offset;
1281
1282 dump_stream.Format("{0:x}: EntitySymbol ({1})\n", load_addr,
1283 m_symbol.GetName());
1284
1285 {
1286 dump_stream.Printf("Pointer:\n");
1287
1288 DataBufferHeap data(m_size, 0);
1289
1290 map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
1291
1292 if (!err.Success()) {
1293 dump_stream.Printf(" <could not be read>\n");
1294 } else {
1295 DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
1296 load_addr);
1297
1298 dump_stream.PutChar('\n');
1299 }
1300 }
1301
1302 log->PutString(dump_stream.GetString());
1303 }
1304
1305 void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {}
1306
1307private:
1309};
1310
1311uint32_t Materializer::AddSymbol(const Symbol &symbol_sp, Status &err) {
1312 EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
1313 *iter = std::make_unique<EntitySymbol>(symbol_sp);
1314 uint32_t ret = AddStructMember(**iter);
1315 (*iter)->SetOffset(ret);
1316 return ret;
1317}
1318
1320public:
1321 EntityRegister(const RegisterInfo &register_info)
1322 : Entity(), m_register_info(register_info) {
1323 // Hard-coding alignment conservatively
1324 m_size = m_register_info.byte_size;
1325 m_alignment = m_register_info.byte_size;
1326 }
1327
1329 lldb::addr_t process_address, Status &err) override {
1331
1332 const lldb::addr_t load_addr = process_address + m_offset;
1333
1334 LLDB_LOGF(log,
1335 "EntityRegister::Materialize [address = 0x%" PRIx64
1336 ", m_register_info = %s]",
1337 (uint64_t)load_addr, m_register_info.name);
1338
1339 RegisterValue reg_value;
1340
1341 if (!frame_sp.get()) {
1343 "couldn't materialize register %s without a stack frame",
1344 m_register_info.name);
1345 return;
1346 }
1347
1348 lldb::RegisterContextSP reg_context_sp = frame_sp->GetRegisterContext();
1349
1350 if (!reg_context_sp->ReadRegister(&m_register_info, reg_value)) {
1352 "couldn't read the value of register %s", m_register_info.name);
1353 return;
1354 }
1355
1356 if (reg_value.GetByteSize() != m_register_info.byte_size) {
1358 "data for register %s had size %llu but we expected %llu",
1359 m_register_info.name, (unsigned long long)reg_value.GetByteSize(),
1360 (unsigned long long)m_register_info.byte_size);
1361 return;
1362 }
1363
1364 lldb_private::DataBufferHeap buf(reg_value.GetByteSize(), 0);
1365 reg_value.GetAsMemoryData(m_register_info, buf.GetBytes(),
1366 buf.GetByteSize(), map.GetByteOrder(), err);
1367 if (!err.Success())
1368 return;
1369
1370 m_register_contents = std::make_shared<DataBufferHeap>(buf);
1371
1372 Status write_error;
1373
1374 map.WriteMemory(load_addr, buf.GetBytes(), reg_value.GetByteSize(),
1375 write_error);
1376
1377 if (!write_error.Success()) {
1379 "couldn't write the contents of register %s: %s",
1380 m_register_info.name, write_error.AsCString());
1381 return;
1382 }
1383 }
1384
1386 lldb::addr_t process_address, lldb::addr_t frame_top,
1387 lldb::addr_t frame_bottom, Status &err) override {
1389
1390 const lldb::addr_t load_addr = process_address + m_offset;
1391
1392 LLDB_LOGF(log,
1393 "EntityRegister::Dematerialize [address = 0x%" PRIx64
1394 ", m_register_info = %s]",
1395 (uint64_t)load_addr, m_register_info.name);
1396
1397 Status extract_error;
1398
1399 DataExtractor register_data;
1400
1401 if (!frame_sp.get()) {
1403 "couldn't dematerialize register %s without a stack frame",
1404 m_register_info.name);
1405 return;
1406 }
1407
1408 lldb::RegisterContextSP reg_context_sp = frame_sp->GetRegisterContext();
1409
1410 map.GetMemoryData(register_data, load_addr, m_register_info.byte_size,
1411 extract_error);
1412
1413 if (!extract_error.Success()) {
1415 "couldn't get the data for register %s: %s", m_register_info.name,
1416 extract_error.AsCString());
1417 return;
1418 }
1419
1420 if (!memcmp(register_data.GetDataStart(), m_register_contents->GetBytes(),
1421 register_data.GetByteSize())) {
1422 // No write required, and in particular we avoid errors if the register
1423 // wasn't writable
1424
1425 m_register_contents.reset();
1426 return;
1427 }
1428
1429 m_register_contents.reset();
1430
1431 RegisterValue register_value(register_data.GetData(),
1432 register_data.GetByteOrder());
1433
1434 if (!reg_context_sp->WriteRegister(&m_register_info, register_value)) {
1436 "couldn't write the value of register %s", m_register_info.name);
1437 return;
1438 }
1439 }
1440
1441 void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
1442 Log *log) override {
1443 StreamString dump_stream;
1444
1445 Status err;
1446
1447 const lldb::addr_t load_addr = process_address + m_offset;
1448
1449 dump_stream.Printf("0x%" PRIx64 ": EntityRegister (%s)\n", load_addr,
1450 m_register_info.name);
1451
1452 {
1453 dump_stream.Printf("Value:\n");
1454
1455 DataBufferHeap data(m_size, 0);
1456
1457 map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
1458
1459 if (!err.Success()) {
1460 dump_stream.Printf(" <could not be read>\n");
1461 } else {
1462 DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
1463 load_addr);
1464
1465 dump_stream.PutChar('\n');
1466 }
1467 }
1468
1469 log->PutString(dump_stream.GetString());
1470 }
1471
1472 void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {}
1473
1474private:
1477};
1478
1479uint32_t Materializer::AddRegister(const RegisterInfo &register_info,
1480 Status &err) {
1481 EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
1482 *iter = std::make_unique<EntityRegister>(register_info);
1483 uint32_t ret = AddStructMember(**iter);
1484 (*iter)->SetOffset(ret);
1485 return ret;
1486}
1487
1489 DematerializerSP dematerializer_sp = m_dematerializer_wp.lock();
1490
1491 if (dematerializer_sp)
1492 dematerializer_sp->Wipe();
1493}
1494
1497 lldb::addr_t process_address, Status &error) {
1498 ExecutionContextScope *exe_scope = frame_sp.get();
1499 if (!exe_scope)
1500 exe_scope = map.GetBestExecutionContextScope();
1501
1502 DematerializerSP dematerializer_sp = m_dematerializer_wp.lock();
1503
1504 if (dematerializer_sp) {
1505 error =
1506 Status::FromErrorString("Couldn't materialize: already materialized");
1507 }
1508
1509 DematerializerSP ret(
1510 new Dematerializer(*this, frame_sp, map, process_address));
1511
1512 if (!exe_scope) {
1513 error =
1514 Status::FromErrorString("Couldn't materialize: target doesn't exist");
1515 }
1516
1517 for (EntityUP &entity_up : m_entities) {
1518 entity_up->Materialize(frame_sp, map, process_address, error);
1519
1520 if (!error.Success())
1521 return DematerializerSP();
1522 }
1523
1524 if (Log *log = GetLog(LLDBLog::Expressions)) {
1525 LLDB_LOGF(
1526 log,
1527 "Materializer::Materialize (frame_sp = %p, process_address = 0x%" PRIx64
1528 ") materialized:",
1529 static_cast<void *>(frame_sp.get()), process_address);
1530 for (EntityUP &entity_up : m_entities)
1531 entity_up->DumpToLog(map, process_address, log);
1532 }
1533
1534 m_dematerializer_wp = ret;
1535
1536 return ret;
1537}
1538
1540 lldb::addr_t frame_bottom,
1541 lldb::addr_t frame_top) {
1542 lldb::StackFrameSP frame_sp;
1543
1544 lldb::ThreadSP thread_sp = m_thread_wp.lock();
1545 if (thread_sp)
1546 frame_sp = thread_sp->GetFrameWithStackID(m_stack_id);
1547
1548 ExecutionContextScope *exe_scope = frame_sp.get();
1549 if (!exe_scope)
1550 exe_scope = m_map->GetBestExecutionContextScope();
1551
1552 if (!IsValid()) {
1554 "Couldn't dematerialize: invalid dematerializer");
1555 }
1556
1557 if (!exe_scope) {
1558 error = Status::FromErrorString("Couldn't dematerialize: target is gone");
1559 } else {
1560 if (Log *log = GetLog(LLDBLog::Expressions)) {
1561 LLDB_LOGF(log,
1562 "Materializer::Dematerialize (frame_sp = %p, process_address "
1563 "= 0x%" PRIx64 ") about to dematerialize:",
1564 static_cast<void *>(frame_sp.get()), m_process_address);
1565 for (EntityUP &entity_up : m_materializer->m_entities)
1566 entity_up->DumpToLog(*m_map, m_process_address, log);
1567 }
1568
1569 for (EntityUP &entity_up : m_materializer->m_entities) {
1570 entity_up->Dematerialize(frame_sp, *m_map, m_process_address, frame_top,
1571 frame_bottom, error);
1572
1573 if (!error.Success())
1574 break;
1575 }
1576 }
1577
1578 Wipe();
1579}
1580
1582 if (!IsValid())
1583 return;
1584
1585 for (EntityUP &entity_up : m_materializer->m_entities) {
1586 entity_up->Wipe(*m_map, m_process_address);
1587 }
1588
1589 m_materializer = nullptr;
1590 m_map = nullptr;
1592}
1593
1595 default;
1597 default;
static llvm::raw_ostream & error(Stream &strm)
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
Definition Log.h:364
#define LLDB_LOGF(log,...)
Definition Log.h:378
static constexpr uint32_t g_default_var_byte_size
static constexpr uint32_t g_default_var_alignment
static llvm::StringRef GetName(XcodeSDK::Type type)
Definition XcodeSDK.cpp:21
Materializer::PersistentVariableDelegate * m_delegate
lldb::ExpressionVariableSP m_persistent_variable_sp
void DestroyAllocation(IRMemoryMap &map, Status &err)
void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, lldb::addr_t process_address, Status &err) override
void MakeAllocation(IRMemoryMap &map, Status &err)
void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, lldb::addr_t process_address, lldb::addr_t frame_top, lldb::addr_t frame_bottom, Status &err) override
void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override
void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address, Log *log) override
EntityPersistentVariable(lldb::ExpressionVariableSP &persistent_variable_sp, Materializer::PersistentVariableDelegate *delegate)
void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, lldb::addr_t process_address, Status &err) override
void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address, Log *log) override
void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, lldb::addr_t process_address, lldb::addr_t frame_top, lldb::addr_t frame_bottom, Status &err) override
RegisterInfo m_register_info
void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override
lldb::DataBufferSP m_register_contents
EntityRegister(const RegisterInfo &register_info)
void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, lldb::addr_t process_address, lldb::addr_t frame_top, lldb::addr_t frame_bottom, Status &err) override
void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address, Log *log) override
Materializer::PersistentVariableDelegate * m_delegate
bool m_is_program_reference
This is used both to control whether this result entity can (and should) track the value in inferior ...
EntityResultVariable(const CompilerType &type, bool is_program_reference, bool keep_in_memory, Materializer::PersistentVariableDelegate *delegate)
void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, lldb::addr_t process_address, Status &err) override
void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override
lldb::addr_t m_temporary_allocation
EntitySymbol(const Symbol &symbol)
void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address, Log *log) override
void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override
void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, lldb::addr_t process_address, Status &err) override
void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, lldb::addr_t process_address, lldb::addr_t frame_top, lldb::addr_t frame_bottom, Status &err) override
ConstString GetName() const override
ValueObjectProviderTy m_valobj_provider
lldb::ValueObjectSP m_valobj_sp
bool LocationExpressionIsValid() const override
Returns 'true' if the location expression associated with this variable is valid.
std::optional< size_t > GetTypeBitAlign(ExecutionContextScope *scope) const override
Returns alignment of the type associated with this variable in bits.
llvm::Expected< uint64_t > GetByteSize(ExecutionContextScope *scope) const override
Returns size in bytes of the type associated with this variable.
lldb::ValueObjectSP SetupValueObject(ExecutionContextScope *scope) override
Creates and returns ValueObject tied to this variable and prepares Entity for materialization.
EntityValueObject(ConstString name, ValueObjectProviderTy provider)
lldb::DataBufferSP m_original_data
size_t m_temporary_allocation_size
lldb::addr_t m_temporary_allocation
void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, lldb::addr_t process_address, Status &err) override
virtual ~EntityVariableBase()=default
void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override
void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address, Log *log) override
virtual std::optional< size_t > GetTypeBitAlign(ExecutionContextScope *scope) const =0
Returns alignment of the type associated with this variable in bits.
virtual ConstString GetName() const =0
virtual bool LocationExpressionIsValid() const =0
Returns 'true' if the location expression associated with this variable is valid.
virtual lldb::ValueObjectSP SetupValueObject(ExecutionContextScope *scope)=0
Creates and returns ValueObject tied to this variable and prepares Entity for materialization.
virtual llvm::Expected< uint64_t > GetByteSize(ExecutionContextScope *scope) const =0
Returns size in bytes of the type associated with this variable.
void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, lldb::addr_t process_address, lldb::addr_t frame_top, lldb::addr_t frame_bottom, Status &err) override
ConstString GetName() const override
std::optional< size_t > GetTypeBitAlign(ExecutionContextScope *scope) const override
Returns alignment of the type associated with this variable in bits.
lldb::ValueObjectSP SetupValueObject(ExecutionContextScope *scope) override
Creates and returns ValueObject tied to this variable and prepares Entity for materialization.
bool LocationExpressionIsValid() const override
Returns 'true' if the location expression associated with this variable is valid.
lldb::VariableSP m_variable_sp
Variable that this entity is based on.
llvm::Expected< uint64_t > GetByteSize(ExecutionContextScope *scope) const override
Returns size in bytes of the type associated with this variable.
EntityVariable(lldb::VariableSP &variable_sp)
A section + offset based address class.
Definition Address.h:62
lldb::addr_t GetLoadAddress(Target *target) const
Get the load address.
Definition Address.cpp:301
lldb::addr_t GetFileAddress() const
Get the file address.
Definition Address.cpp:281
Generic representation of a type in a programming language.
A uniqued constant string class.
Definition ConstString.h:40
A subclass of DataBuffer that stores a data buffer on the heap.
lldb::offset_t GetByteSize() const override
Get the number of bytes in the data buffer.
An data extractor class.
virtual const void * GetData(lldb::offset_t *offset_ptr, lldb::offset_t length) const
Extract length bytes from *offset_ptr.
virtual uint64_t GetByteSize() const
Get the number of bytes contained in this object.
uint64_t GetAddress(lldb::offset_t *offset_ptr) const
Extract an address from *offset_ptr.
const uint8_t * GetDataStart() const
Get the data start pointer.
lldb::ByteOrder GetByteOrder() const
Get the current byte order value.
"lldb/Target/ExecutionContextScope.h" Inherit from this if your object can reconstruct its execution ...
virtual lldb::StackFrameSP CalculateStackFrame()=0
virtual lldb::ProcessSP CalculateProcess()=0
virtual lldb::TargetSP CalculateTarget()=0
@ EVIsLLDBAllocated
This variable is resident in a location specifically allocated for it by LLDB in the target process.
@ EVNeedsFreezeDry
Copy from m_live_sp to m_frozen_sp during dematerialization.
@ EVNeedsAllocation
Space for this variable has yet to be allocated in the target process.
@ EVIsProgramReference
This variable is a reference to a (possibly invalid) area managed by the target program.
@ EVKeepInTarget
Keep the allocation after the expression is complete rather than freeze drying its contents and freei...
Encapsulates memory that may exist in the process but must also be available in the host process.
Definition IRMemoryMap.h:35
void Free(lldb::addr_t process_address, Status &error)
lldb::ByteOrder GetByteOrder()
llvm::Expected< lldb::addr_t > Malloc(size_t size, uint8_t alignment, uint32_t permissions, AllocationPolicy policy, bool zero_memory, AllocationPolicy *used_policy=nullptr)
void ReadPointerFromMemory(lldb::addr_t *address, lldb::addr_t process_address, Status &error)
ExecutionContextScope * GetBestExecutionContextScope() const
void GetMemoryData(DataExtractor &extractor, lldb::addr_t process_address, size_t size, Status &error)
void WritePointerToMemory(lldb::addr_t process_address, lldb::addr_t pointer, Status &error)
void WriteScalarToMemory(lldb::addr_t process_address, Scalar &scalar, size_t size, Status &error)
void Leak(lldb::addr_t process_address, Status &error)
void WriteMemory(lldb::addr_t process_address, const uint8_t *bytes, size_t size, Status &error)
void ReadMemory(uint8_t *bytes, lldb::addr_t process_address, size_t size, Status &error)
@ eAllocationPolicyMirror
The intent is that this allocation exist both in the host and the process and have the same content i...
Definition IRMemoryMap.h:47
void PutString(llvm::StringRef str)
Definition Log.cpp:147
void Dematerialize(Status &err, lldb::addr_t frame_top, lldb::addr_t frame_bottom)
uint32_t AddResultVariable(const CompilerType &type, bool is_lvalue, bool keep_in_memory, PersistentVariableDelegate *delegate, Status &err)
uint32_t AddStructMember(Entity &entity)
std::unique_ptr< Entity > EntityUP
std::shared_ptr< Dematerializer > DematerializerSP
DematerializerSP Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, lldb::addr_t process_address, Status &err)
uint32_t AddSymbol(const Symbol &symbol_sp, Status &err)
uint32_t AddRegister(const RegisterInfo &register_info, Status &err)
DematerializerWP m_dematerializer_wp
uint32_t AddValueObject(ConstString name, ValueObjectProviderTy valobj_provider, Status &err)
Create entity from supplied ValueObject and count it as a member of the materialized struct.
uint32_t AddPersistentVariable(lldb::ExpressionVariableSP &persistent_variable_sp, PersistentVariableDelegate *delegate, Status &err)
uint32_t AddVariable(lldb::VariableSP &variable_sp, Status &err)
virtual lldb::ExpressionVariableSP CreatePersistentVariable(const lldb::ValueObjectSP &valobj_sp)=0
virtual ConstString GetNextPersistentVariableName(bool is_error=false)=0
Return a new persistent variable name with the specified prefix.
uint32_t GetAsMemoryData(const RegisterInfo &reg_info, void *dst, uint32_t dst_len, lldb::ByteOrder dst_byte_order, Status &error) const
An error handling class.
Definition Status.h:118
void Clear()
Clear the object state.
Definition Status.cpp:214
static Status FromErrorStringWithFormat(const char *format,...) __attribute__((format(printf
Definition Status.cpp:106
static Status FromErrorString(const char *str)
Definition Status.h:141
bool Fail() const
Test for error condition.
Definition Status.cpp:293
const char * AsCString(const char *default_error_str="unknown error") const
Get the error string associated with the current error.
Definition Status.cpp:194
static Status static Status FromErrorStringWithFormatv(const char *format, Args &&...args)
Definition Status.h:151
static Status FromError(llvm::Error error)
Avoid using this in new code. Migrate APIs to llvm::Expected instead.
Definition Status.cpp:136
bool Success() const
Test for success condition.
Definition Status.cpp:303
llvm::StringRef GetString() const
void Format(const char *format, Args &&... args)
Forwards the arguments to llvm::formatv and writes to the stream.
Definition Stream.h:367
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition Stream.cpp:132
size_t PutChar(char ch)
Definition Stream.cpp:129
static lldb::ValueObjectSP Create(ExecutionContextScope *exe_scope, lldb::ByteOrder byte_order, uint32_t addr_byte_size, lldb::addr_t address=LLDB_INVALID_ADDRESS)
static lldb::ValueObjectSP Create(ExecutionContextScope *exe_scope, const lldb::VariableSP &var_sp)
uint8_t * GetBytes()
Get a pointer to the data.
Definition DataBuffer.h:108
#define LLDB_INVALID_ADDRESS
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
Definition Log.h:327
std::function< lldb::ValueObjectSP(ConstString, StackFrame *)> ValueObjectProviderTy
Functor that returns a ValueObjectSP for a variable given its name and the StackFrame of interest.
void DumpHexBytes(Stream *s, const void *src, size_t src_len, uint32_t bytes_per_line, lldb::addr_t base_addr)
@ eAddressTypeLoad
Address is an address as in the current target inferior process.
std::string toString(FormatterBytecode::OpCodes op)
std::shared_ptr< lldb_private::StackFrame > StackFrameSP
std::shared_ptr< lldb_private::Thread > ThreadSP
std::shared_ptr< lldb_private::ValueObject > ValueObjectSP
std::shared_ptr< lldb_private::ExpressionVariable > ExpressionVariableSP
uint64_t offset_t
Definition lldb-types.h:85
std::shared_ptr< lldb_private::Process > ProcessSP
std::shared_ptr< lldb_private::Variable > VariableSP
std::shared_ptr< lldb_private::DataBuffer > DataBufferSP
uint64_t addr_t
Definition lldb-types.h:80
std::shared_ptr< lldb_private::Target > TargetSP
std::shared_ptr< lldb_private::RegisterContext > RegisterContextSP
Every register is described in detail including its name, alternate name (optional),...