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
14#include "lldb/Symbol/Symbol.h"
15#include "lldb/Symbol/Type.h"
20#include "lldb/Target/Target.h"
21#include "lldb/Target/Thread.h"
23#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
68 m_alignment = g_default_var_alignment;
69 }
70
72 Log *log = GetLog(LLDBLog::Expressions);
73
74 // Allocate a spare memory area to store the persistent variable's
75 // contents.
76
77 Status allocate_error;
78 const bool zero_memory = false;
79
80 lldb::addr_t mem = map.Malloc(
81 m_persistent_variable_sp->GetByteSize().value_or(0), 8,
82 lldb::ePermissionsReadable | lldb::ePermissionsWritable,
83 IRMemoryMap::eAllocationPolicyMirror, zero_memory, allocate_error);
84
85 if (!allocate_error.Success()) {
87 "couldn't allocate a memory area to store %s: %s",
88 m_persistent_variable_sp->GetName().GetCString(),
89 allocate_error.AsCString());
90 return;
91 }
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
99 m_persistent_variable_sp->m_live_sp = ValueObjectConstResult::Create(
101 m_persistent_variable_sp->GetCompilerType(),
102 m_persistent_variable_sp->GetName(), mem, eAddressTypeLoad,
103 map.GetAddressByteSize());
104
105 // Clear the flag if the variable will never be deallocated.
106
107 if (m_persistent_variable_sp->m_flags &
109 Status leak_error;
110 map.Leak(mem, leak_error);
111 m_persistent_variable_sp->m_flags &=
112 ~ExpressionVariable::EVNeedsAllocation;
113 }
114
115 // Write the contents of the variable to the area.
116
117 Status write_error;
118
119 map.WriteMemory(mem, m_persistent_variable_sp->GetValueBytes(),
120 m_persistent_variable_sp->GetByteSize().value_or(0),
121 write_error);
122
123 if (!write_error.Success()) {
125 "couldn't write %s to the target: %s",
126 m_persistent_variable_sp->GetName().AsCString(),
127 write_error.AsCString());
128 return;
129 }
130 }
131
133 Status deallocate_error;
134
135 map.Free((lldb::addr_t)m_persistent_variable_sp->m_live_sp->GetValue()
136 .GetScalar()
137 .ULongLong(),
138 deallocate_error);
139
140 m_persistent_variable_sp->m_live_sp.reset();
141
142 if (!deallocate_error.Success()) {
144 "couldn't deallocate memory for %s: %s",
145 m_persistent_variable_sp->GetName().GetCString(),
146 deallocate_error.AsCString());
147 }
148 }
149
151 lldb::addr_t process_address, Status &err) override {
152 Log *log = GetLog(LLDBLog::Expressions);
153
154 const lldb::addr_t load_addr = process_address + m_offset;
155
156 if (log) {
157 LLDB_LOGF(log,
158 "EntityPersistentVariable::Materialize [address = 0x%" PRIx64
159 ", m_name = %s, m_flags = 0x%hx]",
160 (uint64_t)load_addr,
161 m_persistent_variable_sp->GetName().AsCString(),
162 m_persistent_variable_sp->m_flags);
163 }
164
165 if (m_persistent_variable_sp->m_flags &
167 MakeAllocation(map, err);
168 m_persistent_variable_sp->m_flags |=
170
171 if (!err.Success())
172 return;
173 }
174
175 if ((m_persistent_variable_sp->m_flags &
177 m_persistent_variable_sp->m_live_sp) ||
178 m_persistent_variable_sp->m_flags &
180 Status write_error;
181
183 load_addr,
184 m_persistent_variable_sp->m_live_sp->GetValue().GetScalar(),
185 map.GetAddressByteSize(), write_error);
186
187 if (!write_error.Success()) {
189 "couldn't write the location of %s to memory: %s",
190 m_persistent_variable_sp->GetName().AsCString(),
191 write_error.AsCString());
192 }
193 } else {
195 "no materialization happened for persistent variable %s",
196 m_persistent_variable_sp->GetName().AsCString());
197 return;
198 }
199 }
200
202 lldb::addr_t process_address, lldb::addr_t frame_top,
203 lldb::addr_t frame_bottom, Status &err) override {
204 Log *log = GetLog(LLDBLog::Expressions);
205
206 const lldb::addr_t load_addr = process_address + m_offset;
207
208 if (log) {
209 LLDB_LOGF(log,
210 "EntityPersistentVariable::Dematerialize [address = 0x%" PRIx64
211 ", m_name = %s, m_flags = 0x%hx]",
212 (uint64_t)process_address + m_offset,
213 m_persistent_variable_sp->GetName().AsCString(),
214 m_persistent_variable_sp->m_flags);
215 }
216
217 if (m_delegate) {
218 m_delegate->DidDematerialize(m_persistent_variable_sp);
219 }
220
221 if ((m_persistent_variable_sp->m_flags &
223 (m_persistent_variable_sp->m_flags &
225 if (m_persistent_variable_sp->m_flags &
227 !m_persistent_variable_sp->m_live_sp) {
228 // If the reference comes from the program, then the
229 // ClangExpressionVariable's live variable data hasn't been set up yet.
230 // Do this now.
231
232 lldb::addr_t location;
233 Status read_error;
234
235 map.ReadPointerFromMemory(&location, load_addr, read_error);
236
237 if (!read_error.Success()) {
239 "couldn't read the address of program-allocated variable %s: %s",
240 m_persistent_variable_sp->GetName().GetCString(),
241 read_error.AsCString());
242 return;
243 }
244
245 m_persistent_variable_sp->m_live_sp = ValueObjectConstResult::Create(
247 m_persistent_variable_sp.get()->GetCompilerType(),
248 m_persistent_variable_sp->GetName(), location, eAddressTypeLoad,
249 m_persistent_variable_sp->GetByteSize().value_or(0));
250
251 if (frame_top != LLDB_INVALID_ADDRESS &&
252 frame_bottom != LLDB_INVALID_ADDRESS && location >= frame_bottom &&
253 location <= frame_top) {
254 // If the variable is resident in the stack frame created by the
255 // expression, then it cannot be relied upon to stay around. We
256 // treat it as needing reallocation.
257 m_persistent_variable_sp->m_flags |=
259 m_persistent_variable_sp->m_flags |=
261 m_persistent_variable_sp->m_flags |=
263 m_persistent_variable_sp->m_flags &=
264 ~ExpressionVariable::EVIsProgramReference;
265 }
266 }
267
268 lldb::addr_t mem = m_persistent_variable_sp->m_live_sp->GetValue()
269 .GetScalar()
270 .ULongLong();
271
272 if (!m_persistent_variable_sp->m_live_sp) {
274 "couldn't find the memory area used to store %s",
275 m_persistent_variable_sp->GetName().GetCString());
276 return;
277 }
278
279 if (m_persistent_variable_sp->m_live_sp->GetValue()
280 .GetValueAddressType() != eAddressTypeLoad) {
282 "the address of the memory area for %s is in an incorrect format",
283 m_persistent_variable_sp->GetName().GetCString());
284 return;
285 }
286
287 if (m_persistent_variable_sp->m_flags &
289 m_persistent_variable_sp->m_flags &
291 LLDB_LOGF(log, "Dematerializing %s from 0x%" PRIx64 " (size = %llu)",
292 m_persistent_variable_sp->GetName().GetCString(),
293 (uint64_t)mem,
294 (unsigned long long)m_persistent_variable_sp->GetByteSize()
295 .value_or(0));
296
297 // Read the contents of the spare memory area
298
299 m_persistent_variable_sp->ValueUpdated();
300
301 Status read_error;
302
303 map.ReadMemory(m_persistent_variable_sp->GetValueBytes(), mem,
304 m_persistent_variable_sp->GetByteSize().value_or(0),
305 read_error);
306
307 if (!read_error.Success()) {
309 "couldn't read the contents of %s from memory: %s",
310 m_persistent_variable_sp->GetName().GetCString(),
311 read_error.AsCString());
312 return;
313 }
314
315 m_persistent_variable_sp->m_flags &=
316 ~ExpressionVariable::EVNeedsFreezeDry;
317 }
318 } else {
320 "no dematerialization happened for persistent variable %s",
321 m_persistent_variable_sp->GetName().AsCString());
322 return;
323 }
324
325 lldb::ProcessSP process_sp =
327 if (!process_sp || !process_sp->CanJIT()) {
328 // Allocations are not persistent so persistent variables cannot stay
329 // materialized.
330
331 m_persistent_variable_sp->m_flags |=
333
334 DestroyAllocation(map, err);
335 if (!err.Success())
336 return;
337 } else if (m_persistent_variable_sp->m_flags &
339 !(m_persistent_variable_sp->m_flags &
341 DestroyAllocation(map, err);
342 if (!err.Success())
343 return;
344 }
345 }
346
347 void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
348 Log *log) override {
349 StreamString dump_stream;
350
351 Status err;
352
353 const lldb::addr_t load_addr = process_address + m_offset;
354
355 dump_stream.Printf("0x%" PRIx64 ": EntityPersistentVariable (%s)\n",
356 load_addr,
357 m_persistent_variable_sp->GetName().AsCString());
358
359 {
360 dump_stream.Printf("Pointer:\n");
361
362 DataBufferHeap data(m_size, 0);
363
364 map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
365
366 if (!err.Success()) {
367 dump_stream.Printf(" <could not be read>\n");
368 } else {
369 DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
370 load_addr);
371
372 dump_stream.PutChar('\n');
373 }
374 }
375
376 {
377 dump_stream.Printf("Target:\n");
378
379 lldb::addr_t target_address;
380
381 map.ReadPointerFromMemory(&target_address, load_addr, err);
382
383 if (!err.Success()) {
384 dump_stream.Printf(" <could not be read>\n");
385 } else {
386 DataBufferHeap data(m_persistent_variable_sp->GetByteSize().value_or(0),
387 0);
388
389 map.ReadMemory(data.GetBytes(), target_address,
390 m_persistent_variable_sp->GetByteSize().value_or(0),
391 err);
392
393 if (!err.Success()) {
394 dump_stream.Printf(" <could not be read>\n");
395 } else {
396 DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
397 target_address);
398
399 dump_stream.PutChar('\n');
400 }
401 }
402 }
403
404 log->PutString(dump_stream.GetString());
405 }
406
407 void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {}
408
409private:
412};
413
415 lldb::ExpressionVariableSP &persistent_variable_sp,
416 PersistentVariableDelegate *delegate, Status &err) {
417 EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
418 *iter = std::make_unique<EntityPersistentVariable>(persistent_variable_sp,
419 delegate);
420 uint32_t ret = AddStructMember(**iter);
421 (*iter)->SetOffset(ret);
422 return ret;
423}
424
425/// Base class for materialization of Variables and ValueObjects.
426///
427/// Subclasses specify how to obtain the Value which is to be
428/// materialized.
430public:
431 virtual ~EntityVariableBase() = default;
432
434 // Hard-coding to maximum size of a pointer since all variables are
435 // materialized by reference
437 m_alignment = g_default_var_alignment;
438 }
439
441 lldb::addr_t process_address, Status &err) override {
442 Log *log = GetLog(LLDBLog::Expressions);
443
444 const lldb::addr_t load_addr = process_address + m_offset;
445 if (log) {
446 LLDB_LOGF(log,
447 "EntityVariable::Materialize [address = 0x%" PRIx64
448 ", m_variable_sp = %s]",
449 (uint64_t)load_addr, GetName().GetCString());
450 }
451
452 ExecutionContextScope *scope = frame_sp.get();
453
454 if (!scope)
455 scope = map.GetBestExecutionContextScope();
456
457 lldb::ValueObjectSP valobj_sp = SetupValueObject(scope);
458
459 if (!valobj_sp) {
461 "couldn't get a value object for variable %s", GetName().AsCString());
462 return;
463 }
464
465 Status valobj_error = valobj_sp->GetError();
466
467 if (valobj_error.Fail()) {
468 err.SetErrorStringWithFormat("couldn't get the value of variable %s: %s",
469 GetName().AsCString(),
470 valobj_error.AsCString());
471 return;
472 }
473
474 if (m_is_reference) {
475 DataExtractor valobj_extractor;
476 Status extract_error;
477 valobj_sp->GetData(valobj_extractor, extract_error);
478
479 if (!extract_error.Success()) {
481 "couldn't read contents of reference variable %s: %s",
482 GetName().AsCString(), extract_error.AsCString());
483 return;
484 }
485
486 lldb::offset_t offset = 0;
487 lldb::addr_t reference_addr = valobj_extractor.GetAddress(&offset);
488
489 Status write_error;
490 map.WritePointerToMemory(load_addr, reference_addr, write_error);
491
492 if (!write_error.Success()) {
493 err.SetErrorStringWithFormat("couldn't write the contents of reference "
494 "variable %s to memory: %s",
495 GetName().AsCString(),
496 write_error.AsCString());
497 return;
498 }
499 } else {
500 AddressType address_type = eAddressTypeInvalid;
501 const bool scalar_is_load_address = false;
502 lldb::addr_t addr_of_valobj =
503 valobj_sp->GetAddressOf(scalar_is_load_address, &address_type);
504 if (addr_of_valobj != LLDB_INVALID_ADDRESS) {
505 Status write_error;
506 map.WritePointerToMemory(load_addr, addr_of_valobj, write_error);
507
508 if (!write_error.Success()) {
510 "couldn't write the address of variable %s to memory: %s",
511 GetName().AsCString(), write_error.AsCString());
512 return;
513 }
514 } else {
515 DataExtractor data;
516 Status extract_error;
517 valobj_sp->GetData(data, extract_error);
518 if (!extract_error.Success()) {
519 err.SetErrorStringWithFormat("couldn't get the value of %s: %s",
520 GetName().AsCString(),
521 extract_error.AsCString());
522 return;
523 }
524
525 if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
527 "trying to create a temporary region for %s but one exists",
528 GetName().AsCString());
529 return;
530 }
531
532 if (data.GetByteSize() < GetByteSize(scope)) {
533 if (data.GetByteSize() == 0 && !LocationExpressionIsValid()) {
534 err.SetErrorStringWithFormat("the variable '%s' has no location, "
535 "it may have been optimized out",
536 GetName().AsCString());
537 } else {
539 "size of variable %s (%" PRIu64
540 ") is larger than the ValueObject's size (%" PRIu64 ")",
541 GetName().AsCString(), GetByteSize(scope).value_or(0),
542 data.GetByteSize());
543 }
544 return;
545 }
546
547 std::optional<size_t> opt_bit_align = GetTypeBitAlign(scope);
548 if (!opt_bit_align) {
549 err.SetErrorStringWithFormat("can't get the type alignment for %s",
550 GetName().AsCString());
551 return;
552 }
553
554 size_t byte_align = (*opt_bit_align + 7) / 8;
555
556 Status alloc_error;
557 const bool zero_memory = false;
558
559 m_temporary_allocation = map.Malloc(
560 data.GetByteSize(), byte_align,
561 lldb::ePermissionsReadable | lldb::ePermissionsWritable,
562 IRMemoryMap::eAllocationPolicyMirror, zero_memory, alloc_error);
563
564 m_temporary_allocation_size = data.GetByteSize();
565
566 m_original_data = std::make_shared<DataBufferHeap>(data.GetDataStart(),
567 data.GetByteSize());
568
569 if (!alloc_error.Success()) {
571 "couldn't allocate a temporary region for %s: %s",
572 GetName().AsCString(), alloc_error.AsCString());
573 return;
574 }
575
576 Status write_error;
577
578 map.WriteMemory(m_temporary_allocation, data.GetDataStart(),
579 data.GetByteSize(), write_error);
580
581 if (!write_error.Success()) {
583 "couldn't write to the temporary region for %s: %s",
584 GetName().AsCString(), write_error.AsCString());
585 return;
586 }
587
588 Status pointer_write_error;
589
590 map.WritePointerToMemory(load_addr, m_temporary_allocation,
591 pointer_write_error);
592
593 if (!pointer_write_error.Success()) {
595 "couldn't write the address of the temporary region for %s: %s",
596 GetName().AsCString(), pointer_write_error.AsCString());
597 }
598 }
599 }
600 }
601
603 lldb::addr_t process_address, lldb::addr_t frame_top,
604 lldb::addr_t frame_bottom, Status &err) override {
605 Log *log = GetLog(LLDBLog::Expressions);
606
607 const lldb::addr_t load_addr = process_address + m_offset;
608 if (log) {
609 LLDB_LOGF(log,
610 "EntityVariable::Dematerialize [address = 0x%" PRIx64
611 ", m_variable_sp = %s]",
612 (uint64_t)load_addr, GetName().AsCString());
613 }
614
615 if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
616 ExecutionContextScope *scope = frame_sp.get();
617
618 if (!scope)
619 scope = map.GetBestExecutionContextScope();
620
621 lldb::ValueObjectSP valobj_sp = SetupValueObject(scope);
622
623 if (!valobj_sp) {
625 "couldn't get a value object for variable %s",
626 GetName().AsCString());
627 return;
628 }
629
631
632 Status extract_error;
633
634 map.GetMemoryData(data, m_temporary_allocation,
635 valobj_sp->GetByteSize().value_or(0), extract_error);
636
637 if (!extract_error.Success()) {
638 err.SetErrorStringWithFormat("couldn't get the data for variable %s",
639 GetName().AsCString());
640 return;
641 }
642
643 bool actually_write = true;
644
645 if (m_original_data) {
646 if ((data.GetByteSize() == m_original_data->GetByteSize()) &&
647 !memcmp(m_original_data->GetBytes(), data.GetDataStart(),
648 data.GetByteSize())) {
649 actually_write = false;
650 }
651 }
652
653 Status set_error;
654
655 if (actually_write) {
656 valobj_sp->SetData(data, set_error);
657
658 if (!set_error.Success()) {
660 "couldn't write the new contents of %s back into the variable",
661 GetName().AsCString());
662 return;
663 }
664 }
665
666 Status free_error;
667
668 map.Free(m_temporary_allocation, free_error);
669
670 if (!free_error.Success()) {
672 "couldn't free the temporary region for %s: %s",
673 GetName().AsCString(), free_error.AsCString());
674 return;
675 }
676
677 m_original_data.reset();
678 m_temporary_allocation = LLDB_INVALID_ADDRESS;
679 m_temporary_allocation_size = 0;
680 }
681 }
682
683 void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
684 Log *log) override {
685 StreamString dump_stream;
686
687 const lldb::addr_t load_addr = process_address + m_offset;
688 dump_stream.Printf("0x%" PRIx64 ": EntityVariable\n", load_addr);
689
690 Status err;
691
693
694 {
695 dump_stream.Printf("Pointer:\n");
696
697 DataBufferHeap data(m_size, 0);
698
699 map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
700
701 if (!err.Success()) {
702 dump_stream.Printf(" <could not be read>\n");
703 } else {
704 DataExtractor extractor(data.GetBytes(), data.GetByteSize(),
705 map.GetByteOrder(), map.GetAddressByteSize());
706
707 DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
708 load_addr);
709
710 lldb::offset_t offset = 0;
711
712 ptr = extractor.GetAddress(&offset);
713
714 dump_stream.PutChar('\n');
715 }
716 }
717
718 if (m_temporary_allocation == LLDB_INVALID_ADDRESS) {
719 dump_stream.Printf("Points to process memory:\n");
720 } else {
721 dump_stream.Printf("Temporary allocation:\n");
722 }
723
724 if (ptr == LLDB_INVALID_ADDRESS) {
725 dump_stream.Printf(" <could not be be found>\n");
726 } else {
727 DataBufferHeap data(m_temporary_allocation_size, 0);
728
729 map.ReadMemory(data.GetBytes(), m_temporary_allocation,
730 m_temporary_allocation_size, err);
731
732 if (!err.Success()) {
733 dump_stream.Printf(" <could not be read>\n");
734 } else {
735 DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
736 load_addr);
737
738 dump_stream.PutChar('\n');
739 }
740 }
741
742 log->PutString(dump_stream.GetString());
743 }
744
745 void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {
746 if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
747 Status free_error;
748
749 map.Free(m_temporary_allocation, free_error);
750
751 m_temporary_allocation = LLDB_INVALID_ADDRESS;
752 m_temporary_allocation_size = 0;
753 }
754 }
755
756private:
757 virtual ConstString GetName() const = 0;
758
759 /// Creates and returns ValueObject tied to this variable
760 /// and prepares Entity for materialization.
761 ///
762 /// Called each time the Materializer (de)materializes a
763 /// variable. We re-create the ValueObject based on the
764 /// current ExecutionContextScope since clients such as
765 /// conditional breakpoints may materialize the same
766 /// EntityVariable multiple times with different frames.
767 ///
768 /// Each subsequent use of the EntityVariableBase interface
769 /// will query the newly created ValueObject until this
770 /// function is called again.
771 virtual lldb::ValueObjectSP
773
774 /// Returns size in bytes of the type associated with this variable
775 ///
776 /// \returns On success, returns byte size of the type associated
777 /// with this variable. Returns std::nullopt otherwise.
778 virtual std::optional<uint64_t>
780
781 /// Returns 'true' if the location expression associated with this variable
782 /// is valid.
783 virtual bool LocationExpressionIsValid() const = 0;
784
785 /// Returns alignment of the type associated with this variable in bits.
786 ///
787 /// \returns On success, returns alignment in bits for the type associated
788 /// with this variable. Returns std::nullopt otherwise.
789 virtual std::optional<size_t>
791
792protected:
793 bool m_is_reference = false;
794 lldb::addr_t m_temporary_allocation = LLDB_INVALID_ADDRESS;
795 size_t m_temporary_allocation_size = 0;
797};
798
799/// Represents an Entity constructed from a VariableSP.
800///
801/// This class is used for materialization of variables for which
802/// the user has a VariableSP on hand. The ValueObject is then
803/// derived from the associated DWARF location expression when needed
804/// by the Materializer.
806public:
807 EntityVariable(lldb::VariableSP &variable_sp) : m_variable_sp(variable_sp) {
808 m_is_reference =
809 m_variable_sp->GetType()->GetForwardCompilerType().IsReferenceType();
810 }
811
812 ConstString GetName() const override { return m_variable_sp->GetName(); }
813
815 assert(m_variable_sp != nullptr);
816 return ValueObjectVariable::Create(scope, m_variable_sp);
817 }
818
819 std::optional<uint64_t>
820 GetByteSize(ExecutionContextScope *scope) const override {
821 return m_variable_sp->GetType()->GetByteSize(scope);
822 }
823
824 bool LocationExpressionIsValid() const override {
825 return m_variable_sp->LocationExpressionList().IsValid();
826 }
827
828 std::optional<size_t>
829 GetTypeBitAlign(ExecutionContextScope *scope) const override {
830 return m_variable_sp->GetType()->GetLayoutCompilerType().GetTypeBitAlign(
831 scope);
832 }
833
834private:
835 lldb::VariableSP m_variable_sp; ///< Variable that this entity is based on.
836};
837
838/// Represents an Entity constructed from a VariableSP.
839///
840/// This class is used for materialization of variables for
841/// which the user does not have a VariableSP available (e.g.,
842/// when materializing ivars).
844public:
846 : m_name(name), m_valobj_provider(std::move(provider)) {
847 assert(m_valobj_provider);
848 }
849
850 ConstString GetName() const override { return m_name; }
851
853 m_valobj_sp =
854 m_valobj_provider(GetName(), scope->CalculateStackFrame().get());
855
856 if (m_valobj_sp)
857 m_is_reference = m_valobj_sp->GetCompilerType().IsReferenceType();
858
859 return m_valobj_sp;
860 }
861
862 std::optional<uint64_t>
863 GetByteSize(ExecutionContextScope *scope) const override {
864 if (m_valobj_sp)
865 return m_valobj_sp->GetCompilerType().GetByteSize(scope);
866
867 return {};
868 }
869
870 bool LocationExpressionIsValid() const override {
871 if (m_valobj_sp)
872 return m_valobj_sp->GetError().Success();
873
874 return false;
875 }
876
877 std::optional<size_t>
878 GetTypeBitAlign(ExecutionContextScope *scope) const override {
879 if (m_valobj_sp)
880 return m_valobj_sp->GetCompilerType().GetTypeBitAlign(scope);
881
882 return {};
883 }
884
885private:
889};
890
892 EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
893 *iter = std::make_unique<EntityVariable>(variable_sp);
894 uint32_t ret = AddStructMember(**iter);
895 (*iter)->SetOffset(ret);
896 return ret;
897}
898
900 ValueObjectProviderTy valobj_provider,
901 Status &err) {
902 assert(valobj_provider);
903 EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
904 *iter = std::make_unique<EntityValueObject>(name, std::move(valobj_provider));
905 uint32_t ret = AddStructMember(**iter);
906 (*iter)->SetOffset(ret);
907 return ret;
908}
909
911public:
912 EntityResultVariable(const CompilerType &type, bool is_program_reference,
913 bool keep_in_memory,
915 : Entity(), m_type(type), m_is_program_reference(is_program_reference),
916 m_keep_in_memory(keep_in_memory), m_delegate(delegate) {
917 // Hard-coding to maximum size of a pointer since all results are
918 // materialized by reference
920 m_alignment = g_default_var_alignment;
921 }
922
924 lldb::addr_t process_address, Status &err) override {
925 if (!m_is_program_reference) {
926 if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
927 err.SetErrorString("Trying to create a temporary region for the result "
928 "but one exists");
929 return;
930 }
931
932 const lldb::addr_t load_addr = process_address + m_offset;
933
934 ExecutionContextScope *exe_scope = frame_sp.get();
935 if (!exe_scope)
936 exe_scope = map.GetBestExecutionContextScope();
937
938 std::optional<uint64_t> byte_size = m_type.GetByteSize(exe_scope);
939 if (!byte_size) {
940 err.SetErrorStringWithFormat("can't get size of type \"%s\"",
941 m_type.GetTypeName().AsCString());
942 return;
943 }
944
945 std::optional<size_t> opt_bit_align = m_type.GetTypeBitAlign(exe_scope);
946 if (!opt_bit_align) {
947 err.SetErrorStringWithFormat("can't get the alignment of type \"%s\"",
948 m_type.GetTypeName().AsCString());
949 return;
950 }
951
952 size_t byte_align = (*opt_bit_align + 7) / 8;
953
954 Status alloc_error;
955 const bool zero_memory = true;
956
957 m_temporary_allocation = map.Malloc(
958 *byte_size, byte_align,
959 lldb::ePermissionsReadable | lldb::ePermissionsWritable,
960 IRMemoryMap::eAllocationPolicyMirror, zero_memory, alloc_error);
961 m_temporary_allocation_size = *byte_size;
962
963 if (!alloc_error.Success()) {
965 "couldn't allocate a temporary region for the result: %s",
966 alloc_error.AsCString());
967 return;
968 }
969
970 Status pointer_write_error;
971
972 map.WritePointerToMemory(load_addr, m_temporary_allocation,
973 pointer_write_error);
974
975 if (!pointer_write_error.Success()) {
976 err.SetErrorStringWithFormat("couldn't write the address of the "
977 "temporary region for the result: %s",
978 pointer_write_error.AsCString());
979 }
980 }
981 }
982
984 lldb::addr_t process_address, lldb::addr_t frame_top,
985 lldb::addr_t frame_bottom, Status &err) override {
986 err.Clear();
987
988 ExecutionContextScope *exe_scope = frame_sp.get();
989 if (!exe_scope)
990 exe_scope = map.GetBestExecutionContextScope();
991
992 if (!exe_scope) {
993 err.SetErrorString("Couldn't dematerialize a result variable: invalid "
994 "execution context scope");
995 return;
996 }
997
998 lldb::addr_t address;
999 Status read_error;
1000 const lldb::addr_t load_addr = process_address + m_offset;
1001
1002 map.ReadPointerFromMemory(&address, load_addr, read_error);
1003
1004 if (!read_error.Success()) {
1005 err.SetErrorString("Couldn't dematerialize a result variable: couldn't "
1006 "read its address");
1007 return;
1008 }
1009
1010 lldb::TargetSP target_sp = exe_scope->CalculateTarget();
1011
1012 if (!target_sp) {
1013 err.SetErrorString("Couldn't dematerialize a result variable: no target");
1014 return;
1015 }
1016
1017 auto type_system_or_err =
1018 target_sp->GetScratchTypeSystemForLanguage(m_type.GetMinimumLanguage());
1019
1020 if (auto error = type_system_or_err.takeError()) {
1021 err.SetErrorStringWithFormat("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) {
1029 err.SetErrorStringWithFormat("Couldn't dematerialize a result variable: "
1030 "couldn't corresponding type system is "
1031 "no longer live.");
1032 return;
1033 }
1034 PersistentExpressionState *persistent_state =
1035 ts->GetPersistentExpressionState();
1036
1037 if (!persistent_state) {
1038 err.SetErrorString("Couldn't dematerialize a result variable: "
1039 "corresponding type system doesn't handle persistent "
1040 "variables");
1041 return;
1042 }
1043
1044 ConstString name = m_delegate
1045 ? m_delegate->GetName()
1046 : persistent_state->GetNextPersistentVariableName();
1047
1049 exe_scope, name, m_type, map.GetByteOrder(), map.GetAddressByteSize());
1050
1051 if (!ret) {
1052 err.SetErrorStringWithFormat("couldn't dematerialize a result variable: "
1053 "failed to make persistent variable %s",
1054 name.AsCString());
1055 return;
1056 }
1057
1058 lldb::ProcessSP process_sp =
1060
1061 if (m_delegate) {
1062 m_delegate->DidDematerialize(ret);
1063 }
1064
1065 bool can_persist =
1066 (m_is_program_reference && process_sp && process_sp->CanJIT() &&
1067 !(address >= frame_bottom && address < frame_top));
1068
1069 if (can_persist && m_keep_in_memory) {
1070 ret->m_live_sp = ValueObjectConstResult::Create(exe_scope, m_type, name,
1071 address, eAddressTypeLoad,
1072 map.GetAddressByteSize());
1073 }
1074
1075 ret->ValueUpdated();
1076
1077 const size_t pvar_byte_size = ret->GetByteSize().value_or(0);
1078 uint8_t *pvar_data = ret->GetValueBytes();
1079
1080 map.ReadMemory(pvar_data, address, pvar_byte_size, read_error);
1081
1082 if (!read_error.Success()) {
1083 err.SetErrorString(
1084 "Couldn't dematerialize a result variable: couldn't read its memory");
1085 return;
1086 }
1087
1088 if (!can_persist || !m_keep_in_memory) {
1090
1091 if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
1092 Status free_error;
1093 map.Free(m_temporary_allocation, free_error);
1094 }
1095 } else {
1097 }
1098
1099 m_temporary_allocation = LLDB_INVALID_ADDRESS;
1100 m_temporary_allocation_size = 0;
1101 }
1102
1103 void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
1104 Log *log) override {
1105 StreamString dump_stream;
1106
1107 const lldb::addr_t load_addr = process_address + m_offset;
1108
1109 dump_stream.Printf("0x%" PRIx64 ": EntityResultVariable\n", load_addr);
1110
1111 Status err;
1112
1114
1115 {
1116 dump_stream.Printf("Pointer:\n");
1117
1118 DataBufferHeap data(m_size, 0);
1119
1120 map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
1121
1122 if (!err.Success()) {
1123 dump_stream.Printf(" <could not be read>\n");
1124 } else {
1125 DataExtractor extractor(data.GetBytes(), data.GetByteSize(),
1126 map.GetByteOrder(), map.GetAddressByteSize());
1127
1128 DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
1129 load_addr);
1130
1131 lldb::offset_t offset = 0;
1132
1133 ptr = extractor.GetAddress(&offset);
1134
1135 dump_stream.PutChar('\n');
1136 }
1137 }
1138
1139 if (m_temporary_allocation == LLDB_INVALID_ADDRESS) {
1140 dump_stream.Printf("Points to process memory:\n");
1141 } else {
1142 dump_stream.Printf("Temporary allocation:\n");
1143 }
1144
1145 if (ptr == LLDB_INVALID_ADDRESS) {
1146 dump_stream.Printf(" <could not be be found>\n");
1147 } else {
1148 DataBufferHeap data(m_temporary_allocation_size, 0);
1149
1150 map.ReadMemory(data.GetBytes(), m_temporary_allocation,
1151 m_temporary_allocation_size, err);
1152
1153 if (!err.Success()) {
1154 dump_stream.Printf(" <could not be read>\n");
1155 } else {
1156 DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
1157 load_addr);
1158
1159 dump_stream.PutChar('\n');
1160 }
1161 }
1162
1163 log->PutString(dump_stream.GetString());
1164 }
1165
1166 void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {
1167 if (!m_keep_in_memory && m_temporary_allocation != LLDB_INVALID_ADDRESS) {
1168 Status free_error;
1169
1170 map.Free(m_temporary_allocation, free_error);
1171 }
1172
1173 m_temporary_allocation = LLDB_INVALID_ADDRESS;
1174 m_temporary_allocation_size = 0;
1175 }
1176
1177private:
1181
1182 lldb::addr_t m_temporary_allocation = LLDB_INVALID_ADDRESS;
1183 size_t m_temporary_allocation_size = 0;
1185};
1186
1188 bool is_program_reference,
1189 bool keep_in_memory,
1191 Status &err) {
1192 EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
1193 *iter = std::make_unique<EntityResultVariable>(type, is_program_reference,
1194 keep_in_memory, delegate);
1195 uint32_t ret = AddStructMember(**iter);
1196 (*iter)->SetOffset(ret);
1197 return ret;
1198}
1199
1201public:
1202 EntitySymbol(const Symbol &symbol) : Entity(), m_symbol(symbol) {
1203 // Hard-coding to maximum size of a symbol
1204 m_size = g_default_var_byte_size;
1205 m_alignment = g_default_var_alignment;
1206 }
1207
1209 lldb::addr_t process_address, Status &err) override {
1210 Log *log = GetLog(LLDBLog::Expressions);
1211
1212 const lldb::addr_t load_addr = process_address + m_offset;
1213
1214 if (log) {
1215 LLDB_LOGF(log,
1216 "EntitySymbol::Materialize [address = 0x%" PRIx64
1217 ", m_symbol = %s]",
1218 (uint64_t)load_addr, m_symbol.GetName().AsCString());
1219 }
1220
1221 const Address sym_address = m_symbol.GetAddress();
1222
1223 ExecutionContextScope *exe_scope = frame_sp.get();
1224 if (!exe_scope)
1225 exe_scope = map.GetBestExecutionContextScope();
1226
1227 lldb::TargetSP target_sp;
1228
1229 if (exe_scope)
1230 target_sp = map.GetBestExecutionContextScope()->CalculateTarget();
1231
1232 if (!target_sp) {
1234 "couldn't resolve symbol %s because there is no target",
1235 m_symbol.GetName().AsCString());
1236 return;
1237 }
1238
1239 lldb::addr_t resolved_address = sym_address.GetLoadAddress(target_sp.get());
1240
1241 if (resolved_address == LLDB_INVALID_ADDRESS)
1242 resolved_address = sym_address.GetFileAddress();
1243
1244 Status pointer_write_error;
1245
1246 map.WritePointerToMemory(load_addr, resolved_address, pointer_write_error);
1247
1248 if (!pointer_write_error.Success()) {
1250 "couldn't write the address of symbol %s: %s",
1251 m_symbol.GetName().AsCString(), pointer_write_error.AsCString());
1252 return;
1253 }
1254 }
1255
1257 lldb::addr_t process_address, lldb::addr_t frame_top,
1258 lldb::addr_t frame_bottom, Status &err) override {
1259 Log *log = GetLog(LLDBLog::Expressions);
1260
1261 const lldb::addr_t load_addr = process_address + m_offset;
1262
1263 if (log) {
1264 LLDB_LOGF(log,
1265 "EntitySymbol::Dematerialize [address = 0x%" PRIx64
1266 ", m_symbol = %s]",
1267 (uint64_t)load_addr, m_symbol.GetName().AsCString());
1268 }
1269
1270 // no work needs to be done
1271 }
1272
1273 void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
1274 Log *log) override {
1275 StreamString dump_stream;
1276
1277 Status err;
1278
1279 const lldb::addr_t load_addr = process_address + m_offset;
1280
1281 dump_stream.Printf("0x%" PRIx64 ": EntitySymbol (%s)\n", load_addr,
1282 m_symbol.GetName().AsCString());
1283
1284 {
1285 dump_stream.Printf("Pointer:\n");
1286
1287 DataBufferHeap data(m_size, 0);
1288
1289 map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
1290
1291 if (!err.Success()) {
1292 dump_stream.Printf(" <could not be read>\n");
1293 } else {
1294 DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
1295 load_addr);
1296
1297 dump_stream.PutChar('\n');
1298 }
1299 }
1300
1301 log->PutString(dump_stream.GetString());
1302 }
1303
1304 void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {}
1305
1306private:
1308};
1309
1310uint32_t Materializer::AddSymbol(const Symbol &symbol_sp, Status &err) {
1311 EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
1312 *iter = std::make_unique<EntitySymbol>(symbol_sp);
1313 uint32_t ret = AddStructMember(**iter);
1314 (*iter)->SetOffset(ret);
1315 return ret;
1316}
1317
1319public:
1320 EntityRegister(const RegisterInfo &register_info)
1321 : Entity(), m_register_info(register_info) {
1322 // Hard-coding alignment conservatively
1323 m_size = m_register_info.byte_size;
1324 m_alignment = m_register_info.byte_size;
1325 }
1326
1328 lldb::addr_t process_address, Status &err) override {
1329 Log *log = GetLog(LLDBLog::Expressions);
1330
1331 const lldb::addr_t load_addr = process_address + m_offset;
1332
1333 if (log) {
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
1340 RegisterValue reg_value;
1341
1342 if (!frame_sp.get()) {
1344 "couldn't materialize register %s without a stack frame",
1345 m_register_info.name);
1346 return;
1347 }
1348
1349 lldb::RegisterContextSP reg_context_sp = frame_sp->GetRegisterContext();
1350
1351 if (!reg_context_sp->ReadRegister(&m_register_info, reg_value)) {
1352 err.SetErrorStringWithFormat("couldn't read the value of register %s",
1353 m_register_info.name);
1354 return;
1355 }
1356
1357 DataExtractor register_data;
1358
1359 if (!reg_value.GetData(register_data)) {
1360 err.SetErrorStringWithFormat("couldn't get the data for register %s",
1361 m_register_info.name);
1362 return;
1363 }
1364
1365 if (register_data.GetByteSize() != m_register_info.byte_size) {
1367 "data for register %s had size %llu but we expected %llu",
1368 m_register_info.name, (unsigned long long)register_data.GetByteSize(),
1369 (unsigned long long)m_register_info.byte_size);
1370 return;
1371 }
1372
1373 m_register_contents = std::make_shared<DataBufferHeap>(
1374 register_data.GetDataStart(), register_data.GetByteSize());
1375
1376 Status write_error;
1377
1378 map.WriteMemory(load_addr, register_data.GetDataStart(),
1379 register_data.GetByteSize(), write_error);
1380
1381 if (!write_error.Success()) {
1383 "couldn't write the contents of register %s: %s",
1384 m_register_info.name, write_error.AsCString());
1385 return;
1386 }
1387 }
1388
1390 lldb::addr_t process_address, lldb::addr_t frame_top,
1391 lldb::addr_t frame_bottom, Status &err) override {
1392 Log *log = GetLog(LLDBLog::Expressions);
1393
1394 const lldb::addr_t load_addr = process_address + m_offset;
1395
1396 if (log) {
1397 LLDB_LOGF(log,
1398 "EntityRegister::Dematerialize [address = 0x%" PRIx64
1399 ", m_register_info = %s]",
1400 (uint64_t)load_addr, m_register_info.name);
1401 }
1402
1403 Status extract_error;
1404
1405 DataExtractor register_data;
1406
1407 if (!frame_sp.get()) {
1409 "couldn't dematerialize register %s without a stack frame",
1410 m_register_info.name);
1411 return;
1412 }
1413
1414 lldb::RegisterContextSP reg_context_sp = frame_sp->GetRegisterContext();
1415
1416 map.GetMemoryData(register_data, load_addr, m_register_info.byte_size,
1417 extract_error);
1418
1419 if (!extract_error.Success()) {
1420 err.SetErrorStringWithFormat("couldn't get the data for register %s: %s",
1421 m_register_info.name,
1422 extract_error.AsCString());
1423 return;
1424 }
1425
1426 if (!memcmp(register_data.GetDataStart(), m_register_contents->GetBytes(),
1427 register_data.GetByteSize())) {
1428 // No write required, and in particular we avoid errors if the register
1429 // wasn't writable
1430
1431 m_register_contents.reset();
1432 return;
1433 }
1434
1435 m_register_contents.reset();
1436
1437 RegisterValue register_value(register_data.GetData(),
1438 register_data.GetByteOrder());
1439
1440 if (!reg_context_sp->WriteRegister(&m_register_info, register_value)) {
1441 err.SetErrorStringWithFormat("couldn't write the value of register %s",
1442 m_register_info.name);
1443 return;
1444 }
1445 }
1446
1447 void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
1448 Log *log) override {
1449 StreamString dump_stream;
1450
1451 Status err;
1452
1453 const lldb::addr_t load_addr = process_address + m_offset;
1454
1455 dump_stream.Printf("0x%" PRIx64 ": EntityRegister (%s)\n", load_addr,
1456 m_register_info.name);
1457
1458 {
1459 dump_stream.Printf("Value:\n");
1460
1461 DataBufferHeap data(m_size, 0);
1462
1463 map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
1464
1465 if (!err.Success()) {
1466 dump_stream.Printf(" <could not be read>\n");
1467 } else {
1468 DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
1469 load_addr);
1470
1471 dump_stream.PutChar('\n');
1472 }
1473 }
1474
1475 log->PutString(dump_stream.GetString());
1476 }
1477
1478 void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {}
1479
1480private:
1483};
1484
1485uint32_t Materializer::AddRegister(const RegisterInfo &register_info,
1486 Status &err) {
1487 EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
1488 *iter = std::make_unique<EntityRegister>(register_info);
1489 uint32_t ret = AddStructMember(**iter);
1490 (*iter)->SetOffset(ret);
1491 return ret;
1492}
1493
1495 DematerializerSP dematerializer_sp = m_dematerializer_wp.lock();
1496
1497 if (dematerializer_sp)
1498 dematerializer_sp->Wipe();
1499}
1500
1503 lldb::addr_t process_address, Status &error) {
1504 ExecutionContextScope *exe_scope = frame_sp.get();
1505 if (!exe_scope)
1506 exe_scope = map.GetBestExecutionContextScope();
1507
1508 DematerializerSP dematerializer_sp = m_dematerializer_wp.lock();
1509
1510 if (dematerializer_sp) {
1511 error.SetErrorToGenericError();
1512 error.SetErrorString("Couldn't materialize: already materialized");
1513 }
1514
1515 DematerializerSP ret(
1516 new Dematerializer(*this, frame_sp, map, process_address));
1517
1518 if (!exe_scope) {
1519 error.SetErrorToGenericError();
1520 error.SetErrorString("Couldn't materialize: target doesn't exist");
1521 }
1522
1523 for (EntityUP &entity_up : m_entities) {
1524 entity_up->Materialize(frame_sp, map, process_address, error);
1525
1526 if (!error.Success())
1527 return DematerializerSP();
1528 }
1529
1530 if (Log *log = GetLog(LLDBLog::Expressions)) {
1531 LLDB_LOGF(
1532 log,
1533 "Materializer::Materialize (frame_sp = %p, process_address = 0x%" PRIx64
1534 ") materialized:",
1535 static_cast<void *>(frame_sp.get()), process_address);
1536 for (EntityUP &entity_up : m_entities)
1537 entity_up->DumpToLog(map, process_address, log);
1538 }
1539
1540 m_dematerializer_wp = ret;
1541
1542 return ret;
1543}
1544
1546 lldb::addr_t frame_bottom,
1547 lldb::addr_t frame_top) {
1548 lldb::StackFrameSP frame_sp;
1549
1550 lldb::ThreadSP thread_sp = m_thread_wp.lock();
1551 if (thread_sp)
1552 frame_sp = thread_sp->GetFrameWithStackID(m_stack_id);
1553
1554 ExecutionContextScope *exe_scope = frame_sp.get();
1555 if (!exe_scope)
1556 exe_scope = m_map->GetBestExecutionContextScope();
1557
1558 if (!IsValid()) {
1559 error.SetErrorToGenericError();
1560 error.SetErrorString("Couldn't dematerialize: invalid dematerializer");
1561 }
1562
1563 if (!exe_scope) {
1564 error.SetErrorToGenericError();
1565 error.SetErrorString("Couldn't dematerialize: target is gone");
1566 } else {
1567 if (Log *log = GetLog(LLDBLog::Expressions)) {
1568 LLDB_LOGF(log,
1569 "Materializer::Dematerialize (frame_sp = %p, process_address "
1570 "= 0x%" PRIx64 ") about to dematerialize:",
1571 static_cast<void *>(frame_sp.get()), m_process_address);
1572 for (EntityUP &entity_up : m_materializer->m_entities)
1573 entity_up->DumpToLog(*m_map, m_process_address, log);
1574 }
1575
1576 for (EntityUP &entity_up : m_materializer->m_entities) {
1577 entity_up->Dematerialize(frame_sp, *m_map, m_process_address, frame_top,
1578 frame_bottom, error);
1579
1580 if (!error.Success())
1581 break;
1582 }
1583 }
1584
1585 Wipe();
1586}
1587
1589 if (!IsValid())
1590 return;
1591
1592 for (EntityUP &entity_up : m_materializer->m_entities) {
1593 entity_up->Wipe(*m_map, m_process_address);
1594 }
1595
1596 m_materializer = nullptr;
1597 m_map = nullptr;
1598 m_process_address = LLDB_INVALID_ADDRESS;
1599}
1600
1602 default;
1604 default;
static llvm::raw_ostream & error(Stream &strm)
static const char * GetName(DWARFDeclContext::Entry entry)
Returns the name of entry if it has one, or the appropriate "anonymous {namespace,...
#define LLDB_LOGF(log,...)
Definition: Log.h:349
static constexpr uint32_t g_default_var_byte_size
static constexpr uint32_t g_default_var_alignment
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
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
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
Represents an Entity constructed from a VariableSP.
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.
lldb::ValueObjectSP SetupValueObject(ExecutionContextScope *scope) override
Creates and returns ValueObject tied to this variable and prepares Entity for materialization.
std::optional< uint64_t > GetByteSize(ExecutionContextScope *scope) const override
Returns size in bytes of the type associated with this variable.
ConstString m_name
EntityValueObject(ConstString name, ValueObjectProviderTy provider)
Base class for materialization of Variables and ValueObjects.
lldb::DataBufferSP m_original_data
void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, lldb::addr_t process_address, Status &err) override
virtual std::optional< uint64_t > GetByteSize(ExecutionContextScope *scope) const =0
Returns size in bytes of the type associated with this variable.
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.
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
Represents an Entity constructed from a VariableSP.
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.
std::optional< 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:313
lldb::addr_t GetFileAddress() const
Get the file address.
Definition: Address.cpp:293
Generic representation of a type in a programming language.
Definition: CompilerType.h:36
A uniqued constant string class.
Definition: ConstString.h:40
const char * AsCString(const char *value_if_empty=nullptr) const
Get the string value as a C string.
Definition: ConstString.h:188
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.
Definition: DataExtractor.h:48
const void * GetData(lldb::offset_t *offset_ptr, lldb::offset_t length) const
Extract length bytes from *offset_ptr.
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:34
void Free(lldb::addr_t process_address, Status &error)
lldb::ByteOrder GetByteOrder()
void ReadPointerFromMemory(lldb::addr_t *address, lldb::addr_t process_address, Status &error)
ExecutionContextScope * GetBestExecutionContextScope() const
lldb::addr_t Malloc(size_t size, uint8_t alignment, uint32_t permissions, AllocationPolicy policy, bool zero_memory, Status &error)
void GetMemoryData(DataExtractor &extractor, lldb::addr_t process_address, size_t size, Status &error)
void WritePointerToMemory(lldb::addr_t process_address, lldb::addr_t address, 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:46
void PutString(llvm::StringRef str)
Definition: Log.cpp:136
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
Definition: Materializer.h:147
std::shared_ptr< Dematerializer > DematerializerSP
Definition: Materializer.h:64
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
Definition: Materializer.h:150
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.
bool GetData(DataExtractor &data) const
An error handling class.
Definition: Status.h:44
void Clear()
Clear the object state.
Definition: Status.cpp:167
ValueType GetError() const
Access the error value.
Definition: Status.cpp:174
int SetErrorStringWithFormat(const char *format,...) __attribute__((format(printf
Set the current error string to a formatted error string.
Definition: Status.cpp:247
bool Fail() const
Test for error condition.
Definition: Status.cpp:181
const char * AsCString(const char *default_error_str="unknown error") const
Get the error string associated with the current error.
Definition: Status.cpp:130
void SetErrorString(llvm::StringRef err_str)
Set the current error string to err_str.
Definition: Status.cpp:233
bool Success() const
Test for success condition.
Definition: Status.cpp:279
llvm::StringRef GetString() const
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition: Stream.cpp:134
size_t PutChar(char ch)
Definition: Stream.cpp:131
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
Definition: lldb-defines.h:82
A class that represents a running process on the host machine.
Definition: SBAttachInfo.h:14
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
Definition: Log.h:314
void DumpHexBytes(Stream *s, const void *src, size_t src_len, uint32_t bytes_per_line, lldb::addr_t base_addr)
std::function< lldb::ValueObjectSP(ConstString, StackFrame *)> ValueObjectProviderTy
Functor that returns a ValueObjectSP for a variable given its name and the StackFrame of interest.
@ eAddressTypeLoad
Address is an address as in the current target inferior process.
std::shared_ptr< lldb_private::StackFrame > StackFrameSP
Definition: lldb-forward.h:412
std::shared_ptr< lldb_private::Thread > ThreadSP
Definition: lldb-forward.h:438
std::shared_ptr< lldb_private::ValueObject > ValueObjectSP
Definition: lldb-forward.h:472
std::shared_ptr< lldb_private::ExpressionVariable > ExpressionVariableSP
Definition: lldb-forward.h:343
uint64_t offset_t
Definition: lldb-types.h:83
std::shared_ptr< lldb_private::Process > ProcessSP
Definition: lldb-forward.h:381
std::shared_ptr< lldb_private::Variable > VariableSP
Definition: lldb-forward.h:474
std::shared_ptr< lldb_private::DataBuffer > DataBufferSP
Definition: lldb-forward.h:328
uint64_t addr_t
Definition: lldb-types.h:79
std::shared_ptr< lldb_private::Target > TargetSP
Definition: lldb-forward.h:436
std::shared_ptr< lldb_private::RegisterContext > RegisterContextSP
Definition: lldb-forward.h:386
Every register is described in detail including its name, alternate name (optional),...