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/Core/ValueObjectConstResult.h"
12 #include "lldb/Core/ValueObjectVariable.h"
13 #include "lldb/Expression/ExpressionVariable.h"
14 #include "lldb/Symbol/Symbol.h"
15 #include "lldb/Symbol/Type.h"
16 #include "lldb/Symbol/Variable.h"
17 #include "lldb/Target/ExecutionContext.h"
18 #include "lldb/Target/RegisterContext.h"
19 #include "lldb/Target/StackFrame.h"
20 #include "lldb/Target/Target.h"
21 #include "lldb/Target/Thread.h"
22 #include "lldb/Utility/LLDBLog.h"
23 #include "lldb/Utility/Log.h"
24 #include "lldb/Utility/RegisterValue.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.SetErrorStringWithFormat(
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.SetErrorStringWithFormat(
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.SetErrorStringWithFormat(
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.SetErrorStringWithFormat(
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.SetErrorStringWithFormat(
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.SetErrorStringWithFormat(
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.SetErrorStringWithFormat(
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.SetErrorStringWithFormat(
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.SetErrorStringWithFormat(
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.SetErrorStringWithFormat(
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.SetErrorStringWithFormat(
461           "couldn't get a value object for variable %s", GetName().AsCString());
462       return;
463     }
464 
465     Status valobj_error = valobj_sp->GetError();
466 
467     if (valobj_error.Fail()) {
468       err.SetErrorStringWithFormat("couldn't get the value of variable %s: %s",
469                                    GetName().AsCString(),
470                                    valobj_error.AsCString());
471       return;
472     }
473 
474     if (m_is_reference) {
475       DataExtractor valobj_extractor;
476       Status extract_error;
477       valobj_sp->GetData(valobj_extractor, extract_error);
478 
479       if (!extract_error.Success()) {
480         err.SetErrorStringWithFormat(
481             "couldn't read contents of reference variable %s: %s",
482             GetName().AsCString(), extract_error.AsCString());
483         return;
484       }
485 
486       lldb::offset_t offset = 0;
487       lldb::addr_t reference_addr = valobj_extractor.GetAddress(&offset);
488 
489       Status write_error;
490       map.WritePointerToMemory(load_addr, reference_addr, write_error);
491 
492       if (!write_error.Success()) {
493         err.SetErrorStringWithFormat("couldn't write the contents of reference "
494                                      "variable %s to memory: %s",
495                                      GetName().AsCString(),
496                                      write_error.AsCString());
497         return;
498       }
499     } else {
500       AddressType address_type = eAddressTypeInvalid;
501       const bool scalar_is_load_address = false;
502       lldb::addr_t addr_of_valobj =
503           valobj_sp->GetAddressOf(scalar_is_load_address, &address_type);
504       if (addr_of_valobj != LLDB_INVALID_ADDRESS) {
505         Status write_error;
506         map.WritePointerToMemory(load_addr, addr_of_valobj, write_error);
507 
508         if (!write_error.Success()) {
509           err.SetErrorStringWithFormat(
510               "couldn't write the address of variable %s to memory: %s",
511               GetName().AsCString(), write_error.AsCString());
512           return;
513         }
514       } else {
515         DataExtractor data;
516         Status extract_error;
517         valobj_sp->GetData(data, extract_error);
518         if (!extract_error.Success()) {
519           err.SetErrorStringWithFormat("couldn't get the value of %s: %s",
520                                        GetName().AsCString(),
521                                        extract_error.AsCString());
522           return;
523         }
524 
525         if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
526           err.SetErrorStringWithFormat(
527               "trying to create a temporary region for %s but one exists",
528               GetName().AsCString());
529           return;
530         }
531 
532         if (data.GetByteSize() < GetByteSize(scope)) {
533           if (data.GetByteSize() == 0 && !LocationExpressionIsValid()) {
534             err.SetErrorStringWithFormat("the variable '%s' has no location, "
535                                          "it may have been optimized out",
536                                          GetName().AsCString());
537           } else {
538             err.SetErrorStringWithFormat(
539                 "size of variable %s (%" PRIu64
540                 ") is larger than the ValueObject's size (%" PRIu64 ")",
541                 GetName().AsCString(), GetByteSize(scope).value_or(0),
542                 data.GetByteSize());
543           }
544           return;
545         }
546 
547         std::optional<size_t> opt_bit_align = GetTypeBitAlign(scope);
548         if (!opt_bit_align) {
549           err.SetErrorStringWithFormat("can't get the type alignment for %s",
550                                        GetName().AsCString());
551           return;
552         }
553 
554         size_t byte_align = (*opt_bit_align + 7) / 8;
555 
556         Status alloc_error;
557         const bool zero_memory = false;
558 
559         m_temporary_allocation = map.Malloc(
560             data.GetByteSize(), byte_align,
561             lldb::ePermissionsReadable | lldb::ePermissionsWritable,
562             IRMemoryMap::eAllocationPolicyMirror, zero_memory, alloc_error);
563 
564         m_temporary_allocation_size = data.GetByteSize();
565 
566         m_original_data = std::make_shared<DataBufferHeap>(data.GetDataStart(),
567                                                            data.GetByteSize());
568 
569         if (!alloc_error.Success()) {
570           err.SetErrorStringWithFormat(
571               "couldn't allocate a temporary region for %s: %s",
572               GetName().AsCString(), alloc_error.AsCString());
573           return;
574         }
575 
576         Status write_error;
577 
578         map.WriteMemory(m_temporary_allocation, data.GetDataStart(),
579                         data.GetByteSize(), write_error);
580 
581         if (!write_error.Success()) {
582           err.SetErrorStringWithFormat(
583               "couldn't write to the temporary region for %s: %s",
584               GetName().AsCString(), write_error.AsCString());
585           return;
586         }
587 
588         Status pointer_write_error;
589 
590         map.WritePointerToMemory(load_addr, m_temporary_allocation,
591                                  pointer_write_error);
592 
593         if (!pointer_write_error.Success()) {
594           err.SetErrorStringWithFormat(
595               "couldn't write the address of the temporary region for %s: %s",
596               GetName().AsCString(), pointer_write_error.AsCString());
597         }
598       }
599     }
600   }
601 
602   void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
603                      lldb::addr_t process_address, lldb::addr_t frame_top,
604                      lldb::addr_t frame_bottom, Status &err) override {
605     Log *log = GetLog(LLDBLog::Expressions);
606 
607     const lldb::addr_t load_addr = process_address + m_offset;
608     if (log) {
609       LLDB_LOGF(log,
610                 "EntityVariable::Dematerialize [address = 0x%" PRIx64
611                 ", m_variable_sp = %s]",
612                 (uint64_t)load_addr, GetName().AsCString());
613     }
614 
615     if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
616       ExecutionContextScope *scope = frame_sp.get();
617 
618       if (!scope)
619         scope = map.GetBestExecutionContextScope();
620 
621       lldb::ValueObjectSP valobj_sp = SetupValueObject(scope);
622 
623       if (!valobj_sp) {
624         err.SetErrorStringWithFormat(
625             "couldn't get a value object for variable %s",
626             GetName().AsCString());
627         return;
628       }
629 
630       lldb_private::DataExtractor data;
631 
632       Status extract_error;
633 
634       map.GetMemoryData(data, m_temporary_allocation,
635                         valobj_sp->GetByteSize().value_or(0), extract_error);
636 
637       if (!extract_error.Success()) {
638         err.SetErrorStringWithFormat("couldn't get the data for variable %s",
639                                      GetName().AsCString());
640         return;
641       }
642 
643       bool actually_write = true;
644 
645       if (m_original_data) {
646         if ((data.GetByteSize() == m_original_data->GetByteSize()) &&
647             !memcmp(m_original_data->GetBytes(), data.GetDataStart(),
648                     data.GetByteSize())) {
649           actually_write = false;
650         }
651       }
652 
653       Status set_error;
654 
655       if (actually_write) {
656         valobj_sp->SetData(data, set_error);
657 
658         if (!set_error.Success()) {
659           err.SetErrorStringWithFormat(
660               "couldn't write the new contents of %s back into the variable",
661               GetName().AsCString());
662           return;
663         }
664       }
665 
666       Status free_error;
667 
668       map.Free(m_temporary_allocation, free_error);
669 
670       if (!free_error.Success()) {
671         err.SetErrorStringWithFormat(
672             "couldn't free the temporary region for %s: %s",
673             GetName().AsCString(), free_error.AsCString());
674         return;
675       }
676 
677       m_original_data.reset();
678       m_temporary_allocation = LLDB_INVALID_ADDRESS;
679       m_temporary_allocation_size = 0;
680     }
681   }
682 
683   void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
684                  Log *log) override {
685     StreamString dump_stream;
686 
687     const lldb::addr_t load_addr = process_address + m_offset;
688     dump_stream.Printf("0x%" PRIx64 ": EntityVariable\n", load_addr);
689 
690     Status err;
691 
692     lldb::addr_t ptr = LLDB_INVALID_ADDRESS;
693 
694     {
695       dump_stream.Printf("Pointer:\n");
696 
697       DataBufferHeap data(m_size, 0);
698 
699       map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
700 
701       if (!err.Success()) {
702         dump_stream.Printf("  <could not be read>\n");
703       } else {
704         DataExtractor extractor(data.GetBytes(), data.GetByteSize(),
705                                 map.GetByteOrder(), map.GetAddressByteSize());
706 
707         DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
708                      load_addr);
709 
710         lldb::offset_t offset = 0;
711 
712         ptr = extractor.GetAddress(&offset);
713 
714         dump_stream.PutChar('\n');
715       }
716     }
717 
718     if (m_temporary_allocation == LLDB_INVALID_ADDRESS) {
719       dump_stream.Printf("Points to process memory:\n");
720     } else {
721       dump_stream.Printf("Temporary allocation:\n");
722     }
723 
724     if (ptr == LLDB_INVALID_ADDRESS) {
725       dump_stream.Printf("  <could not be be found>\n");
726     } else {
727       DataBufferHeap data(m_temporary_allocation_size, 0);
728 
729       map.ReadMemory(data.GetBytes(), m_temporary_allocation,
730                      m_temporary_allocation_size, err);
731 
732       if (!err.Success()) {
733         dump_stream.Printf("  <could not be read>\n");
734       } else {
735         DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
736                      load_addr);
737 
738         dump_stream.PutChar('\n');
739       }
740     }
741 
742     log->PutString(dump_stream.GetString());
743   }
744 
745   void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {
746     if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
747       Status free_error;
748 
749       map.Free(m_temporary_allocation, free_error);
750 
751       m_temporary_allocation = LLDB_INVALID_ADDRESS;
752       m_temporary_allocation_size = 0;
753     }
754   }
755 
756 private:
757   virtual ConstString GetName() const = 0;
758 
759   /// Creates and returns ValueObject tied to this variable
760   /// and prepares Entity for materialization.
761   ///
762   /// Called each time the Materializer (de)materializes a
763   /// variable. We re-create the ValueObject based on the
764   /// current ExecutionContextScope since clients such as
765   /// conditional breakpoints may materialize the same
766   /// EntityVariable multiple times with different frames.
767   ///
768   /// Each subsequent use of the EntityVariableBase interface
769   /// will query the newly created ValueObject until this
770   /// function is called again.
771   virtual lldb::ValueObjectSP
772   SetupValueObject(ExecutionContextScope *scope) = 0;
773 
774   /// Returns size in bytes of the type associated with this variable
775   ///
776   /// \returns On success, returns byte size of the type associated
777   ///          with this variable. Returns std::nullopt otherwise.
778   virtual std::optional<uint64_t>
779   GetByteSize(ExecutionContextScope *scope) const = 0;
780 
781   /// Returns 'true' if the location expression associated with this variable
782   /// is valid.
783   virtual bool LocationExpressionIsValid() const = 0;
784 
785   /// Returns alignment of the type associated with this variable in bits.
786   ///
787   /// \returns On success, returns alignment in bits for the type associated
788   ///          with this variable. Returns std::nullopt otherwise.
789   virtual std::optional<size_t>
790   GetTypeBitAlign(ExecutionContextScope *scope) const = 0;
791 
792 protected:
793   bool m_is_reference = false;
794   lldb::addr_t m_temporary_allocation = LLDB_INVALID_ADDRESS;
795   size_t m_temporary_allocation_size = 0;
796   lldb::DataBufferSP m_original_data;
797 };
798 
799 /// Represents an Entity constructed from a VariableSP.
800 ///
801 /// This class is used for materialization of variables for which
802 /// the user has a VariableSP on hand. The ValueObject is then
803 /// derived from the associated DWARF location expression when needed
804 /// by the Materializer.
805 class EntityVariable : public EntityVariableBase {
806 public:
807   EntityVariable(lldb::VariableSP &variable_sp) : m_variable_sp(variable_sp) {
808     m_is_reference =
809         m_variable_sp->GetType()->GetForwardCompilerType().IsReferenceType();
810   }
811 
812   ConstString GetName() const override { return m_variable_sp->GetName(); }
813 
814   lldb::ValueObjectSP SetupValueObject(ExecutionContextScope *scope) override {
815     assert(m_variable_sp != nullptr);
816     return ValueObjectVariable::Create(scope, m_variable_sp);
817   }
818 
819   std::optional<uint64_t>
820   GetByteSize(ExecutionContextScope *scope) const override {
821     return m_variable_sp->GetType()->GetByteSize(scope);
822   }
823 
824   bool LocationExpressionIsValid() const override {
825     return m_variable_sp->LocationExpressionList().IsValid();
826   }
827 
828   std::optional<size_t>
829   GetTypeBitAlign(ExecutionContextScope *scope) const override {
830     return m_variable_sp->GetType()->GetLayoutCompilerType().GetTypeBitAlign(
831         scope);
832   }
833 
834 private:
835   lldb::VariableSP m_variable_sp; ///< Variable that this entity is based on.
836 };
837 
838 /// Represents an Entity constructed from a VariableSP.
839 ///
840 /// This class is used for materialization of variables for
841 /// which the user does not have a VariableSP available (e.g.,
842 /// when materializing ivars).
843 class EntityValueObject : public EntityVariableBase {
844 public:
845   EntityValueObject(ConstString name, ValueObjectProviderTy provider)
846       : m_name(name), m_valobj_provider(std::move(provider)) {
847     assert(m_valobj_provider);
848   }
849 
850   ConstString GetName() const override { return m_name; }
851 
852   lldb::ValueObjectSP SetupValueObject(ExecutionContextScope *scope) override {
853     m_valobj_sp =
854         m_valobj_provider(GetName(), scope->CalculateStackFrame().get());
855 
856     if (m_valobj_sp)
857       m_is_reference = m_valobj_sp->GetCompilerType().IsReferenceType();
858 
859     return m_valobj_sp;
860   }
861 
862   std::optional<uint64_t>
863   GetByteSize(ExecutionContextScope *scope) const override {
864     if (m_valobj_sp)
865       return m_valobj_sp->GetCompilerType().GetByteSize(scope);
866 
867     return {};
868   }
869 
870   bool LocationExpressionIsValid() const override {
871     if (m_valobj_sp)
872       return m_valobj_sp->GetError().Success();
873 
874     return false;
875   }
876 
877   std::optional<size_t>
878   GetTypeBitAlign(ExecutionContextScope *scope) const override {
879     if (m_valobj_sp)
880       return m_valobj_sp->GetCompilerType().GetTypeBitAlign(scope);
881 
882     return {};
883   }
884 
885 private:
886   ConstString m_name;
887   lldb::ValueObjectSP m_valobj_sp;
888   ValueObjectProviderTy m_valobj_provider;
889 };
890 
891 uint32_t Materializer::AddVariable(lldb::VariableSP &variable_sp, Status &err) {
892   EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
893   *iter = std::make_unique<EntityVariable>(variable_sp);
894   uint32_t ret = AddStructMember(**iter);
895   (*iter)->SetOffset(ret);
896   return ret;
897 }
898 
899 uint32_t Materializer::AddValueObject(ConstString name,
900                                       ValueObjectProviderTy valobj_provider,
901                                       Status &err) {
902   assert(valobj_provider);
903   EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
904   *iter = std::make_unique<EntityValueObject>(name, std::move(valobj_provider));
905   uint32_t ret = AddStructMember(**iter);
906   (*iter)->SetOffset(ret);
907   return ret;
908 }
909 
910 class EntityResultVariable : public Materializer::Entity {
911 public:
912   EntityResultVariable(const CompilerType &type, bool is_program_reference,
913                        bool keep_in_memory,
914                        Materializer::PersistentVariableDelegate *delegate)
915       : Entity(), m_type(type), m_is_program_reference(is_program_reference),
916         m_keep_in_memory(keep_in_memory), m_delegate(delegate) {
917     // Hard-coding to maximum size of a pointer since all results are
918     // materialized by reference
919     m_size = g_default_var_byte_size;
920     m_alignment = g_default_var_alignment;
921   }
922 
923   void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
924                    lldb::addr_t process_address, Status &err) override {
925     if (!m_is_program_reference) {
926       if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
927         err.SetErrorString("Trying to create a temporary region for the result "
928                            "but one exists");
929         return;
930       }
931 
932       const lldb::addr_t load_addr = process_address + m_offset;
933 
934       ExecutionContextScope *exe_scope = frame_sp.get();
935       if (!exe_scope)
936         exe_scope = map.GetBestExecutionContextScope();
937 
938       std::optional<uint64_t> byte_size = m_type.GetByteSize(exe_scope);
939       if (!byte_size) {
940         err.SetErrorStringWithFormat("can't get size of type \"%s\"",
941                                      m_type.GetTypeName().AsCString());
942         return;
943       }
944 
945       std::optional<size_t> opt_bit_align = m_type.GetTypeBitAlign(exe_scope);
946       if (!opt_bit_align) {
947         err.SetErrorStringWithFormat("can't get the alignment of type  \"%s\"",
948                                      m_type.GetTypeName().AsCString());
949         return;
950       }
951 
952       size_t byte_align = (*opt_bit_align + 7) / 8;
953 
954       Status alloc_error;
955       const bool zero_memory = true;
956 
957       m_temporary_allocation = map.Malloc(
958           *byte_size, byte_align,
959           lldb::ePermissionsReadable | lldb::ePermissionsWritable,
960           IRMemoryMap::eAllocationPolicyMirror, zero_memory, alloc_error);
961       m_temporary_allocation_size = *byte_size;
962 
963       if (!alloc_error.Success()) {
964         err.SetErrorStringWithFormat(
965             "couldn't allocate a temporary region for the result: %s",
966             alloc_error.AsCString());
967         return;
968       }
969 
970       Status pointer_write_error;
971 
972       map.WritePointerToMemory(load_addr, m_temporary_allocation,
973                                pointer_write_error);
974 
975       if (!pointer_write_error.Success()) {
976         err.SetErrorStringWithFormat("couldn't write the address of the "
977                                      "temporary region for the result: %s",
978                                      pointer_write_error.AsCString());
979       }
980     }
981   }
982 
983   void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
984                      lldb::addr_t process_address, lldb::addr_t frame_top,
985                      lldb::addr_t frame_bottom, Status &err) override {
986     err.Clear();
987 
988     ExecutionContextScope *exe_scope = frame_sp.get();
989     if (!exe_scope)
990       exe_scope = map.GetBestExecutionContextScope();
991 
992     if (!exe_scope) {
993       err.SetErrorString("Couldn't dematerialize a result variable: invalid "
994                          "execution context scope");
995       return;
996     }
997 
998     lldb::addr_t address;
999     Status read_error;
1000     const lldb::addr_t load_addr = process_address + m_offset;
1001 
1002     map.ReadPointerFromMemory(&address, load_addr, read_error);
1003 
1004     if (!read_error.Success()) {
1005       err.SetErrorString("Couldn't dematerialize a result variable: couldn't "
1006                          "read its address");
1007       return;
1008     }
1009 
1010     lldb::TargetSP target_sp = exe_scope->CalculateTarget();
1011 
1012     if (!target_sp) {
1013       err.SetErrorString("Couldn't dematerialize a result variable: no target");
1014       return;
1015     }
1016 
1017     auto type_system_or_err =
1018         target_sp->GetScratchTypeSystemForLanguage(m_type.GetMinimumLanguage());
1019 
1020     if (auto error = type_system_or_err.takeError()) {
1021       err.SetErrorStringWithFormat("Couldn't dematerialize a result variable: "
1022                                    "couldn't get the corresponding type "
1023                                    "system: %s",
1024                                    llvm::toString(std::move(error)).c_str());
1025       return;
1026     }
1027     auto ts = *type_system_or_err;
1028     if (!ts) {
1029       err.SetErrorStringWithFormat("Couldn't dematerialize a result variable: "
1030                                    "couldn't corresponding type system is "
1031                                    "no longer live.");
1032       return;
1033     }
1034     PersistentExpressionState *persistent_state =
1035         ts->GetPersistentExpressionState();
1036 
1037     if (!persistent_state) {
1038       err.SetErrorString("Couldn't dematerialize a result variable: "
1039                          "corresponding type system doesn't handle persistent "
1040                          "variables");
1041       return;
1042     }
1043 
1044     ConstString name = m_delegate
1045                            ? m_delegate->GetName()
1046                            : persistent_state->GetNextPersistentVariableName();
1047 
1048     lldb::ExpressionVariableSP ret = persistent_state->CreatePersistentVariable(
1049         exe_scope, name, m_type, map.GetByteOrder(), map.GetAddressByteSize());
1050 
1051     if (!ret) {
1052       err.SetErrorStringWithFormat("couldn't dematerialize a result variable: "
1053                                    "failed to make persistent variable %s",
1054                                    name.AsCString());
1055       return;
1056     }
1057 
1058     lldb::ProcessSP process_sp =
1059         map.GetBestExecutionContextScope()->CalculateProcess();
1060 
1061     if (m_delegate) {
1062       m_delegate->DidDematerialize(ret);
1063     }
1064 
1065     bool can_persist =
1066         (m_is_program_reference && process_sp && process_sp->CanJIT() &&
1067          !(address >= frame_bottom && address < frame_top));
1068 
1069     if (can_persist && m_keep_in_memory) {
1070       ret->m_live_sp = ValueObjectConstResult::Create(exe_scope, m_type, name,
1071                                                       address, eAddressTypeLoad,
1072                                                       map.GetAddressByteSize());
1073     }
1074 
1075     ret->ValueUpdated();
1076 
1077     const size_t pvar_byte_size = ret->GetByteSize().value_or(0);
1078     uint8_t *pvar_data = ret->GetValueBytes();
1079 
1080     map.ReadMemory(pvar_data, address, pvar_byte_size, read_error);
1081 
1082     if (!read_error.Success()) {
1083       err.SetErrorString(
1084           "Couldn't dematerialize a result variable: couldn't read its memory");
1085       return;
1086     }
1087 
1088     if (!can_persist || !m_keep_in_memory) {
1089       ret->m_flags |= ExpressionVariable::EVNeedsAllocation;
1090 
1091       if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
1092         Status free_error;
1093         map.Free(m_temporary_allocation, free_error);
1094       }
1095     } else {
1096       ret->m_flags |= ExpressionVariable::EVIsLLDBAllocated;
1097     }
1098 
1099     m_temporary_allocation = LLDB_INVALID_ADDRESS;
1100     m_temporary_allocation_size = 0;
1101   }
1102 
1103   void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
1104                  Log *log) override {
1105     StreamString dump_stream;
1106 
1107     const lldb::addr_t load_addr = process_address + m_offset;
1108 
1109     dump_stream.Printf("0x%" PRIx64 ": EntityResultVariable\n", load_addr);
1110 
1111     Status err;
1112 
1113     lldb::addr_t ptr = LLDB_INVALID_ADDRESS;
1114 
1115     {
1116       dump_stream.Printf("Pointer:\n");
1117 
1118       DataBufferHeap data(m_size, 0);
1119 
1120       map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
1121 
1122       if (!err.Success()) {
1123         dump_stream.Printf("  <could not be read>\n");
1124       } else {
1125         DataExtractor extractor(data.GetBytes(), data.GetByteSize(),
1126                                 map.GetByteOrder(), map.GetAddressByteSize());
1127 
1128         DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
1129                      load_addr);
1130 
1131         lldb::offset_t offset = 0;
1132 
1133         ptr = extractor.GetAddress(&offset);
1134 
1135         dump_stream.PutChar('\n');
1136       }
1137     }
1138 
1139     if (m_temporary_allocation == LLDB_INVALID_ADDRESS) {
1140       dump_stream.Printf("Points to process memory:\n");
1141     } else {
1142       dump_stream.Printf("Temporary allocation:\n");
1143     }
1144 
1145     if (ptr == LLDB_INVALID_ADDRESS) {
1146       dump_stream.Printf("  <could not be be found>\n");
1147     } else {
1148       DataBufferHeap data(m_temporary_allocation_size, 0);
1149 
1150       map.ReadMemory(data.GetBytes(), m_temporary_allocation,
1151                      m_temporary_allocation_size, err);
1152 
1153       if (!err.Success()) {
1154         dump_stream.Printf("  <could not be read>\n");
1155       } else {
1156         DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
1157                      load_addr);
1158 
1159         dump_stream.PutChar('\n');
1160       }
1161     }
1162 
1163     log->PutString(dump_stream.GetString());
1164   }
1165 
1166   void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {
1167     if (!m_keep_in_memory && m_temporary_allocation != LLDB_INVALID_ADDRESS) {
1168       Status free_error;
1169 
1170       map.Free(m_temporary_allocation, free_error);
1171     }
1172 
1173     m_temporary_allocation = LLDB_INVALID_ADDRESS;
1174     m_temporary_allocation_size = 0;
1175   }
1176 
1177 private:
1178   CompilerType m_type;
1179   bool m_is_program_reference;
1180   bool m_keep_in_memory;
1181 
1182   lldb::addr_t m_temporary_allocation = LLDB_INVALID_ADDRESS;
1183   size_t m_temporary_allocation_size = 0;
1184   Materializer::PersistentVariableDelegate *m_delegate;
1185 };
1186 
1187 uint32_t Materializer::AddResultVariable(const CompilerType &type,
1188                                          bool is_program_reference,
1189                                          bool keep_in_memory,
1190                                          PersistentVariableDelegate *delegate,
1191                                          Status &err) {
1192   EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
1193   *iter = std::make_unique<EntityResultVariable>(type, is_program_reference,
1194                                                  keep_in_memory, delegate);
1195   uint32_t ret = AddStructMember(**iter);
1196   (*iter)->SetOffset(ret);
1197   return ret;
1198 }
1199 
1200 class EntitySymbol : public Materializer::Entity {
1201 public:
1202   EntitySymbol(const Symbol &symbol) : Entity(), m_symbol(symbol) {
1203     // Hard-coding to maximum size of a symbol
1204     m_size = g_default_var_byte_size;
1205     m_alignment = g_default_var_alignment;
1206   }
1207 
1208   void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1209                    lldb::addr_t process_address, Status &err) override {
1210     Log *log = GetLog(LLDBLog::Expressions);
1211 
1212     const lldb::addr_t load_addr = process_address + m_offset;
1213 
1214     if (log) {
1215       LLDB_LOGF(log,
1216                 "EntitySymbol::Materialize [address = 0x%" PRIx64
1217                 ", m_symbol = %s]",
1218                 (uint64_t)load_addr, m_symbol.GetName().AsCString());
1219     }
1220 
1221     const Address sym_address = m_symbol.GetAddress();
1222 
1223     ExecutionContextScope *exe_scope = frame_sp.get();
1224     if (!exe_scope)
1225       exe_scope = map.GetBestExecutionContextScope();
1226 
1227     lldb::TargetSP target_sp;
1228 
1229     if (exe_scope)
1230       target_sp = map.GetBestExecutionContextScope()->CalculateTarget();
1231 
1232     if (!target_sp) {
1233       err.SetErrorStringWithFormat(
1234           "couldn't resolve symbol %s because there is no target",
1235           m_symbol.GetName().AsCString());
1236       return;
1237     }
1238 
1239     lldb::addr_t resolved_address = sym_address.GetLoadAddress(target_sp.get());
1240 
1241     if (resolved_address == LLDB_INVALID_ADDRESS)
1242       resolved_address = sym_address.GetFileAddress();
1243 
1244     Status pointer_write_error;
1245 
1246     map.WritePointerToMemory(load_addr, resolved_address, pointer_write_error);
1247 
1248     if (!pointer_write_error.Success()) {
1249       err.SetErrorStringWithFormat(
1250           "couldn't write the address of symbol %s: %s",
1251           m_symbol.GetName().AsCString(), pointer_write_error.AsCString());
1252       return;
1253     }
1254   }
1255 
1256   void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1257                      lldb::addr_t process_address, lldb::addr_t frame_top,
1258                      lldb::addr_t frame_bottom, Status &err) override {
1259     Log *log = GetLog(LLDBLog::Expressions);
1260 
1261     const lldb::addr_t load_addr = process_address + m_offset;
1262 
1263     if (log) {
1264       LLDB_LOGF(log,
1265                 "EntitySymbol::Dematerialize [address = 0x%" PRIx64
1266                 ", m_symbol = %s]",
1267                 (uint64_t)load_addr, m_symbol.GetName().AsCString());
1268     }
1269 
1270     // no work needs to be done
1271   }
1272 
1273   void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
1274                  Log *log) override {
1275     StreamString dump_stream;
1276 
1277     Status err;
1278 
1279     const lldb::addr_t load_addr = process_address + m_offset;
1280 
1281     dump_stream.Printf("0x%" PRIx64 ": EntitySymbol (%s)\n", load_addr,
1282                        m_symbol.GetName().AsCString());
1283 
1284     {
1285       dump_stream.Printf("Pointer:\n");
1286 
1287       DataBufferHeap data(m_size, 0);
1288 
1289       map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
1290 
1291       if (!err.Success()) {
1292         dump_stream.Printf("  <could not be read>\n");
1293       } else {
1294         DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
1295                      load_addr);
1296 
1297         dump_stream.PutChar('\n');
1298       }
1299     }
1300 
1301     log->PutString(dump_stream.GetString());
1302   }
1303 
1304   void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {}
1305 
1306 private:
1307   Symbol m_symbol;
1308 };
1309 
1310 uint32_t Materializer::AddSymbol(const Symbol &symbol_sp, Status &err) {
1311   EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
1312   *iter = std::make_unique<EntitySymbol>(symbol_sp);
1313   uint32_t ret = AddStructMember(**iter);
1314   (*iter)->SetOffset(ret);
1315   return ret;
1316 }
1317 
1318 class EntityRegister : public Materializer::Entity {
1319 public:
1320   EntityRegister(const RegisterInfo &register_info)
1321       : Entity(), m_register_info(register_info) {
1322     // Hard-coding alignment conservatively
1323     m_size = m_register_info.byte_size;
1324     m_alignment = m_register_info.byte_size;
1325   }
1326 
1327   void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1328                    lldb::addr_t process_address, Status &err) override {
1329     Log *log = GetLog(LLDBLog::Expressions);
1330 
1331     const lldb::addr_t load_addr = process_address + m_offset;
1332 
1333     if (log) {
1334       LLDB_LOGF(log,
1335                 "EntityRegister::Materialize [address = 0x%" PRIx64
1336                 ", m_register_info = %s]",
1337                 (uint64_t)load_addr, m_register_info.name);
1338     }
1339 
1340     RegisterValue reg_value;
1341 
1342     if (!frame_sp.get()) {
1343       err.SetErrorStringWithFormat(
1344           "couldn't materialize register %s without a stack frame",
1345           m_register_info.name);
1346       return;
1347     }
1348 
1349     lldb::RegisterContextSP reg_context_sp = frame_sp->GetRegisterContext();
1350 
1351     if (!reg_context_sp->ReadRegister(&m_register_info, reg_value)) {
1352       err.SetErrorStringWithFormat("couldn't read the value of register %s",
1353                                    m_register_info.name);
1354       return;
1355     }
1356 
1357     DataExtractor register_data;
1358 
1359     if (!reg_value.GetData(register_data)) {
1360       err.SetErrorStringWithFormat("couldn't get the data for register %s",
1361                                    m_register_info.name);
1362       return;
1363     }
1364 
1365     if (register_data.GetByteSize() != m_register_info.byte_size) {
1366       err.SetErrorStringWithFormat(
1367           "data for register %s had size %llu but we expected %llu",
1368           m_register_info.name, (unsigned long long)register_data.GetByteSize(),
1369           (unsigned long long)m_register_info.byte_size);
1370       return;
1371     }
1372 
1373     m_register_contents = std::make_shared<DataBufferHeap>(
1374         register_data.GetDataStart(), register_data.GetByteSize());
1375 
1376     Status write_error;
1377 
1378     map.WriteMemory(load_addr, register_data.GetDataStart(),
1379                     register_data.GetByteSize(), write_error);
1380 
1381     if (!write_error.Success()) {
1382       err.SetErrorStringWithFormat(
1383           "couldn't write the contents of register %s: %s",
1384           m_register_info.name, write_error.AsCString());
1385       return;
1386     }
1387   }
1388 
1389   void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1390                      lldb::addr_t process_address, lldb::addr_t frame_top,
1391                      lldb::addr_t frame_bottom, Status &err) override {
1392     Log *log = GetLog(LLDBLog::Expressions);
1393 
1394     const lldb::addr_t load_addr = process_address + m_offset;
1395 
1396     if (log) {
1397       LLDB_LOGF(log,
1398                 "EntityRegister::Dematerialize [address = 0x%" PRIx64
1399                 ", m_register_info = %s]",
1400                 (uint64_t)load_addr, m_register_info.name);
1401     }
1402 
1403     Status extract_error;
1404 
1405     DataExtractor register_data;
1406 
1407     if (!frame_sp.get()) {
1408       err.SetErrorStringWithFormat(
1409           "couldn't dematerialize register %s without a stack frame",
1410           m_register_info.name);
1411       return;
1412     }
1413 
1414     lldb::RegisterContextSP reg_context_sp = frame_sp->GetRegisterContext();
1415 
1416     map.GetMemoryData(register_data, load_addr, m_register_info.byte_size,
1417                       extract_error);
1418 
1419     if (!extract_error.Success()) {
1420       err.SetErrorStringWithFormat("couldn't get the data for register %s: %s",
1421                                    m_register_info.name,
1422                                    extract_error.AsCString());
1423       return;
1424     }
1425 
1426     if (!memcmp(register_data.GetDataStart(), m_register_contents->GetBytes(),
1427                 register_data.GetByteSize())) {
1428       // No write required, and in particular we avoid errors if the register
1429       // wasn't writable
1430 
1431       m_register_contents.reset();
1432       return;
1433     }
1434 
1435     m_register_contents.reset();
1436 
1437     RegisterValue register_value(register_data.GetData(),
1438                                  register_data.GetByteOrder());
1439 
1440     if (!reg_context_sp->WriteRegister(&m_register_info, register_value)) {
1441       err.SetErrorStringWithFormat("couldn't write the value of register %s",
1442                                    m_register_info.name);
1443       return;
1444     }
1445   }
1446 
1447   void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
1448                  Log *log) override {
1449     StreamString dump_stream;
1450 
1451     Status err;
1452 
1453     const lldb::addr_t load_addr = process_address + m_offset;
1454 
1455     dump_stream.Printf("0x%" PRIx64 ": EntityRegister (%s)\n", load_addr,
1456                        m_register_info.name);
1457 
1458     {
1459       dump_stream.Printf("Value:\n");
1460 
1461       DataBufferHeap data(m_size, 0);
1462 
1463       map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
1464 
1465       if (!err.Success()) {
1466         dump_stream.Printf("  <could not be read>\n");
1467       } else {
1468         DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
1469                      load_addr);
1470 
1471         dump_stream.PutChar('\n');
1472       }
1473     }
1474 
1475     log->PutString(dump_stream.GetString());
1476   }
1477 
1478   void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {}
1479 
1480 private:
1481   RegisterInfo m_register_info;
1482   lldb::DataBufferSP m_register_contents;
1483 };
1484 
1485 uint32_t Materializer::AddRegister(const RegisterInfo &register_info,
1486                                    Status &err) {
1487   EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
1488   *iter = std::make_unique<EntityRegister>(register_info);
1489   uint32_t ret = AddStructMember(**iter);
1490   (*iter)->SetOffset(ret);
1491   return ret;
1492 }
1493 
1494 Materializer::~Materializer() {
1495   DematerializerSP dematerializer_sp = m_dematerializer_wp.lock();
1496 
1497   if (dematerializer_sp)
1498     dematerializer_sp->Wipe();
1499 }
1500 
1501 Materializer::DematerializerSP
1502 Materializer::Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1503                           lldb::addr_t process_address, Status &error) {
1504   ExecutionContextScope *exe_scope = frame_sp.get();
1505   if (!exe_scope)
1506     exe_scope = map.GetBestExecutionContextScope();
1507 
1508   DematerializerSP dematerializer_sp = m_dematerializer_wp.lock();
1509 
1510   if (dematerializer_sp) {
1511     error.SetErrorToGenericError();
1512     error.SetErrorString("Couldn't materialize: already materialized");
1513   }
1514 
1515   DematerializerSP ret(
1516       new Dematerializer(*this, frame_sp, map, process_address));
1517 
1518   if (!exe_scope) {
1519     error.SetErrorToGenericError();
1520     error.SetErrorString("Couldn't materialize: target doesn't exist");
1521   }
1522 
1523   for (EntityUP &entity_up : m_entities) {
1524     entity_up->Materialize(frame_sp, map, process_address, error);
1525 
1526     if (!error.Success())
1527       return DematerializerSP();
1528   }
1529 
1530   if (Log *log = GetLog(LLDBLog::Expressions)) {
1531     LLDB_LOGF(
1532         log,
1533         "Materializer::Materialize (frame_sp = %p, process_address = 0x%" PRIx64
1534         ") materialized:",
1535         static_cast<void *>(frame_sp.get()), process_address);
1536     for (EntityUP &entity_up : m_entities)
1537       entity_up->DumpToLog(map, process_address, log);
1538   }
1539 
1540   m_dematerializer_wp = ret;
1541 
1542   return ret;
1543 }
1544 
1545 void Materializer::Dematerializer::Dematerialize(Status &error,
1546                                                  lldb::addr_t frame_bottom,
1547                                                  lldb::addr_t frame_top) {
1548   lldb::StackFrameSP frame_sp;
1549 
1550   lldb::ThreadSP thread_sp = m_thread_wp.lock();
1551   if (thread_sp)
1552     frame_sp = thread_sp->GetFrameWithStackID(m_stack_id);
1553 
1554   ExecutionContextScope *exe_scope = frame_sp.get();
1555   if (!exe_scope)
1556     exe_scope = m_map->GetBestExecutionContextScope();
1557 
1558   if (!IsValid()) {
1559     error.SetErrorToGenericError();
1560     error.SetErrorString("Couldn't dematerialize: invalid dematerializer");
1561   }
1562 
1563   if (!exe_scope) {
1564     error.SetErrorToGenericError();
1565     error.SetErrorString("Couldn't dematerialize: target is gone");
1566   } else {
1567     if (Log *log = GetLog(LLDBLog::Expressions)) {
1568       LLDB_LOGF(log,
1569                 "Materializer::Dematerialize (frame_sp = %p, process_address "
1570                 "= 0x%" PRIx64 ") about to dematerialize:",
1571                 static_cast<void *>(frame_sp.get()), m_process_address);
1572       for (EntityUP &entity_up : m_materializer->m_entities)
1573         entity_up->DumpToLog(*m_map, m_process_address, log);
1574     }
1575 
1576     for (EntityUP &entity_up : m_materializer->m_entities) {
1577       entity_up->Dematerialize(frame_sp, *m_map, m_process_address, frame_top,
1578                                frame_bottom, error);
1579 
1580       if (!error.Success())
1581         break;
1582     }
1583   }
1584 
1585   Wipe();
1586 }
1587 
1588 void Materializer::Dematerializer::Wipe() {
1589   if (!IsValid())
1590     return;
1591 
1592   for (EntityUP &entity_up : m_materializer->m_entities) {
1593     entity_up->Wipe(*m_map, m_process_address);
1594   }
1595 
1596   m_materializer = nullptr;
1597   m_map = nullptr;
1598   m_process_address = LLDB_INVALID_ADDRESS;
1599 }
1600 
1601 Materializer::PersistentVariableDelegate::~PersistentVariableDelegate() =
1602     default;
1603