xref: /llvm-project/lldb/source/Expression/Materializer.cpp (revision b852fb1ec5fa15f0b913cc4988cbd09239b19904)
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 
9 #include "lldb/Expression/Materializer.h"
10 #include "lldb/Core/DumpDataExtractor.h"
11 #include "lldb/Expression/ExpressionVariable.h"
12 #include "lldb/Symbol/Symbol.h"
13 #include "lldb/Symbol/Type.h"
14 #include "lldb/Symbol/Variable.h"
15 #include "lldb/Target/ExecutionContext.h"
16 #include "lldb/Target/RegisterContext.h"
17 #include "lldb/Target/StackFrame.h"
18 #include "lldb/Target/Target.h"
19 #include "lldb/Target/Thread.h"
20 #include "lldb/Utility/LLDBLog.h"
21 #include "lldb/Utility/Log.h"
22 #include "lldb/Utility/RegisterValue.h"
23 #include "lldb/ValueObject/ValueObjectConstResult.h"
24 #include "lldb/ValueObject/ValueObjectVariable.h"
25 #include "lldb/lldb-forward.h"
26 
27 #include <memory>
28 #include <optional>
29 
30 using 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.
37 static constexpr uint32_t g_default_var_alignment = 8;
38 static constexpr uint32_t g_default_var_byte_size = 8;
39 
40 uint32_t Materializer::AddStructMember(Entity &entity) {
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 
59 class EntityPersistentVariable : public Materializer::Entity {
60 public:
61   EntityPersistentVariable(lldb::ExpressionVariableSP &persistent_variable_sp,
62                            Materializer::PersistentVariableDelegate *delegate)
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
67     m_size = g_default_var_byte_size;
68     m_alignment = g_default_var_alignment;
69   }
70 
71   void MakeAllocation(IRMemoryMap &map, Status &err) {
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()) {
86       err = Status::FromErrorStringWithFormat(
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(
100         map.GetBestExecutionContextScope(),
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 &
108         ExpressionVariable::EVKeepInTarget) {
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()) {
124       err = Status::FromErrorStringWithFormat(
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 
132   void DestroyAllocation(IRMemoryMap &map, Status &err) {
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()) {
143       err = Status::FromErrorStringWithFormat(
144           "couldn't deallocate memory for %s: %s",
145           m_persistent_variable_sp->GetName().GetCString(),
146           deallocate_error.AsCString());
147     }
148   }
149 
150   void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
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 &
166         ExpressionVariable::EVNeedsAllocation) {
167       MakeAllocation(map, err);
168       m_persistent_variable_sp->m_flags |=
169           ExpressionVariable::EVIsLLDBAllocated;
170 
171       if (!err.Success())
172         return;
173     }
174 
175     if ((m_persistent_variable_sp->m_flags &
176              ExpressionVariable::EVIsProgramReference &&
177          m_persistent_variable_sp->m_live_sp) ||
178         m_persistent_variable_sp->m_flags &
179             ExpressionVariable::EVIsLLDBAllocated) {
180       Status write_error;
181 
182       map.WriteScalarToMemory(
183           load_addr,
184           m_persistent_variable_sp->m_live_sp->GetValue().GetScalar(),
185           map.GetAddressByteSize(), write_error);
186 
187       if (!write_error.Success()) {
188         err = Status::FromErrorStringWithFormat(
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 {
194       err = Status::FromErrorStringWithFormat(
195           "no materialization happened for persistent variable %s",
196           m_persistent_variable_sp->GetName().AsCString());
197       return;
198     }
199   }
200 
201   void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
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 &
222          ExpressionVariable::EVIsLLDBAllocated) ||
223         (m_persistent_variable_sp->m_flags &
224          ExpressionVariable::EVIsProgramReference)) {
225       if (m_persistent_variable_sp->m_flags &
226               ExpressionVariable::EVIsProgramReference &&
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()) {
238           err = Status::FromErrorStringWithFormat(
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(
246             map.GetBestExecutionContextScope(),
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 |=
258               ExpressionVariable::EVIsLLDBAllocated;
259           m_persistent_variable_sp->m_flags |=
260               ExpressionVariable::EVNeedsAllocation;
261           m_persistent_variable_sp->m_flags |=
262               ExpressionVariable::EVNeedsFreezeDry;
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) {
273         err = Status::FromErrorStringWithFormat(
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) {
281         err = Status::FromErrorStringWithFormat(
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 &
288               ExpressionVariable::EVNeedsFreezeDry ||
289           m_persistent_variable_sp->m_flags &
290               ExpressionVariable::EVKeepInTarget) {
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()) {
308           err = Status::FromErrorStringWithFormat(
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 {
319       err = Status::FromErrorStringWithFormat(
320           "no dematerialization happened for persistent variable %s",
321           m_persistent_variable_sp->GetName().AsCString());
322       return;
323     }
324 
325     lldb::ProcessSP process_sp =
326         map.GetBestExecutionContextScope()->CalculateProcess();
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 |=
332           ExpressionVariable::EVNeedsAllocation;
333 
334       DestroyAllocation(map, err);
335       if (!err.Success())
336         return;
337     } else if (m_persistent_variable_sp->m_flags &
338                    ExpressionVariable::EVNeedsAllocation &&
339                !(m_persistent_variable_sp->m_flags &
340                  ExpressionVariable::EVKeepInTarget)) {
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 
409 private:
410   lldb::ExpressionVariableSP m_persistent_variable_sp;
411   Materializer::PersistentVariableDelegate *m_delegate;
412 };
413 
414 uint32_t Materializer::AddPersistentVariable(
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.
429 class EntityVariableBase : public Materializer::Entity {
430 public:
431   virtual ~EntityVariableBase() = default;
432 
433   EntityVariableBase() {
434     // Hard-coding to maximum size of a pointer since all variables are
435     // materialized by reference
436     m_size = g_default_var_byte_size;
437     m_alignment = g_default_var_alignment;
438   }
439 
440   void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
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) {
460       err = Status::FromErrorStringWithFormat(
461           "couldn't get a value object for variable %s", GetName().AsCString());
462       return;
463     }
464 
465     Status valobj_error = valobj_sp->GetError().Clone();
466 
467     if (valobj_error.Fail()) {
468       err = Status::FromErrorStringWithFormat(
469           "couldn't get the value of variable %s: %s", 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()) {
480         err = Status::FromErrorStringWithFormat(
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 = Status::FromErrorStringWithFormat(
494             "couldn't write the contents of reference "
495             "variable %s to memory: %s",
496             GetName().AsCString(), 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()) {
509           err = Status::FromErrorStringWithFormat(
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 = Status::FromErrorStringWithFormat(
520               "couldn't get the value of %s: %s", GetName().AsCString(),
521               extract_error.AsCString());
522           return;
523         }
524 
525         if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
526           err = Status::FromErrorStringWithFormat(
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 = Status::FromErrorStringWithFormat(
535                 "the variable '%s' has no location, "
536                 "it may have been optimized out",
537                 GetName().AsCString());
538           } else {
539             err = Status::FromErrorStringWithFormat(
540                 "size of variable %s (%" PRIu64
541                 ") is larger than the ValueObject's size (%" PRIu64 ")",
542                 GetName().AsCString(), GetByteSize(scope).value_or(0),
543                 data.GetByteSize());
544           }
545           return;
546         }
547 
548         std::optional<size_t> opt_bit_align = GetTypeBitAlign(scope);
549         if (!opt_bit_align) {
550           err = Status::FromErrorStringWithFormat(
551               "can't get the type alignment for %s", GetName().AsCString());
552           return;
553         }
554 
555         size_t byte_align = (*opt_bit_align + 7) / 8;
556 
557         Status alloc_error;
558         const bool zero_memory = false;
559 
560         m_temporary_allocation = map.Malloc(
561             data.GetByteSize(), byte_align,
562             lldb::ePermissionsReadable | lldb::ePermissionsWritable,
563             IRMemoryMap::eAllocationPolicyMirror, zero_memory, alloc_error);
564 
565         m_temporary_allocation_size = data.GetByteSize();
566 
567         m_original_data = std::make_shared<DataBufferHeap>(data.GetDataStart(),
568                                                            data.GetByteSize());
569 
570         if (!alloc_error.Success()) {
571           err = Status::FromErrorStringWithFormat(
572               "couldn't allocate a temporary region for %s: %s",
573               GetName().AsCString(), alloc_error.AsCString());
574           return;
575         }
576 
577         Status write_error;
578 
579         map.WriteMemory(m_temporary_allocation, data.GetDataStart(),
580                         data.GetByteSize(), write_error);
581 
582         if (!write_error.Success()) {
583           err = Status::FromErrorStringWithFormat(
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 
591         map.WritePointerToMemory(load_addr, m_temporary_allocation,
592                                  pointer_write_error);
593 
594         if (!pointer_write_error.Success()) {
595           err = Status::FromErrorStringWithFormat(
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 
603   void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
604                      lldb::addr_t process_address, lldb::addr_t frame_top,
605                      lldb::addr_t frame_bottom, Status &err) override {
606     Log *log = GetLog(LLDBLog::Expressions);
607 
608     const lldb::addr_t load_addr = process_address + m_offset;
609     if (log) {
610       LLDB_LOGF(log,
611                 "EntityVariable::Dematerialize [address = 0x%" PRIx64
612                 ", m_variable_sp = %s]",
613                 (uint64_t)load_addr, GetName().AsCString());
614     }
615 
616     if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
617       ExecutionContextScope *scope = frame_sp.get();
618 
619       if (!scope)
620         scope = map.GetBestExecutionContextScope();
621 
622       lldb::ValueObjectSP valobj_sp = SetupValueObject(scope);
623 
624       if (!valobj_sp) {
625         err = Status::FromErrorStringWithFormat(
626             "couldn't get a value object for variable %s",
627             GetName().AsCString());
628         return;
629       }
630 
631       lldb_private::DataExtractor data;
632 
633       Status extract_error;
634 
635       map.GetMemoryData(data, m_temporary_allocation,
636                         valobj_sp->GetByteSize().value_or(0), extract_error);
637 
638       if (!extract_error.Success()) {
639         err = Status::FromErrorStringWithFormat(
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()) {
660           err = Status::FromErrorStringWithFormat(
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()) {
672         err = Status::FromErrorStringWithFormat(
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();
679       m_temporary_allocation = LLDB_INVALID_ADDRESS;
680       m_temporary_allocation_size = 0;
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 
693     lldb::addr_t ptr = LLDB_INVALID_ADDRESS;
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 
719     if (m_temporary_allocation == LLDB_INVALID_ADDRESS) {
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 {
728       DataBufferHeap data(m_temporary_allocation_size, 0);
729 
730       map.ReadMemory(data.GetBytes(), m_temporary_allocation,
731                      m_temporary_allocation_size, err);
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 {
747     if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
748       Status free_error;
749 
750       map.Free(m_temporary_allocation, free_error);
751 
752       m_temporary_allocation = LLDB_INVALID_ADDRESS;
753       m_temporary_allocation_size = 0;
754     }
755   }
756 
757 private:
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
773   SetupValueObject(ExecutionContextScope *scope) = 0;
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 std::optional<uint64_t>
780   GetByteSize(ExecutionContextScope *scope) const = 0;
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>
791   GetTypeBitAlign(ExecutionContextScope *scope) const = 0;
792 
793 protected:
794   bool m_is_reference = false;
795   lldb::addr_t m_temporary_allocation = LLDB_INVALID_ADDRESS;
796   size_t m_temporary_allocation_size = 0;
797   lldb::DataBufferSP m_original_data;
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.
806 class EntityVariable : public EntityVariableBase {
807 public:
808   EntityVariable(lldb::VariableSP &variable_sp) : m_variable_sp(variable_sp) {
809     m_is_reference =
810         m_variable_sp->GetType()->GetForwardCompilerType().IsReferenceType();
811   }
812 
813   ConstString GetName() const override { return m_variable_sp->GetName(); }
814 
815   lldb::ValueObjectSP SetupValueObject(ExecutionContextScope *scope) override {
816     assert(m_variable_sp != nullptr);
817     return ValueObjectVariable::Create(scope, m_variable_sp);
818   }
819 
820   std::optional<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 
835 private:
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).
844 class EntityValueObject : public EntityVariableBase {
845 public:
846   EntityValueObject(ConstString name, ValueObjectProviderTy provider)
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 
853   lldb::ValueObjectSP SetupValueObject(ExecutionContextScope *scope) override {
854     m_valobj_sp =
855         m_valobj_provider(GetName(), scope->CalculateStackFrame().get());
856 
857     if (m_valobj_sp)
858       m_is_reference = m_valobj_sp->GetCompilerType().IsReferenceType();
859 
860     return m_valobj_sp;
861   }
862 
863   std::optional<uint64_t>
864   GetByteSize(ExecutionContextScope *scope) const override {
865     if (m_valobj_sp)
866       return m_valobj_sp->GetCompilerType().GetByteSize(scope);
867 
868     return {};
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 
886 private:
887   ConstString m_name;
888   lldb::ValueObjectSP m_valobj_sp;
889   ValueObjectProviderTy m_valobj_provider;
890 };
891 
892 uint32_t Materializer::AddVariable(lldb::VariableSP &variable_sp, Status &err) {
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 
900 uint32_t Materializer::AddValueObject(ConstString name,
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 
911 class EntityResultVariable : public Materializer::Entity {
912 public:
913   EntityResultVariable(const CompilerType &type, bool is_program_reference,
914                        bool keep_in_memory,
915                        Materializer::PersistentVariableDelegate *delegate)
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
920     m_size = g_default_var_byte_size;
921     m_alignment = g_default_var_alignment;
922   }
923 
924   void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
925                    lldb::addr_t process_address, Status &err) override {
926     if (!m_is_program_reference) {
927       if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
928         err = Status::FromErrorString(
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       std::optional<uint64_t> byte_size = m_type.GetByteSize(exe_scope);
941       if (!byte_size) {
942         err = Status::FromErrorStringWithFormat(
943             "can't get size of type \"%s\"", m_type.GetTypeName().AsCString());
944         return;
945       }
946 
947       std::optional<size_t> opt_bit_align = m_type.GetTypeBitAlign(exe_scope);
948       if (!opt_bit_align) {
949         err = Status::FromErrorStringWithFormat(
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       Status alloc_error;
958       const bool zero_memory = true;
959 
960       m_temporary_allocation = map.Malloc(
961           *byte_size, byte_align,
962           lldb::ePermissionsReadable | lldb::ePermissionsWritable,
963           IRMemoryMap::eAllocationPolicyMirror, zero_memory, alloc_error);
964       m_temporary_allocation_size = *byte_size;
965 
966       if (!alloc_error.Success()) {
967         err = Status::FromErrorStringWithFormat(
968             "couldn't allocate a temporary region for the result: %s",
969             alloc_error.AsCString());
970         return;
971       }
972 
973       Status pointer_write_error;
974 
975       map.WritePointerToMemory(load_addr, m_temporary_allocation,
976                                pointer_write_error);
977 
978       if (!pointer_write_error.Success()) {
979         err = Status::FromErrorStringWithFormat(
980             "couldn't write the address of the "
981             "temporary region for the result: %s",
982             pointer_write_error.AsCString());
983       }
984     }
985   }
986 
987   void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
988                      lldb::addr_t process_address, lldb::addr_t frame_top,
989                      lldb::addr_t frame_bottom, Status &err) override {
990     err.Clear();
991 
992     ExecutionContextScope *exe_scope = frame_sp.get();
993     if (!exe_scope)
994       exe_scope = map.GetBestExecutionContextScope();
995 
996     if (!exe_scope) {
997       err = Status::FromErrorString(
998           "Couldn't dematerialize a result variable: invalid "
999           "execution context scope");
1000       return;
1001     }
1002 
1003     lldb::addr_t address;
1004     Status read_error;
1005     const lldb::addr_t load_addr = process_address + m_offset;
1006 
1007     map.ReadPointerFromMemory(&address, load_addr, read_error);
1008 
1009     if (!read_error.Success()) {
1010       err = Status::FromErrorString(
1011           "Couldn't dematerialize a result variable: couldn't "
1012           "read its address");
1013       return;
1014     }
1015 
1016     lldb::TargetSP target_sp = exe_scope->CalculateTarget();
1017 
1018     if (!target_sp) {
1019       err = Status::FromErrorString(
1020           "Couldn't dematerialize a result variable: no target");
1021       return;
1022     }
1023 
1024     auto type_system_or_err =
1025         target_sp->GetScratchTypeSystemForLanguage(m_type.GetMinimumLanguage());
1026 
1027     if (auto error = type_system_or_err.takeError()) {
1028       err = Status::FromErrorStringWithFormat(
1029           "Couldn't dematerialize a result variable: "
1030           "couldn't get the corresponding type "
1031           "system: %s",
1032           llvm::toString(std::move(error)).c_str());
1033       return;
1034     }
1035     auto ts = *type_system_or_err;
1036     if (!ts) {
1037       err = Status::FromErrorStringWithFormat(
1038           "Couldn't dematerialize a result variable: "
1039           "couldn't corresponding type system is "
1040           "no longer live.");
1041       return;
1042     }
1043     PersistentExpressionState *persistent_state =
1044         ts->GetPersistentExpressionState();
1045 
1046     if (!persistent_state) {
1047       err = Status::FromErrorString(
1048           "Couldn't dematerialize a result variable: "
1049           "corresponding type system doesn't handle persistent "
1050           "variables");
1051       return;
1052     }
1053 
1054     ConstString name = m_delegate
1055                            ? m_delegate->GetName()
1056                            : persistent_state->GetNextPersistentVariableName();
1057 
1058     lldb::ExpressionVariableSP ret = persistent_state->CreatePersistentVariable(
1059         exe_scope, name, m_type, map.GetByteOrder(), map.GetAddressByteSize());
1060 
1061     if (!ret) {
1062       err = Status::FromErrorStringWithFormat(
1063           "couldn't dematerialize a result variable: "
1064           "failed to make persistent variable %s",
1065           name.AsCString());
1066       return;
1067     }
1068 
1069     lldb::ProcessSP process_sp =
1070         map.GetBestExecutionContextScope()->CalculateProcess();
1071 
1072     if (m_delegate) {
1073       m_delegate->DidDematerialize(ret);
1074     }
1075 
1076     bool can_persist =
1077         (m_is_program_reference && process_sp && process_sp->CanJIT() &&
1078          !(address >= frame_bottom && address < frame_top));
1079 
1080     if (can_persist && m_keep_in_memory) {
1081       ret->m_live_sp = ValueObjectConstResult::Create(exe_scope, m_type, name,
1082                                                       address, eAddressTypeLoad,
1083                                                       map.GetAddressByteSize());
1084     }
1085 
1086     ret->ValueUpdated();
1087 
1088     const size_t pvar_byte_size = ret->GetByteSize().value_or(0);
1089     uint8_t *pvar_data = ret->GetValueBytes();
1090 
1091     map.ReadMemory(pvar_data, address, pvar_byte_size, read_error);
1092 
1093     if (!read_error.Success()) {
1094       err = Status::FromErrorString(
1095           "Couldn't dematerialize a result variable: couldn't read its memory");
1096       return;
1097     }
1098 
1099     if (!can_persist || !m_keep_in_memory) {
1100       ret->m_flags |= ExpressionVariable::EVNeedsAllocation;
1101 
1102       if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
1103         Status free_error;
1104         map.Free(m_temporary_allocation, free_error);
1105       }
1106     } else {
1107       ret->m_flags |= ExpressionVariable::EVIsLLDBAllocated;
1108     }
1109 
1110     m_temporary_allocation = LLDB_INVALID_ADDRESS;
1111     m_temporary_allocation_size = 0;
1112   }
1113 
1114   void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
1115                  Log *log) override {
1116     StreamString dump_stream;
1117 
1118     const lldb::addr_t load_addr = process_address + m_offset;
1119 
1120     dump_stream.Printf("0x%" PRIx64 ": EntityResultVariable\n", load_addr);
1121 
1122     Status err;
1123 
1124     lldb::addr_t ptr = LLDB_INVALID_ADDRESS;
1125 
1126     {
1127       dump_stream.Printf("Pointer:\n");
1128 
1129       DataBufferHeap data(m_size, 0);
1130 
1131       map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
1132 
1133       if (!err.Success()) {
1134         dump_stream.Printf("  <could not be read>\n");
1135       } else {
1136         DataExtractor extractor(data.GetBytes(), data.GetByteSize(),
1137                                 map.GetByteOrder(), map.GetAddressByteSize());
1138 
1139         DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
1140                      load_addr);
1141 
1142         lldb::offset_t offset = 0;
1143 
1144         ptr = extractor.GetAddress(&offset);
1145 
1146         dump_stream.PutChar('\n');
1147       }
1148     }
1149 
1150     if (m_temporary_allocation == LLDB_INVALID_ADDRESS) {
1151       dump_stream.Printf("Points to process memory:\n");
1152     } else {
1153       dump_stream.Printf("Temporary allocation:\n");
1154     }
1155 
1156     if (ptr == LLDB_INVALID_ADDRESS) {
1157       dump_stream.Printf("  <could not be be found>\n");
1158     } else {
1159       DataBufferHeap data(m_temporary_allocation_size, 0);
1160 
1161       map.ReadMemory(data.GetBytes(), m_temporary_allocation,
1162                      m_temporary_allocation_size, err);
1163 
1164       if (!err.Success()) {
1165         dump_stream.Printf("  <could not be read>\n");
1166       } else {
1167         DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
1168                      load_addr);
1169 
1170         dump_stream.PutChar('\n');
1171       }
1172     }
1173 
1174     log->PutString(dump_stream.GetString());
1175   }
1176 
1177   void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {
1178     if (!m_keep_in_memory && m_temporary_allocation != LLDB_INVALID_ADDRESS) {
1179       Status free_error;
1180 
1181       map.Free(m_temporary_allocation, free_error);
1182     }
1183 
1184     m_temporary_allocation = LLDB_INVALID_ADDRESS;
1185     m_temporary_allocation_size = 0;
1186   }
1187 
1188 private:
1189   CompilerType m_type;
1190   bool m_is_program_reference;
1191   bool m_keep_in_memory;
1192 
1193   lldb::addr_t m_temporary_allocation = LLDB_INVALID_ADDRESS;
1194   size_t m_temporary_allocation_size = 0;
1195   Materializer::PersistentVariableDelegate *m_delegate;
1196 };
1197 
1198 uint32_t Materializer::AddResultVariable(const CompilerType &type,
1199                                          bool is_program_reference,
1200                                          bool keep_in_memory,
1201                                          PersistentVariableDelegate *delegate,
1202                                          Status &err) {
1203   EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
1204   *iter = std::make_unique<EntityResultVariable>(type, is_program_reference,
1205                                                  keep_in_memory, delegate);
1206   uint32_t ret = AddStructMember(**iter);
1207   (*iter)->SetOffset(ret);
1208   return ret;
1209 }
1210 
1211 class EntitySymbol : public Materializer::Entity {
1212 public:
1213   EntitySymbol(const Symbol &symbol) : Entity(), m_symbol(symbol) {
1214     // Hard-coding to maximum size of a symbol
1215     m_size = g_default_var_byte_size;
1216     m_alignment = g_default_var_alignment;
1217   }
1218 
1219   void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1220                    lldb::addr_t process_address, Status &err) override {
1221     Log *log = GetLog(LLDBLog::Expressions);
1222 
1223     const lldb::addr_t load_addr = process_address + m_offset;
1224 
1225     if (log) {
1226       LLDB_LOGF(log,
1227                 "EntitySymbol::Materialize [address = 0x%" PRIx64
1228                 ", m_symbol = %s]",
1229                 (uint64_t)load_addr, m_symbol.GetName().AsCString());
1230     }
1231 
1232     const Address sym_address = m_symbol.GetAddress();
1233 
1234     ExecutionContextScope *exe_scope = frame_sp.get();
1235     if (!exe_scope)
1236       exe_scope = map.GetBestExecutionContextScope();
1237 
1238     lldb::TargetSP target_sp;
1239 
1240     if (exe_scope)
1241       target_sp = map.GetBestExecutionContextScope()->CalculateTarget();
1242 
1243     if (!target_sp) {
1244       err = Status::FromErrorStringWithFormat(
1245           "couldn't resolve symbol %s because there is no target",
1246           m_symbol.GetName().AsCString());
1247       return;
1248     }
1249 
1250     lldb::addr_t resolved_address = sym_address.GetLoadAddress(target_sp.get());
1251 
1252     if (resolved_address == LLDB_INVALID_ADDRESS)
1253       resolved_address = sym_address.GetFileAddress();
1254 
1255     Status pointer_write_error;
1256 
1257     map.WritePointerToMemory(load_addr, resolved_address, pointer_write_error);
1258 
1259     if (!pointer_write_error.Success()) {
1260       err = Status::FromErrorStringWithFormat(
1261           "couldn't write the address of symbol %s: %s",
1262           m_symbol.GetName().AsCString(), pointer_write_error.AsCString());
1263       return;
1264     }
1265   }
1266 
1267   void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1268                      lldb::addr_t process_address, lldb::addr_t frame_top,
1269                      lldb::addr_t frame_bottom, Status &err) override {
1270     Log *log = GetLog(LLDBLog::Expressions);
1271 
1272     const lldb::addr_t load_addr = process_address + m_offset;
1273 
1274     if (log) {
1275       LLDB_LOGF(log,
1276                 "EntitySymbol::Dematerialize [address = 0x%" PRIx64
1277                 ", m_symbol = %s]",
1278                 (uint64_t)load_addr, m_symbol.GetName().AsCString());
1279     }
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 
1317 private:
1318   Symbol m_symbol;
1319 };
1320 
1321 uint32_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 
1329 class EntityRegister : public Materializer::Entity {
1330 public:
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 
1338   void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1339                    lldb::addr_t process_address, Status &err) override {
1340     Log *log = GetLog(LLDBLog::Expressions);
1341 
1342     const lldb::addr_t load_addr = process_address + m_offset;
1343 
1344     if (log) {
1345       LLDB_LOGF(log,
1346                 "EntityRegister::Materialize [address = 0x%" PRIx64
1347                 ", m_register_info = %s]",
1348                 (uint64_t)load_addr, m_register_info.name);
1349     }
1350 
1351     RegisterValue reg_value;
1352 
1353     if (!frame_sp.get()) {
1354       err = Status::FromErrorStringWithFormat(
1355           "couldn't materialize register %s without a stack frame",
1356           m_register_info.name);
1357       return;
1358     }
1359 
1360     lldb::RegisterContextSP reg_context_sp = frame_sp->GetRegisterContext();
1361 
1362     if (!reg_context_sp->ReadRegister(&m_register_info, reg_value)) {
1363       err = Status::FromErrorStringWithFormat(
1364           "couldn't read the value of register %s", m_register_info.name);
1365       return;
1366     }
1367 
1368     DataExtractor register_data;
1369 
1370     if (!reg_value.GetData(register_data)) {
1371       err = Status::FromErrorStringWithFormat(
1372           "couldn't get the data for register %s", m_register_info.name);
1373       return;
1374     }
1375 
1376     if (register_data.GetByteSize() != m_register_info.byte_size) {
1377       err = Status::FromErrorStringWithFormat(
1378           "data for register %s had size %llu but we expected %llu",
1379           m_register_info.name, (unsigned long long)register_data.GetByteSize(),
1380           (unsigned long long)m_register_info.byte_size);
1381       return;
1382     }
1383 
1384     m_register_contents = std::make_shared<DataBufferHeap>(
1385         register_data.GetDataStart(), register_data.GetByteSize());
1386 
1387     Status write_error;
1388 
1389     map.WriteMemory(load_addr, register_data.GetDataStart(),
1390                     register_data.GetByteSize(), write_error);
1391 
1392     if (!write_error.Success()) {
1393       err = Status::FromErrorStringWithFormat(
1394           "couldn't write the contents of register %s: %s",
1395           m_register_info.name, write_error.AsCString());
1396       return;
1397     }
1398   }
1399 
1400   void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1401                      lldb::addr_t process_address, lldb::addr_t frame_top,
1402                      lldb::addr_t frame_bottom, Status &err) override {
1403     Log *log = GetLog(LLDBLog::Expressions);
1404 
1405     const lldb::addr_t load_addr = process_address + m_offset;
1406 
1407     if (log) {
1408       LLDB_LOGF(log,
1409                 "EntityRegister::Dematerialize [address = 0x%" PRIx64
1410                 ", m_register_info = %s]",
1411                 (uint64_t)load_addr, m_register_info.name);
1412     }
1413 
1414     Status extract_error;
1415 
1416     DataExtractor register_data;
1417 
1418     if (!frame_sp.get()) {
1419       err = Status::FromErrorStringWithFormat(
1420           "couldn't dematerialize register %s without a stack frame",
1421           m_register_info.name);
1422       return;
1423     }
1424 
1425     lldb::RegisterContextSP reg_context_sp = frame_sp->GetRegisterContext();
1426 
1427     map.GetMemoryData(register_data, load_addr, m_register_info.byte_size,
1428                       extract_error);
1429 
1430     if (!extract_error.Success()) {
1431       err = Status::FromErrorStringWithFormat(
1432           "couldn't get the data for register %s: %s", m_register_info.name,
1433           extract_error.AsCString());
1434       return;
1435     }
1436 
1437     if (!memcmp(register_data.GetDataStart(), m_register_contents->GetBytes(),
1438                 register_data.GetByteSize())) {
1439       // No write required, and in particular we avoid errors if the register
1440       // wasn't writable
1441 
1442       m_register_contents.reset();
1443       return;
1444     }
1445 
1446     m_register_contents.reset();
1447 
1448     RegisterValue register_value(register_data.GetData(),
1449                                  register_data.GetByteOrder());
1450 
1451     if (!reg_context_sp->WriteRegister(&m_register_info, register_value)) {
1452       err = Status::FromErrorStringWithFormat(
1453           "couldn't write the value of register %s", m_register_info.name);
1454       return;
1455     }
1456   }
1457 
1458   void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
1459                  Log *log) override {
1460     StreamString dump_stream;
1461 
1462     Status err;
1463 
1464     const lldb::addr_t load_addr = process_address + m_offset;
1465 
1466     dump_stream.Printf("0x%" PRIx64 ": EntityRegister (%s)\n", load_addr,
1467                        m_register_info.name);
1468 
1469     {
1470       dump_stream.Printf("Value:\n");
1471 
1472       DataBufferHeap data(m_size, 0);
1473 
1474       map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
1475 
1476       if (!err.Success()) {
1477         dump_stream.Printf("  <could not be read>\n");
1478       } else {
1479         DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
1480                      load_addr);
1481 
1482         dump_stream.PutChar('\n');
1483       }
1484     }
1485 
1486     log->PutString(dump_stream.GetString());
1487   }
1488 
1489   void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {}
1490 
1491 private:
1492   RegisterInfo m_register_info;
1493   lldb::DataBufferSP m_register_contents;
1494 };
1495 
1496 uint32_t Materializer::AddRegister(const RegisterInfo &register_info,
1497                                    Status &err) {
1498   EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
1499   *iter = std::make_unique<EntityRegister>(register_info);
1500   uint32_t ret = AddStructMember(**iter);
1501   (*iter)->SetOffset(ret);
1502   return ret;
1503 }
1504 
1505 Materializer::~Materializer() {
1506   DematerializerSP dematerializer_sp = m_dematerializer_wp.lock();
1507 
1508   if (dematerializer_sp)
1509     dematerializer_sp->Wipe();
1510 }
1511 
1512 Materializer::DematerializerSP
1513 Materializer::Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1514                           lldb::addr_t process_address, Status &error) {
1515   ExecutionContextScope *exe_scope = frame_sp.get();
1516   if (!exe_scope)
1517     exe_scope = map.GetBestExecutionContextScope();
1518 
1519   DematerializerSP dematerializer_sp = m_dematerializer_wp.lock();
1520 
1521   if (dematerializer_sp) {
1522     error =
1523         Status::FromErrorString("Couldn't materialize: already materialized");
1524   }
1525 
1526   DematerializerSP ret(
1527       new Dematerializer(*this, frame_sp, map, process_address));
1528 
1529   if (!exe_scope) {
1530     error =
1531         Status::FromErrorString("Couldn't materialize: target doesn't exist");
1532   }
1533 
1534   for (EntityUP &entity_up : m_entities) {
1535     entity_up->Materialize(frame_sp, map, process_address, error);
1536 
1537     if (!error.Success())
1538       return DematerializerSP();
1539   }
1540 
1541   if (Log *log = GetLog(LLDBLog::Expressions)) {
1542     LLDB_LOGF(
1543         log,
1544         "Materializer::Materialize (frame_sp = %p, process_address = 0x%" PRIx64
1545         ") materialized:",
1546         static_cast<void *>(frame_sp.get()), process_address);
1547     for (EntityUP &entity_up : m_entities)
1548       entity_up->DumpToLog(map, process_address, log);
1549   }
1550 
1551   m_dematerializer_wp = ret;
1552 
1553   return ret;
1554 }
1555 
1556 void Materializer::Dematerializer::Dematerialize(Status &error,
1557                                                  lldb::addr_t frame_bottom,
1558                                                  lldb::addr_t frame_top) {
1559   lldb::StackFrameSP frame_sp;
1560 
1561   lldb::ThreadSP thread_sp = m_thread_wp.lock();
1562   if (thread_sp)
1563     frame_sp = thread_sp->GetFrameWithStackID(m_stack_id);
1564 
1565   ExecutionContextScope *exe_scope = frame_sp.get();
1566   if (!exe_scope)
1567     exe_scope = m_map->GetBestExecutionContextScope();
1568 
1569   if (!IsValid()) {
1570     error = Status::FromErrorString(
1571         "Couldn't dematerialize: invalid dematerializer");
1572   }
1573 
1574   if (!exe_scope) {
1575     error = Status::FromErrorString("Couldn't dematerialize: target is gone");
1576   } else {
1577     if (Log *log = GetLog(LLDBLog::Expressions)) {
1578       LLDB_LOGF(log,
1579                 "Materializer::Dematerialize (frame_sp = %p, process_address "
1580                 "= 0x%" PRIx64 ") about to dematerialize:",
1581                 static_cast<void *>(frame_sp.get()), m_process_address);
1582       for (EntityUP &entity_up : m_materializer->m_entities)
1583         entity_up->DumpToLog(*m_map, m_process_address, log);
1584     }
1585 
1586     for (EntityUP &entity_up : m_materializer->m_entities) {
1587       entity_up->Dematerialize(frame_sp, *m_map, m_process_address, frame_top,
1588                                frame_bottom, error);
1589 
1590       if (!error.Success())
1591         break;
1592     }
1593   }
1594 
1595   Wipe();
1596 }
1597 
1598 void Materializer::Dematerializer::Wipe() {
1599   if (!IsValid())
1600     return;
1601 
1602   for (EntityUP &entity_up : m_materializer->m_entities) {
1603     entity_up->Wipe(*m_map, m_process_address);
1604   }
1605 
1606   m_materializer = nullptr;
1607   m_map = nullptr;
1608   m_process_address = LLDB_INVALID_ADDRESS;
1609 }
1610 
1611 Materializer::PersistentVariableDelegate::PersistentVariableDelegate() =
1612     default;
1613 Materializer::PersistentVariableDelegate::~PersistentVariableDelegate() =
1614     default;
1615