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 %s to the target: %s",
137 m_persistent_variable_sp->GetName().AsCString(),
138 write_error.AsCString());
139 return;
140 }
141 }
142
144 Status deallocate_error;
145
146 map.Free((lldb::addr_t)m_persistent_variable_sp->m_live_sp->GetValue()
147 .GetScalar()
148 .ULongLong(),
149 deallocate_error);
150
151 m_persistent_variable_sp->m_live_sp.reset();
152
153 if (!deallocate_error.Success()) {
155 "couldn't deallocate memory for %s: %s",
156 m_persistent_variable_sp->GetName().GetCString(),
157 deallocate_error.AsCString());
158 }
159 }
160
162 lldb::addr_t process_address, Status &err) override {
164
165 const lldb::addr_t load_addr = process_address + m_offset;
166
167 LLDB_LOGF(log,
168 "EntityPersistentVariable::Materialize [address = 0x%" PRIx64
169 ", m_name = %s, m_flags = 0x%hx]",
170 (uint64_t)load_addr,
171 m_persistent_variable_sp->GetName().AsCString(),
172 m_persistent_variable_sp->m_flags);
173
174 if (m_persistent_variable_sp->m_flags &
176 MakeAllocation(map, err);
177 m_persistent_variable_sp->m_flags |=
179
180 if (!err.Success())
181 return;
182 }
183
184 if ((m_persistent_variable_sp->m_flags &
186 m_persistent_variable_sp->m_live_sp) ||
187 m_persistent_variable_sp->m_flags &
189 Status write_error;
190
192 load_addr,
193 m_persistent_variable_sp->m_live_sp->GetValue().GetScalar(),
194 map.GetAddressByteSize(), write_error);
195
196 if (!write_error.Success()) {
198 "couldn't write the location of %s to memory: %s",
199 m_persistent_variable_sp->GetName().AsCString(),
200 write_error.AsCString());
201 }
202 } else {
204 "no materialization happened for persistent variable %s",
205 m_persistent_variable_sp->GetName().AsCString());
206 return;
207 }
208 }
209
211 lldb::addr_t process_address, lldb::addr_t frame_top,
212 lldb::addr_t frame_bottom, Status &err) override {
214
215 const lldb::addr_t load_addr = process_address + m_offset;
216
217 LLDB_LOGF(log,
218 "EntityPersistentVariable::Dematerialize [address = 0x%" PRIx64
219 ", m_name = %s, m_flags = 0x%hx]",
220 (uint64_t)process_address + m_offset,
221 m_persistent_variable_sp->GetName().AsCString(),
222 m_persistent_variable_sp->m_flags);
223
224 if (m_delegate) {
225 m_delegate->DidDematerialize(m_persistent_variable_sp);
226 }
227
228 if ((m_persistent_variable_sp->m_flags &
230 (m_persistent_variable_sp->m_flags &
232 if (m_persistent_variable_sp->m_flags &
234 !m_persistent_variable_sp->m_live_sp) {
235 // If the reference comes from the program, then the
236 // ClangExpressionVariable's live variable data hasn't been set up yet.
237 // Do this now.
238
239 lldb::addr_t location;
240 Status read_error;
241
242 map.ReadPointerFromMemory(&location, load_addr, read_error);
243
244 if (!read_error.Success()) {
246 "couldn't read the address of program-allocated variable %s: %s",
247 m_persistent_variable_sp->GetName().GetCString(),
248 read_error.AsCString());
249 return;
250 }
251
254 m_persistent_variable_sp.get()->GetCompilerType(),
255 m_persistent_variable_sp->GetName(), location, eAddressTypeLoad,
256 llvm::expectedToOptional(m_persistent_variable_sp->GetByteSize())
257 .value_or(0));
258
259 if (frame_top != LLDB_INVALID_ADDRESS &&
260 frame_bottom != LLDB_INVALID_ADDRESS && location >= frame_bottom &&
261 location <= frame_top) {
262 // If the variable is resident in the stack frame created by the
263 // expression, then it cannot be relied upon to stay around. We
264 // treat it as needing reallocation.
265 m_persistent_variable_sp->m_flags |=
267 m_persistent_variable_sp->m_flags |=
269 m_persistent_variable_sp->m_flags |=
271 m_persistent_variable_sp->m_flags &=
272 ~ExpressionVariable::EVIsProgramReference;
273 }
274 }
275
276 lldb::addr_t mem = m_persistent_variable_sp->m_live_sp->GetValue()
277 .GetScalar()
278 .ULongLong();
279
280 if (!m_persistent_variable_sp->m_live_sp) {
282 "couldn't find the memory area used to store %s",
283 m_persistent_variable_sp->GetName().GetCString());
284 return;
285 }
286
287 if (m_persistent_variable_sp->m_live_sp->GetValue()
288 .GetValueAddressType() != eAddressTypeLoad) {
290 "the address of the memory area for %s is in an incorrect format",
291 m_persistent_variable_sp->GetName().GetCString());
292 return;
293 }
294
295 if (m_persistent_variable_sp->m_flags &
297 m_persistent_variable_sp->m_flags &
299 LLDB_LOGF(log, "Dematerializing %s from 0x%" PRIx64 " (size = %llu)",
300 m_persistent_variable_sp->GetName().GetCString(),
301 (uint64_t)mem,
302 (unsigned long long)llvm::expectedToOptional(
303 m_persistent_variable_sp->GetByteSize())
304 .value_or(0));
305
306 // Read the contents of the spare memory area
307
308 m_persistent_variable_sp->ValueUpdated();
309
310 Status read_error;
311
312 map.ReadMemory(
313 m_persistent_variable_sp->GetValueBytes(), mem,
314 llvm::expectedToOptional(m_persistent_variable_sp->GetByteSize())
315 .value_or(0),
316 read_error);
317
318 if (!read_error.Success()) {
320 "couldn't read the contents of %s from memory: %s",
321 m_persistent_variable_sp->GetName().GetCString(),
322 read_error.AsCString());
323 return;
324 }
325
326 m_persistent_variable_sp->m_flags &=
327 ~ExpressionVariable::EVNeedsFreezeDry;
328 }
329 } else {
331 "no dematerialization happened for persistent variable %s",
332 m_persistent_variable_sp->GetName().AsCString());
333 return;
334 }
335
336 if (m_persistent_variable_sp->m_flags &
338 !(m_persistent_variable_sp->m_flags &
340 DestroyAllocation(map, err);
341 if (!err.Success())
342 return;
343 }
344 }
345
346 void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
347 Log *log) override {
348 StreamString dump_stream;
349
350 Status err;
351
352 const lldb::addr_t load_addr = process_address + m_offset;
353
354 dump_stream.Printf("0x%" PRIx64 ": EntityPersistentVariable (%s)\n",
355 load_addr,
356 m_persistent_variable_sp->GetName().AsCString());
357
358 {
359 dump_stream.Printf("Pointer:\n");
360
361 DataBufferHeap data(m_size, 0);
362
363 map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
364
365 if (!err.Success()) {
366 dump_stream.Printf(" <could not be read>\n");
367 } else {
368 DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
369 load_addr);
370
371 dump_stream.PutChar('\n');
372 }
373 }
374
375 {
376 dump_stream.Printf("Target:\n");
377
378 lldb::addr_t target_address;
379
380 map.ReadPointerFromMemory(&target_address, load_addr, err);
381
382 if (!err.Success()) {
383 dump_stream.Printf(" <could not be read>\n");
384 } else {
385 DataBufferHeap data(
386 llvm::expectedToOptional(m_persistent_variable_sp->GetByteSize())
387 .value_or(0),
388 0);
389
390 map.ReadMemory(
391 data.GetBytes(), target_address,
392 llvm::expectedToOptional(m_persistent_variable_sp->GetByteSize())
393 .value_or(0),
394 err);
395
396 if (!err.Success()) {
397 dump_stream.Printf(" <could not be read>\n");
398 } else {
399 DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
400 target_address);
401
402 dump_stream.PutChar('\n');
403 }
404 }
405 }
406
407 log->PutString(dump_stream.GetString());
408 }
409
410 void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {}
411
412private:
415};
416
418 lldb::ExpressionVariableSP &persistent_variable_sp,
419 PersistentVariableDelegate *delegate, Status &err) {
420 EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
421 *iter = std::make_unique<EntityPersistentVariable>(persistent_variable_sp,
422 delegate);
423 uint32_t ret = AddStructMember(**iter);
424 (*iter)->SetOffset(ret);
425 return ret;
426}
427
428/// Base class for materialization of Variables and ValueObjects.
429///
430/// Subclasses specify how to obtain the Value which is to be
431/// materialized.
433public:
434 virtual ~EntityVariableBase() = default;
435
437 // Hard-coding to maximum size of a pointer since all variables are
438 // materialized by reference
441 }
442
444 lldb::addr_t process_address, Status &err) override {
446
447 const lldb::addr_t load_addr = process_address + m_offset;
448 LLDB_LOGF(log,
449 "EntityVariable::Materialize [address = 0x%" PRIx64
450 ", m_variable_sp = %s]",
451 (uint64_t)load_addr, GetName().GetCString());
452
453 ExecutionContextScope *scope = frame_sp.get();
454
455 if (!scope)
456 scope = map.GetBestExecutionContextScope();
457
458 lldb::ValueObjectSP valobj_sp = SetupValueObject(scope);
459
460 if (!valobj_sp) {
462 "couldn't get a value object for variable %s", GetName().AsCString());
463 return;
464 }
465
466 Status valobj_error = valobj_sp->GetError().Clone();
467
468 if (valobj_error.Fail()) {
470 "couldn't get the value of variable %s: %s", GetName().AsCString(),
471 valobj_error.AsCString());
472 return;
473 }
474
475 if (m_is_reference) {
476 DataExtractor valobj_extractor;
477 Status extract_error;
478 valobj_sp->GetData(valobj_extractor, extract_error);
479
480 if (!extract_error.Success()) {
482 "couldn't read contents of reference variable %s: %s",
483 GetName().AsCString(), extract_error.AsCString());
484 return;
485 }
486
487 lldb::offset_t offset = 0;
488 lldb::addr_t reference_addr = valobj_extractor.GetAddress(&offset);
489
490 Status write_error;
491 map.WritePointerToMemory(load_addr, reference_addr, write_error);
492
493 if (!write_error.Success()) {
495 "couldn't write the contents of reference "
496 "variable %s to memory: %s",
497 GetName().AsCString(), write_error.AsCString());
498 return;
499 }
500 } else {
501 lldb::addr_t addr_of_valobj =
502 valobj_sp->GetAddressOf(/*scalar_is_load_address=*/false).address;
503 if (addr_of_valobj != LLDB_INVALID_ADDRESS) {
504 Status write_error;
505 map.WritePointerToMemory(load_addr, addr_of_valobj, write_error);
506
507 if (!write_error.Success()) {
509 "couldn't write the address of variable %s to memory: %s",
510 GetName().AsCString(), write_error.AsCString());
511 return;
512 }
513 } else {
514 DataExtractor data;
515 Status extract_error;
516 valobj_sp->GetData(data, extract_error);
517 if (!extract_error.Success()) {
519 "couldn't get the value of %s: %s", GetName().AsCString(),
520 extract_error.AsCString());
521 return;
522 }
523
526 "trying to create a temporary region for %s but one exists",
527 GetName().AsCString());
528 return;
529 }
530
531 if (data.GetByteSize() <
532 llvm::expectedToOptional(GetByteSize(scope)).value_or(0)) {
533 if (data.GetByteSize() == 0 && !LocationExpressionIsValid()) {
535 "the variable '%s' has no location, "
536 "it may have been optimized out",
537 GetName().AsCString());
538 } else {
540 "size of variable %s (%" PRIu64
541 ") is larger than the ValueObject's size (%" PRIu64 ")",
542 GetName().AsCString(),
543 llvm::expectedToOptional(GetByteSize(scope)).value_or(0),
544 data.GetByteSize());
545 }
546 return;
547 }
548
549 std::optional<size_t> opt_bit_align = GetTypeBitAlign(scope);
550 if (!opt_bit_align) {
552 "can't get the type alignment for %s", GetName().AsCString());
553 return;
554 }
555
556 size_t byte_align = (*opt_bit_align + 7) / 8;
557
558 const bool zero_memory = false;
559 if (auto address_or_error = map.Malloc(
560 data.GetByteSize(), byte_align,
561 lldb::ePermissionsReadable | lldb::ePermissionsWritable,
563 m_temporary_allocation = *address_or_error;
564 } else {
566 "couldn't allocate a temporary region for %s: %s",
567 GetName().AsCString(),
568 toString(address_or_error.takeError()).c_str());
569 return;
570 }
571
573
574 m_original_data = std::make_shared<DataBufferHeap>(data.GetDataStart(),
575 data.GetByteSize());
576
577 Status write_error;
578
580 data.GetByteSize(), write_error);
581
582 if (!write_error.Success()) {
584 "couldn't write to the temporary region for %s: %s",
585 GetName().AsCString(), write_error.AsCString());
586 return;
587 }
588
589 Status pointer_write_error;
590
592 pointer_write_error);
593
594 if (!pointer_write_error.Success()) {
596 "couldn't write the address of the temporary region for %s: %s",
597 GetName().AsCString(), pointer_write_error.AsCString());
598 }
599 }
600 }
601 }
602
604 lldb::addr_t process_address, lldb::addr_t frame_top,
605 lldb::addr_t frame_bottom, Status &err) override {
607
608 const lldb::addr_t load_addr = process_address + m_offset;
609 LLDB_LOGF(log,
610 "EntityVariable::Dematerialize [address = 0x%" PRIx64
611 ", m_variable_sp = %s]",
612 (uint64_t)load_addr, GetName().AsCString());
613
615 ExecutionContextScope *scope = frame_sp.get();
616
617 if (!scope)
618 scope = map.GetBestExecutionContextScope();
619
620 lldb::ValueObjectSP valobj_sp = SetupValueObject(scope);
621
622 if (!valobj_sp) {
624 "couldn't get a value object for variable %s",
625 GetName().AsCString());
626 return;
627 }
628
630
631 Status extract_error;
632
633 map.GetMemoryData(
635 llvm::expectedToOptional(valobj_sp->GetByteSize()).value_or(0),
636 extract_error);
637
638 if (!extract_error.Success()) {
640 "couldn't get the data for variable %s", GetName().AsCString());
641 return;
642 }
643
644 bool actually_write = true;
645
646 if (m_original_data) {
647 if ((data.GetByteSize() == m_original_data->GetByteSize()) &&
648 !memcmp(m_original_data->GetBytes(), data.GetDataStart(),
649 data.GetByteSize())) {
650 actually_write = false;
651 }
652 }
653
654 Status set_error;
655
656 if (actually_write) {
657 valobj_sp->SetData(data, set_error);
658
659 if (!set_error.Success()) {
661 "couldn't write the new contents of %s back into the variable",
662 GetName().AsCString());
663 return;
664 }
665 }
666
667 Status free_error;
668
669 map.Free(m_temporary_allocation, free_error);
670
671 if (!free_error.Success()) {
673 "couldn't free the temporary region for %s: %s",
674 GetName().AsCString(), free_error.AsCString());
675 return;
676 }
677
678 m_original_data.reset();
681 }
682 }
683
684 void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
685 Log *log) override {
686 StreamString dump_stream;
687
688 const lldb::addr_t load_addr = process_address + m_offset;
689 dump_stream.Printf("0x%" PRIx64 ": EntityVariable\n", load_addr);
690
691 Status err;
692
694
695 {
696 dump_stream.Printf("Pointer:\n");
697
698 DataBufferHeap data(m_size, 0);
699
700 map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
701
702 if (!err.Success()) {
703 dump_stream.Printf(" <could not be read>\n");
704 } else {
705 DataExtractor extractor(data.GetBytes(), data.GetByteSize(),
706 map.GetByteOrder(), map.GetAddressByteSize());
707
708 DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
709 load_addr);
710
711 lldb::offset_t offset = 0;
712
713 ptr = extractor.GetAddress(&offset);
714
715 dump_stream.PutChar('\n');
716 }
717 }
718
720 dump_stream.Printf("Points to process memory:\n");
721 } else {
722 dump_stream.Printf("Temporary allocation:\n");
723 }
724
725 if (ptr == LLDB_INVALID_ADDRESS) {
726 dump_stream.Printf(" <could not be be found>\n");
727 } else {
729
732
733 if (!err.Success()) {
734 dump_stream.Printf(" <could not be read>\n");
735 } else {
736 DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
737 load_addr);
738
739 dump_stream.PutChar('\n');
740 }
741 }
742
743 log->PutString(dump_stream.GetString());
744 }
745
746 void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {
748 Status free_error;
749
750 map.Free(m_temporary_allocation, free_error);
751
754 }
755 }
756
757private:
758 virtual ConstString GetName() const = 0;
759
760 /// Creates and returns ValueObject tied to this variable
761 /// and prepares Entity for materialization.
762 ///
763 /// Called each time the Materializer (de)materializes a
764 /// variable. We re-create the ValueObject based on the
765 /// current ExecutionContextScope since clients such as
766 /// conditional breakpoints may materialize the same
767 /// EntityVariable multiple times with different frames.
768 ///
769 /// Each subsequent use of the EntityVariableBase interface
770 /// will query the newly created ValueObject until this
771 /// function is called again.
772 virtual lldb::ValueObjectSP
774
775 /// Returns size in bytes of the type associated with this variable
776 ///
777 /// \returns On success, returns byte size of the type associated
778 /// with this variable. Returns std::nullopt otherwise.
779 virtual llvm::Expected<uint64_t>
781
782 /// Returns 'true' if the location expression associated with this variable
783 /// is valid.
784 virtual bool LocationExpressionIsValid() const = 0;
785
786 /// Returns alignment of the type associated with this variable in bits.
787 ///
788 /// \returns On success, returns alignment in bits for the type associated
789 /// with this variable. Returns std::nullopt otherwise.
790 virtual std::optional<size_t>
792
793protected:
794 bool m_is_reference = false;
798};
799
800/// Represents an Entity constructed from a VariableSP.
801///
802/// This class is used for materialization of variables for which
803/// the user has a VariableSP on hand. The ValueObject is then
804/// derived from the associated DWARF location expression when needed
805/// by the Materializer.
807public:
808 EntityVariable(lldb::VariableSP &variable_sp) : m_variable_sp(variable_sp) {
810 m_variable_sp->GetType()->GetForwardCompilerType().IsReferenceType();
811 }
812
813 ConstString GetName() const override { return m_variable_sp->GetName(); }
814
816 assert(m_variable_sp != nullptr);
818 }
819
820 llvm::Expected<uint64_t>
821 GetByteSize(ExecutionContextScope *scope) const override {
822 return m_variable_sp->GetType()->GetByteSize(scope);
823 }
824
825 bool LocationExpressionIsValid() const override {
826 return m_variable_sp->LocationExpressionList().IsValid();
827 }
828
829 std::optional<size_t>
830 GetTypeBitAlign(ExecutionContextScope *scope) const override {
831 return m_variable_sp->GetType()->GetLayoutCompilerType().GetTypeBitAlign(
832 scope);
833 }
834
835private:
836 lldb::VariableSP m_variable_sp; ///< Variable that this entity is based on.
837};
838
839/// Represents an Entity constructed from a VariableSP.
840///
841/// This class is used for materialization of variables for
842/// which the user does not have a VariableSP available (e.g.,
843/// when materializing ivars).
845public:
847 : m_name(name), m_valobj_provider(std::move(provider)) {
848 assert(m_valobj_provider);
849 }
850
851 ConstString GetName() const override { return m_name; }
852
856
857 if (m_valobj_sp)
858 m_is_reference = m_valobj_sp->GetCompilerType().IsReferenceType();
859
860 return m_valobj_sp;
861 }
862
863 llvm::Expected<uint64_t>
864 GetByteSize(ExecutionContextScope *scope) const override {
865 if (m_valobj_sp)
866 return m_valobj_sp->GetCompilerType().GetByteSize(scope);
867
868 return llvm::createStringError("no value object");
869 }
870
871 bool LocationExpressionIsValid() const override {
872 if (m_valobj_sp)
873 return m_valobj_sp->GetError().Success();
874
875 return false;
876 }
877
878 std::optional<size_t>
879 GetTypeBitAlign(ExecutionContextScope *scope) const override {
880 if (m_valobj_sp)
881 return m_valobj_sp->GetCompilerType().GetTypeBitAlign(scope);
882
883 return {};
884 }
885
886private:
890};
891
893 EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
894 *iter = std::make_unique<EntityVariable>(variable_sp);
895 uint32_t ret = AddStructMember(**iter);
896 (*iter)->SetOffset(ret);
897 return ret;
898}
899
901 ValueObjectProviderTy valobj_provider,
902 Status &err) {
903 assert(valobj_provider);
904 EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
905 *iter = std::make_unique<EntityValueObject>(name, std::move(valobj_provider));
906 uint32_t ret = AddStructMember(**iter);
907 (*iter)->SetOffset(ret);
908 return ret;
909}
910
912public:
913 EntityResultVariable(const CompilerType &type, bool is_program_reference,
914 bool keep_in_memory,
916 : Entity(), m_type(type), m_is_program_reference(is_program_reference),
917 m_keep_in_memory(keep_in_memory), m_delegate(delegate) {
918 // Hard-coding to maximum size of a pointer since all results are
919 // materialized by reference
922 }
923
925 lldb::addr_t process_address, Status &err) override {
929 "Trying to create a temporary region for the result "
930 "but one exists");
931 return;
932 }
933
934 const lldb::addr_t load_addr = process_address + m_offset;
935
936 ExecutionContextScope *exe_scope = frame_sp.get();
937 if (!exe_scope)
938 exe_scope = map.GetBestExecutionContextScope();
939
940 auto byte_size_or_err = m_type.GetByteSize(exe_scope);
941 if (!byte_size_or_err) {
942 err = Status::FromError(byte_size_or_err.takeError());
943 return;
944 }
945 auto byte_size = *byte_size_or_err;
946
947 std::optional<size_t> opt_bit_align = m_type.GetTypeBitAlign(exe_scope);
948 if (!opt_bit_align) {
950 "can't get the alignment of type \"%s\"",
951 m_type.GetTypeName().AsCString());
952 return;
953 }
954
955 size_t byte_align = (*opt_bit_align + 7) / 8;
956
957 const bool zero_memory = true;
958 if (auto address_or_error = map.Malloc(
959 byte_size, byte_align,
960 lldb::ePermissionsReadable | lldb::ePermissionsWritable,
962 m_temporary_allocation = *address_or_error;
963 } else {
965 "couldn't allocate a temporary region for the result: %s",
966 toString(address_or_error.takeError()).c_str());
967 return;
968 }
969
970 m_temporary_allocation_size = byte_size;
971
972 Status pointer_write_error;
973
975 pointer_write_error);
976
977 if (!pointer_write_error.Success()) {
979 "couldn't write the address of the "
980 "temporary region for the result: %s",
981 pointer_write_error.AsCString());
982 }
983 }
984 }
985
987 lldb::addr_t process_address, lldb::addr_t frame_top,
988 lldb::addr_t frame_bottom, Status &err) override {
989 err.Clear();
990
991 ExecutionContextScope *exe_scope = frame_sp.get();
992 if (!exe_scope)
993 exe_scope = map.GetBestExecutionContextScope();
994
995 if (!exe_scope) {
997 "Couldn't dematerialize a result variable: invalid "
998 "execution context scope");
999 return;
1000 }
1001
1002 lldb::addr_t address;
1003 Status read_error;
1004 const lldb::addr_t load_addr = process_address + m_offset;
1005
1006 map.ReadPointerFromMemory(&address, load_addr, read_error);
1007
1008 if (!read_error.Success()) {
1010 "Couldn't dematerialize a result variable: couldn't "
1011 "read its address");
1012 return;
1013 }
1014
1015 lldb::TargetSP target_sp = exe_scope->CalculateTarget();
1016
1017 if (!target_sp) {
1019 "Couldn't dematerialize a result variable: no target");
1020 return;
1021 }
1022
1023 auto type_system_or_err =
1024 target_sp->GetScratchTypeSystemForLanguage(m_type.GetMinimumLanguage());
1025
1026 if (auto error = type_system_or_err.takeError()) {
1028 "Couldn't dematerialize a result variable: "
1029 "couldn't get the corresponding type "
1030 "system: %s",
1031 llvm::toString(std::move(error)).c_str());
1032 return;
1033 }
1034 auto ts = *type_system_or_err;
1035 if (!ts) {
1037 "Couldn't dematerialize a result variable: "
1038 "couldn't corresponding type system is "
1039 "no longer live.");
1040 return;
1041 }
1042 PersistentExpressionState *persistent_state =
1043 ts->GetPersistentExpressionState();
1044
1045 if (!persistent_state) {
1047 "Couldn't dematerialize a result variable: "
1048 "corresponding type system doesn't handle persistent "
1049 "variables");
1050 return;
1051 }
1052
1053 ConstString name = m_delegate
1054 ? m_delegate->GetName()
1055 : persistent_state->GetNextPersistentVariableName();
1056
1058 exe_scope, name, m_type, map.GetByteOrder(), map.GetAddressByteSize());
1059
1060 if (!ret) {
1062 "couldn't dematerialize a result variable: "
1063 "failed to make persistent variable %s",
1064 name.AsCString());
1065 return;
1066 }
1067
1068 lldb::ProcessSP process_sp =
1070
1071 if (m_delegate) {
1072 m_delegate->DidDematerialize(ret);
1073 }
1074
1075 bool can_persist = m_is_program_reference &&
1076 !(address >= frame_bottom && address < frame_top);
1077
1078 if (can_persist && m_keep_in_memory) {
1079 ret->m_live_sp = ValueObjectConstResult::Create(exe_scope, m_type, name,
1080 address, eAddressTypeLoad,
1081 map.GetAddressByteSize());
1082 }
1083
1084 ret->ValueUpdated();
1085
1086 const size_t pvar_byte_size =
1087 llvm::expectedToOptional(ret->GetByteSize()).value_or(0);
1088 uint8_t *pvar_data = ret->GetValueBytes();
1089
1090 map.ReadMemory(pvar_data, address, pvar_byte_size, read_error);
1091
1092 if (!read_error.Success()) {
1094 "Couldn't dematerialize a result variable: couldn't read its memory");
1095 return;
1096 }
1097
1098 if (!can_persist || !m_keep_in_memory) {
1100
1102 Status free_error;
1103 map.Free(m_temporary_allocation, free_error);
1104 }
1105 } else {
1106 ret->m_flags |= m_is_program_reference
1109 }
1110
1113 }
1114
1115 void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
1116 Log *log) override {
1117 StreamString dump_stream;
1118
1119 const lldb::addr_t load_addr = process_address + m_offset;
1120
1121 dump_stream.Printf("0x%" PRIx64 ": EntityResultVariable\n", load_addr);
1122
1123 Status err;
1124
1126
1127 {
1128 dump_stream.Printf("Pointer:\n");
1129
1130 DataBufferHeap data(m_size, 0);
1131
1132 map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
1133
1134 if (!err.Success()) {
1135 dump_stream.Printf(" <could not be read>\n");
1136 } else {
1137 DataExtractor extractor(data.GetBytes(), data.GetByteSize(),
1138 map.GetByteOrder(), map.GetAddressByteSize());
1139
1140 DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
1141 load_addr);
1142
1143 lldb::offset_t offset = 0;
1144
1145 ptr = extractor.GetAddress(&offset);
1146
1147 dump_stream.PutChar('\n');
1148 }
1149 }
1150
1152 dump_stream.Printf("Points to process memory:\n");
1153 } else {
1154 dump_stream.Printf("Temporary allocation:\n");
1155 }
1156
1157 if (ptr == LLDB_INVALID_ADDRESS) {
1158 dump_stream.Printf(" <could not be be found>\n");
1159 } else {
1161
1164
1165 if (!err.Success()) {
1166 dump_stream.Printf(" <could not be read>\n");
1167 } else {
1168 DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
1169 load_addr);
1170
1171 dump_stream.PutChar('\n');
1172 }
1173 }
1174
1175 log->PutString(dump_stream.GetString());
1176 }
1177
1178 void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {
1180 Status free_error;
1181
1182 map.Free(m_temporary_allocation, free_error);
1183 }
1184
1187 }
1188
1189private:
1191 /// This is used both to control whether this result entity can (and should)
1192 /// track the value in inferior memory, as well as to control whether LLDB
1193 /// needs to allocate memory for the variable during materialization.
1196
1200};
1201
1203 bool is_program_reference,
1204 bool keep_in_memory,
1206 Status &err) {
1207 EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
1208 *iter = std::make_unique<EntityResultVariable>(type, is_program_reference,
1209 keep_in_memory, delegate);
1210 uint32_t ret = AddStructMember(**iter);
1211 (*iter)->SetOffset(ret);
1212 return ret;
1213}
1214
1216public:
1217 EntitySymbol(const Symbol &symbol) : Entity(), m_symbol(symbol) {
1218 // Hard-coding to maximum size of a symbol
1221 }
1222
1224 lldb::addr_t process_address, Status &err) override {
1226
1227 const lldb::addr_t load_addr = process_address + m_offset;
1228
1229 LLDB_LOGF(log,
1230 "EntitySymbol::Materialize [address = 0x%" PRIx64
1231 ", m_symbol = %s]",
1232 (uint64_t)load_addr, m_symbol.GetName().AsCString());
1233
1234 const Address sym_address = m_symbol.GetAddress();
1235
1236 ExecutionContextScope *exe_scope = frame_sp.get();
1237 if (!exe_scope)
1238 exe_scope = map.GetBestExecutionContextScope();
1239
1240 lldb::TargetSP target_sp;
1241
1242 if (exe_scope)
1243 target_sp = map.GetBestExecutionContextScope()->CalculateTarget();
1244
1245 if (!target_sp) {
1247 "couldn't resolve symbol %s because there is no target",
1248 m_symbol.GetName().AsCString());
1249 return;
1250 }
1251
1252 lldb::addr_t resolved_address = sym_address.GetLoadAddress(target_sp.get());
1253
1254 if (resolved_address == LLDB_INVALID_ADDRESS)
1255 resolved_address = sym_address.GetFileAddress();
1256
1257 Status pointer_write_error;
1258
1259 map.WritePointerToMemory(load_addr, resolved_address, pointer_write_error);
1260
1261 if (!pointer_write_error.Success()) {
1263 "couldn't write the address of symbol %s: %s",
1264 m_symbol.GetName().AsCString(), pointer_write_error.AsCString());
1265 return;
1266 }
1267 }
1268
1270 lldb::addr_t process_address, lldb::addr_t frame_top,
1271 lldb::addr_t frame_bottom, Status &err) override {
1273
1274 const lldb::addr_t load_addr = process_address + m_offset;
1275
1276 LLDB_LOGF(log,
1277 "EntitySymbol::Dematerialize [address = 0x%" PRIx64
1278 ", m_symbol = %s]",
1279 (uint64_t)load_addr, m_symbol.GetName().AsCString());
1280
1281 // no work needs to be done
1282 }
1283
1284 void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
1285 Log *log) override {
1286 StreamString dump_stream;
1287
1288 Status err;
1289
1290 const lldb::addr_t load_addr = process_address + m_offset;
1291
1292 dump_stream.Printf("0x%" PRIx64 ": EntitySymbol (%s)\n", load_addr,
1293 m_symbol.GetName().AsCString());
1294
1295 {
1296 dump_stream.Printf("Pointer:\n");
1297
1298 DataBufferHeap data(m_size, 0);
1299
1300 map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
1301
1302 if (!err.Success()) {
1303 dump_stream.Printf(" <could not be read>\n");
1304 } else {
1305 DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
1306 load_addr);
1307
1308 dump_stream.PutChar('\n');
1309 }
1310 }
1311
1312 log->PutString(dump_stream.GetString());
1313 }
1314
1315 void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {}
1316
1317private:
1319};
1320
1321uint32_t Materializer::AddSymbol(const Symbol &symbol_sp, Status &err) {
1322 EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
1323 *iter = std::make_unique<EntitySymbol>(symbol_sp);
1324 uint32_t ret = AddStructMember(**iter);
1325 (*iter)->SetOffset(ret);
1326 return ret;
1327}
1328
1330public:
1331 EntityRegister(const RegisterInfo &register_info)
1332 : Entity(), m_register_info(register_info) {
1333 // Hard-coding alignment conservatively
1334 m_size = m_register_info.byte_size;
1335 m_alignment = m_register_info.byte_size;
1336 }
1337
1339 lldb::addr_t process_address, Status &err) override {
1341
1342 const lldb::addr_t load_addr = process_address + m_offset;
1343
1344 LLDB_LOGF(log,
1345 "EntityRegister::Materialize [address = 0x%" PRIx64
1346 ", m_register_info = %s]",
1347 (uint64_t)load_addr, m_register_info.name);
1348
1349 RegisterValue reg_value;
1350
1351 if (!frame_sp.get()) {
1353 "couldn't materialize register %s without a stack frame",
1354 m_register_info.name);
1355 return;
1356 }
1357
1358 lldb::RegisterContextSP reg_context_sp = frame_sp->GetRegisterContext();
1359
1360 if (!reg_context_sp->ReadRegister(&m_register_info, reg_value)) {
1362 "couldn't read the value of register %s", m_register_info.name);
1363 return;
1364 }
1365
1366 if (reg_value.GetByteSize() != m_register_info.byte_size) {
1368 "data for register %s had size %llu but we expected %llu",
1369 m_register_info.name, (unsigned long long)reg_value.GetByteSize(),
1370 (unsigned long long)m_register_info.byte_size);
1371 return;
1372 }
1373
1374 lldb_private::DataBufferHeap buf(reg_value.GetByteSize(), 0);
1375 reg_value.GetAsMemoryData(m_register_info, buf.GetBytes(),
1376 buf.GetByteSize(), map.GetByteOrder(), err);
1377 if (!err.Success())
1378 return;
1379
1380 m_register_contents = std::make_shared<DataBufferHeap>(buf);
1381
1382 Status write_error;
1383
1384 map.WriteMemory(load_addr, buf.GetBytes(), reg_value.GetByteSize(),
1385 write_error);
1386
1387 if (!write_error.Success()) {
1389 "couldn't write the contents of register %s: %s",
1390 m_register_info.name, write_error.AsCString());
1391 return;
1392 }
1393 }
1394
1396 lldb::addr_t process_address, lldb::addr_t frame_top,
1397 lldb::addr_t frame_bottom, Status &err) override {
1399
1400 const lldb::addr_t load_addr = process_address + m_offset;
1401
1402 LLDB_LOGF(log,
1403 "EntityRegister::Dematerialize [address = 0x%" PRIx64
1404 ", m_register_info = %s]",
1405 (uint64_t)load_addr, m_register_info.name);
1406
1407 Status extract_error;
1408
1409 DataExtractor register_data;
1410
1411 if (!frame_sp.get()) {
1413 "couldn't dematerialize register %s without a stack frame",
1414 m_register_info.name);
1415 return;
1416 }
1417
1418 lldb::RegisterContextSP reg_context_sp = frame_sp->GetRegisterContext();
1419
1420 map.GetMemoryData(register_data, load_addr, m_register_info.byte_size,
1421 extract_error);
1422
1423 if (!extract_error.Success()) {
1425 "couldn't get the data for register %s: %s", m_register_info.name,
1426 extract_error.AsCString());
1427 return;
1428 }
1429
1430 if (!memcmp(register_data.GetDataStart(), m_register_contents->GetBytes(),
1431 register_data.GetByteSize())) {
1432 // No write required, and in particular we avoid errors if the register
1433 // wasn't writable
1434
1435 m_register_contents.reset();
1436 return;
1437 }
1438
1439 m_register_contents.reset();
1440
1441 RegisterValue register_value(register_data.GetData(),
1442 register_data.GetByteOrder());
1443
1444 if (!reg_context_sp->WriteRegister(&m_register_info, register_value)) {
1446 "couldn't write the value of register %s", m_register_info.name);
1447 return;
1448 }
1449 }
1450
1451 void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
1452 Log *log) override {
1453 StreamString dump_stream;
1454
1455 Status err;
1456
1457 const lldb::addr_t load_addr = process_address + m_offset;
1458
1459 dump_stream.Printf("0x%" PRIx64 ": EntityRegister (%s)\n", load_addr,
1460 m_register_info.name);
1461
1462 {
1463 dump_stream.Printf("Value:\n");
1464
1465 DataBufferHeap data(m_size, 0);
1466
1467 map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
1468
1469 if (!err.Success()) {
1470 dump_stream.Printf(" <could not be read>\n");
1471 } else {
1472 DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
1473 load_addr);
1474
1475 dump_stream.PutChar('\n');
1476 }
1477 }
1478
1479 log->PutString(dump_stream.GetString());
1480 }
1481
1482 void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {}
1483
1484private:
1487};
1488
1489uint32_t Materializer::AddRegister(const RegisterInfo &register_info,
1490 Status &err) {
1491 EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
1492 *iter = std::make_unique<EntityRegister>(register_info);
1493 uint32_t ret = AddStructMember(**iter);
1494 (*iter)->SetOffset(ret);
1495 return ret;
1496}
1497
1499 DematerializerSP dematerializer_sp = m_dematerializer_wp.lock();
1500
1501 if (dematerializer_sp)
1502 dematerializer_sp->Wipe();
1503}
1504
1507 lldb::addr_t process_address, Status &error) {
1508 ExecutionContextScope *exe_scope = frame_sp.get();
1509 if (!exe_scope)
1510 exe_scope = map.GetBestExecutionContextScope();
1511
1512 DematerializerSP dematerializer_sp = m_dematerializer_wp.lock();
1513
1514 if (dematerializer_sp) {
1515 error =
1516 Status::FromErrorString("Couldn't materialize: already materialized");
1517 }
1518
1519 DematerializerSP ret(
1520 new Dematerializer(*this, frame_sp, map, process_address));
1521
1522 if (!exe_scope) {
1523 error =
1524 Status::FromErrorString("Couldn't materialize: target doesn't exist");
1525 }
1526
1527 for (EntityUP &entity_up : m_entities) {
1528 entity_up->Materialize(frame_sp, map, process_address, error);
1529
1530 if (!error.Success())
1531 return DematerializerSP();
1532 }
1533
1534 if (Log *log = GetLog(LLDBLog::Expressions)) {
1535 LLDB_LOGF(
1536 log,
1537 "Materializer::Materialize (frame_sp = %p, process_address = 0x%" PRIx64
1538 ") materialized:",
1539 static_cast<void *>(frame_sp.get()), process_address);
1540 for (EntityUP &entity_up : m_entities)
1541 entity_up->DumpToLog(map, process_address, log);
1542 }
1543
1544 m_dematerializer_wp = ret;
1545
1546 return ret;
1547}
1548
1550 lldb::addr_t frame_bottom,
1551 lldb::addr_t frame_top) {
1552 lldb::StackFrameSP frame_sp;
1553
1554 lldb::ThreadSP thread_sp = m_thread_wp.lock();
1555 if (thread_sp)
1556 frame_sp = thread_sp->GetFrameWithStackID(m_stack_id);
1557
1558 ExecutionContextScope *exe_scope = frame_sp.get();
1559 if (!exe_scope)
1560 exe_scope = m_map->GetBestExecutionContextScope();
1561
1562 if (!IsValid()) {
1564 "Couldn't dematerialize: invalid dematerializer");
1565 }
1566
1567 if (!exe_scope) {
1568 error = Status::FromErrorString("Couldn't dematerialize: target is gone");
1569 } else {
1570 if (Log *log = GetLog(LLDBLog::Expressions)) {
1571 LLDB_LOGF(log,
1572 "Materializer::Dematerialize (frame_sp = %p, process_address "
1573 "= 0x%" PRIx64 ") about to dematerialize:",
1574 static_cast<void *>(frame_sp.get()), m_process_address);
1575 for (EntityUP &entity_up : m_materializer->m_entities)
1576 entity_up->DumpToLog(*m_map, m_process_address, log);
1577 }
1578
1579 for (EntityUP &entity_up : m_materializer->m_entities) {
1580 entity_up->Dematerialize(frame_sp, *m_map, m_process_address, frame_top,
1581 frame_bottom, error);
1582
1583 if (!error.Success())
1584 break;
1585 }
1586 }
1587
1588 Wipe();
1589}
1590
1592 if (!IsValid())
1593 return;
1594
1595 for (EntityUP &entity_up : m_materializer->m_entities) {
1596 entity_up->Wipe(*m_map, m_process_address);
1597 }
1598
1599 m_materializer = nullptr;
1600 m_map = nullptr;
1602}
1603
1605 default;
1607 default;
static llvm::raw_ostream & error(Stream &strm)
#define LLDB_LOGF(log,...)
Definition Log.h:383
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
const char * AsCString(const char *value_if_empty=nullptr) const
Get the string value as a C string.
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 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
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
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:332
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),...