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 
26 #include <memory>
27 
28 using namespace lldb_private;
29 
30 uint32_t Materializer::AddStructMember(Entity &entity) {
31   uint32_t size = entity.GetSize();
32   uint32_t alignment = entity.GetAlignment();
33 
34   uint32_t ret;
35 
36   if (m_current_offset == 0)
37     m_struct_alignment = alignment;
38 
39   if (m_current_offset % alignment)
40     m_current_offset += (alignment - (m_current_offset % alignment));
41 
42   ret = m_current_offset;
43 
44   m_current_offset += size;
45 
46   return ret;
47 }
48 
49 class EntityPersistentVariable : public Materializer::Entity {
50 public:
51   EntityPersistentVariable(lldb::ExpressionVariableSP &persistent_variable_sp,
52                            Materializer::PersistentVariableDelegate *delegate)
53       : Entity(), m_persistent_variable_sp(persistent_variable_sp),
54         m_delegate(delegate) {
55     // Hard-coding to maximum size of a pointer since persistent variables are
56     // materialized by reference
57     m_size = 8;
58     m_alignment = 8;
59   }
60 
61   void MakeAllocation(IRMemoryMap &map, Status &err) {
62     Log *log = GetLog(LLDBLog::Expressions);
63 
64     // Allocate a spare memory area to store the persistent variable's
65     // contents.
66 
67     Status allocate_error;
68     const bool zero_memory = false;
69 
70     lldb::addr_t mem = map.Malloc(
71         m_persistent_variable_sp->GetByteSize().getValueOr(0), 8,
72         lldb::ePermissionsReadable | lldb::ePermissionsWritable,
73         IRMemoryMap::eAllocationPolicyMirror, zero_memory, allocate_error);
74 
75     if (!allocate_error.Success()) {
76       err.SetErrorStringWithFormat(
77           "couldn't allocate a memory area to store %s: %s",
78           m_persistent_variable_sp->GetName().GetCString(),
79           allocate_error.AsCString());
80       return;
81     }
82 
83     LLDB_LOGF(log, "Allocated %s (0x%" PRIx64 ") successfully",
84               m_persistent_variable_sp->GetName().GetCString(), mem);
85 
86     // Put the location of the spare memory into the live data of the
87     // ValueObject.
88 
89     m_persistent_variable_sp->m_live_sp = ValueObjectConstResult::Create(
90         map.GetBestExecutionContextScope(),
91         m_persistent_variable_sp->GetCompilerType(),
92         m_persistent_variable_sp->GetName(), mem, eAddressTypeLoad,
93         map.GetAddressByteSize());
94 
95     // Clear the flag if the variable will never be deallocated.
96 
97     if (m_persistent_variable_sp->m_flags &
98         ExpressionVariable::EVKeepInTarget) {
99       Status leak_error;
100       map.Leak(mem, leak_error);
101       m_persistent_variable_sp->m_flags &=
102           ~ExpressionVariable::EVNeedsAllocation;
103     }
104 
105     // Write the contents of the variable to the area.
106 
107     Status write_error;
108 
109     map.WriteMemory(mem, m_persistent_variable_sp->GetValueBytes(),
110                     m_persistent_variable_sp->GetByteSize().getValueOr(0),
111                     write_error);
112 
113     if (!write_error.Success()) {
114       err.SetErrorStringWithFormat(
115           "couldn't write %s to the target: %s",
116           m_persistent_variable_sp->GetName().AsCString(),
117           write_error.AsCString());
118       return;
119     }
120   }
121 
122   void DestroyAllocation(IRMemoryMap &map, Status &err) {
123     Status deallocate_error;
124 
125     map.Free((lldb::addr_t)m_persistent_variable_sp->m_live_sp->GetValue()
126                  .GetScalar()
127                  .ULongLong(),
128              deallocate_error);
129 
130     m_persistent_variable_sp->m_live_sp.reset();
131 
132     if (!deallocate_error.Success()) {
133       err.SetErrorStringWithFormat(
134           "couldn't deallocate memory for %s: %s",
135           m_persistent_variable_sp->GetName().GetCString(),
136           deallocate_error.AsCString());
137     }
138   }
139 
140   void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
141                    lldb::addr_t process_address, Status &err) override {
142     Log *log = GetLog(LLDBLog::Expressions);
143 
144     const lldb::addr_t load_addr = process_address + m_offset;
145 
146     if (log) {
147       LLDB_LOGF(log,
148                 "EntityPersistentVariable::Materialize [address = 0x%" PRIx64
149                 ", m_name = %s, m_flags = 0x%hx]",
150                 (uint64_t)load_addr,
151                 m_persistent_variable_sp->GetName().AsCString(),
152                 m_persistent_variable_sp->m_flags);
153     }
154 
155     if (m_persistent_variable_sp->m_flags &
156         ExpressionVariable::EVNeedsAllocation) {
157       MakeAllocation(map, err);
158       m_persistent_variable_sp->m_flags |=
159           ExpressionVariable::EVIsLLDBAllocated;
160 
161       if (!err.Success())
162         return;
163     }
164 
165     if ((m_persistent_variable_sp->m_flags &
166              ExpressionVariable::EVIsProgramReference &&
167          m_persistent_variable_sp->m_live_sp) ||
168         m_persistent_variable_sp->m_flags &
169             ExpressionVariable::EVIsLLDBAllocated) {
170       Status write_error;
171 
172       map.WriteScalarToMemory(
173           load_addr,
174           m_persistent_variable_sp->m_live_sp->GetValue().GetScalar(),
175           map.GetAddressByteSize(), write_error);
176 
177       if (!write_error.Success()) {
178         err.SetErrorStringWithFormat(
179             "couldn't write the location of %s to memory: %s",
180             m_persistent_variable_sp->GetName().AsCString(),
181             write_error.AsCString());
182       }
183     } else {
184       err.SetErrorStringWithFormat(
185           "no materialization happened for persistent variable %s",
186           m_persistent_variable_sp->GetName().AsCString());
187       return;
188     }
189   }
190 
191   void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
192                      lldb::addr_t process_address, lldb::addr_t frame_top,
193                      lldb::addr_t frame_bottom, Status &err) override {
194     Log *log = GetLog(LLDBLog::Expressions);
195 
196     const lldb::addr_t load_addr = process_address + m_offset;
197 
198     if (log) {
199       LLDB_LOGF(log,
200                 "EntityPersistentVariable::Dematerialize [address = 0x%" PRIx64
201                 ", m_name = %s, m_flags = 0x%hx]",
202                 (uint64_t)process_address + m_offset,
203                 m_persistent_variable_sp->GetName().AsCString(),
204                 m_persistent_variable_sp->m_flags);
205     }
206 
207     if (m_delegate) {
208       m_delegate->DidDematerialize(m_persistent_variable_sp);
209     }
210 
211     if ((m_persistent_variable_sp->m_flags &
212          ExpressionVariable::EVIsLLDBAllocated) ||
213         (m_persistent_variable_sp->m_flags &
214          ExpressionVariable::EVIsProgramReference)) {
215       if (m_persistent_variable_sp->m_flags &
216               ExpressionVariable::EVIsProgramReference &&
217           !m_persistent_variable_sp->m_live_sp) {
218         // If the reference comes from the program, then the
219         // ClangExpressionVariable's live variable data hasn't been set up yet.
220         // Do this now.
221 
222         lldb::addr_t location;
223         Status read_error;
224 
225         map.ReadPointerFromMemory(&location, load_addr, read_error);
226 
227         if (!read_error.Success()) {
228           err.SetErrorStringWithFormat(
229               "couldn't read the address of program-allocated variable %s: %s",
230               m_persistent_variable_sp->GetName().GetCString(),
231               read_error.AsCString());
232           return;
233         }
234 
235         m_persistent_variable_sp->m_live_sp = ValueObjectConstResult::Create(
236             map.GetBestExecutionContextScope(),
237             m_persistent_variable_sp.get()->GetCompilerType(),
238             m_persistent_variable_sp->GetName(), location, eAddressTypeLoad,
239             m_persistent_variable_sp->GetByteSize().getValueOr(0));
240 
241         if (frame_top != LLDB_INVALID_ADDRESS &&
242             frame_bottom != LLDB_INVALID_ADDRESS && location >= frame_bottom &&
243             location <= frame_top) {
244           // If the variable is resident in the stack frame created by the
245           // expression, then it cannot be relied upon to stay around.  We
246           // treat it as needing reallocation.
247           m_persistent_variable_sp->m_flags |=
248               ExpressionVariable::EVIsLLDBAllocated;
249           m_persistent_variable_sp->m_flags |=
250               ExpressionVariable::EVNeedsAllocation;
251           m_persistent_variable_sp->m_flags |=
252               ExpressionVariable::EVNeedsFreezeDry;
253           m_persistent_variable_sp->m_flags &=
254               ~ExpressionVariable::EVIsProgramReference;
255         }
256       }
257 
258       lldb::addr_t mem = m_persistent_variable_sp->m_live_sp->GetValue()
259                              .GetScalar()
260                              .ULongLong();
261 
262       if (!m_persistent_variable_sp->m_live_sp) {
263         err.SetErrorStringWithFormat(
264             "couldn't find the memory area used to store %s",
265             m_persistent_variable_sp->GetName().GetCString());
266         return;
267       }
268 
269       if (m_persistent_variable_sp->m_live_sp->GetValue()
270               .GetValueAddressType() != eAddressTypeLoad) {
271         err.SetErrorStringWithFormat(
272             "the address of the memory area for %s is in an incorrect format",
273             m_persistent_variable_sp->GetName().GetCString());
274         return;
275       }
276 
277       if (m_persistent_variable_sp->m_flags &
278               ExpressionVariable::EVNeedsFreezeDry ||
279           m_persistent_variable_sp->m_flags &
280               ExpressionVariable::EVKeepInTarget) {
281         LLDB_LOGF(log, "Dematerializing %s from 0x%" PRIx64 " (size = %llu)",
282                   m_persistent_variable_sp->GetName().GetCString(),
283                   (uint64_t)mem,
284                   (unsigned long long)m_persistent_variable_sp->GetByteSize()
285                       .getValueOr(0));
286 
287         // Read the contents of the spare memory area
288 
289         m_persistent_variable_sp->ValueUpdated();
290 
291         Status read_error;
292 
293         map.ReadMemory(m_persistent_variable_sp->GetValueBytes(), mem,
294                        m_persistent_variable_sp->GetByteSize().getValueOr(0), read_error);
295 
296         if (!read_error.Success()) {
297           err.SetErrorStringWithFormat(
298               "couldn't read the contents of %s from memory: %s",
299               m_persistent_variable_sp->GetName().GetCString(),
300               read_error.AsCString());
301           return;
302         }
303 
304         m_persistent_variable_sp->m_flags &=
305             ~ExpressionVariable::EVNeedsFreezeDry;
306       }
307     } else {
308       err.SetErrorStringWithFormat(
309           "no dematerialization happened for persistent variable %s",
310           m_persistent_variable_sp->GetName().AsCString());
311       return;
312     }
313 
314     lldb::ProcessSP process_sp =
315         map.GetBestExecutionContextScope()->CalculateProcess();
316     if (!process_sp || !process_sp->CanJIT()) {
317       // Allocations are not persistent so persistent variables cannot stay
318       // materialized.
319 
320       m_persistent_variable_sp->m_flags |=
321           ExpressionVariable::EVNeedsAllocation;
322 
323       DestroyAllocation(map, err);
324       if (!err.Success())
325         return;
326     } else if (m_persistent_variable_sp->m_flags &
327                    ExpressionVariable::EVNeedsAllocation &&
328                !(m_persistent_variable_sp->m_flags &
329                  ExpressionVariable::EVKeepInTarget)) {
330       DestroyAllocation(map, err);
331       if (!err.Success())
332         return;
333     }
334   }
335 
336   void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
337                  Log *log) override {
338     StreamString dump_stream;
339 
340     Status err;
341 
342     const lldb::addr_t load_addr = process_address + m_offset;
343 
344     dump_stream.Printf("0x%" PRIx64 ": EntityPersistentVariable (%s)\n",
345                        load_addr,
346                        m_persistent_variable_sp->GetName().AsCString());
347 
348     {
349       dump_stream.Printf("Pointer:\n");
350 
351       DataBufferHeap data(m_size, 0);
352 
353       map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
354 
355       if (!err.Success()) {
356         dump_stream.Printf("  <could not be read>\n");
357       } else {
358         DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
359                      load_addr);
360 
361         dump_stream.PutChar('\n');
362       }
363     }
364 
365     {
366       dump_stream.Printf("Target:\n");
367 
368       lldb::addr_t target_address;
369 
370       map.ReadPointerFromMemory(&target_address, load_addr, err);
371 
372       if (!err.Success()) {
373         dump_stream.Printf("  <could not be read>\n");
374       } else {
375         DataBufferHeap data(
376             m_persistent_variable_sp->GetByteSize().getValueOr(0), 0);
377 
378         map.ReadMemory(data.GetBytes(), target_address,
379                        m_persistent_variable_sp->GetByteSize().getValueOr(0), err);
380 
381         if (!err.Success()) {
382           dump_stream.Printf("  <could not be read>\n");
383         } else {
384           DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
385                        target_address);
386 
387           dump_stream.PutChar('\n');
388         }
389       }
390     }
391 
392     log->PutString(dump_stream.GetString());
393   }
394 
395   void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {}
396 
397 private:
398   lldb::ExpressionVariableSP m_persistent_variable_sp;
399   Materializer::PersistentVariableDelegate *m_delegate;
400 };
401 
402 uint32_t Materializer::AddPersistentVariable(
403     lldb::ExpressionVariableSP &persistent_variable_sp,
404     PersistentVariableDelegate *delegate, Status &err) {
405   EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
406   *iter = std::make_unique<EntityPersistentVariable>(persistent_variable_sp,
407                                                      delegate);
408   uint32_t ret = AddStructMember(**iter);
409   (*iter)->SetOffset(ret);
410   return ret;
411 }
412 
413 class EntityVariable : public Materializer::Entity {
414 public:
415   EntityVariable(lldb::VariableSP &variable_sp)
416       : Entity(), m_variable_sp(variable_sp), m_is_reference(false),
417         m_temporary_allocation(LLDB_INVALID_ADDRESS),
418         m_temporary_allocation_size(0) {
419     // Hard-coding to maximum size of a pointer since all variables are
420     // materialized by reference
421     m_size = 8;
422     m_alignment = 8;
423     m_is_reference =
424         m_variable_sp->GetType()->GetForwardCompilerType().IsReferenceType();
425   }
426 
427   void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
428                    lldb::addr_t process_address, Status &err) override {
429     Log *log = GetLog(LLDBLog::Expressions);
430 
431     const lldb::addr_t load_addr = process_address + m_offset;
432     if (log) {
433       LLDB_LOGF(log,
434                 "EntityVariable::Materialize [address = 0x%" PRIx64
435                 ", m_variable_sp = %s]",
436                 (uint64_t)load_addr, m_variable_sp->GetName().AsCString());
437     }
438 
439     ExecutionContextScope *scope = frame_sp.get();
440 
441     if (!scope)
442       scope = map.GetBestExecutionContextScope();
443 
444     lldb::ValueObjectSP valobj_sp =
445         ValueObjectVariable::Create(scope, m_variable_sp);
446 
447     if (!valobj_sp) {
448       err.SetErrorStringWithFormat(
449           "couldn't get a value object for variable %s",
450           m_variable_sp->GetName().AsCString());
451       return;
452     }
453 
454     Status valobj_error = valobj_sp->GetError();
455 
456     if (valobj_error.Fail()) {
457       err.SetErrorStringWithFormat("couldn't get the value of variable %s: %s",
458                                    m_variable_sp->GetName().AsCString(),
459                                    valobj_error.AsCString());
460       return;
461     }
462 
463     if (m_is_reference) {
464       DataExtractor valobj_extractor;
465       Status extract_error;
466       valobj_sp->GetData(valobj_extractor, extract_error);
467 
468       if (!extract_error.Success()) {
469         err.SetErrorStringWithFormat(
470             "couldn't read contents of reference variable %s: %s",
471             m_variable_sp->GetName().AsCString(), extract_error.AsCString());
472         return;
473       }
474 
475       lldb::offset_t offset = 0;
476       lldb::addr_t reference_addr = valobj_extractor.GetAddress(&offset);
477 
478       Status write_error;
479       map.WritePointerToMemory(load_addr, reference_addr, write_error);
480 
481       if (!write_error.Success()) {
482         err.SetErrorStringWithFormat("couldn't write the contents of reference "
483                                      "variable %s to memory: %s",
484                                      m_variable_sp->GetName().AsCString(),
485                                      write_error.AsCString());
486         return;
487       }
488     } else {
489       AddressType address_type = eAddressTypeInvalid;
490       const bool scalar_is_load_address = false;
491       lldb::addr_t addr_of_valobj =
492           valobj_sp->GetAddressOf(scalar_is_load_address, &address_type);
493       if (addr_of_valobj != LLDB_INVALID_ADDRESS) {
494         Status write_error;
495         map.WritePointerToMemory(load_addr, addr_of_valobj, write_error);
496 
497         if (!write_error.Success()) {
498           err.SetErrorStringWithFormat(
499               "couldn't write the address of variable %s to memory: %s",
500               m_variable_sp->GetName().AsCString(), write_error.AsCString());
501           return;
502         }
503       } else {
504         DataExtractor data;
505         Status extract_error;
506         valobj_sp->GetData(data, extract_error);
507         if (!extract_error.Success()) {
508           err.SetErrorStringWithFormat("couldn't get the value of %s: %s",
509                                        m_variable_sp->GetName().AsCString(),
510                                        extract_error.AsCString());
511           return;
512         }
513 
514         if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
515           err.SetErrorStringWithFormat(
516               "trying to create a temporary region for %s but one exists",
517               m_variable_sp->GetName().AsCString());
518           return;
519         }
520 
521         if (data.GetByteSize() < m_variable_sp->GetType()->GetByteSize(scope)) {
522           if (data.GetByteSize() == 0 &&
523               !m_variable_sp->LocationExpression().IsValid()) {
524             err.SetErrorStringWithFormat("the variable '%s' has no location, "
525                                          "it may have been optimized out",
526                                          m_variable_sp->GetName().AsCString());
527           } else {
528             err.SetErrorStringWithFormat(
529                 "size of variable %s (%" PRIu64
530                 ") is larger than the ValueObject's size (%" PRIu64 ")",
531                 m_variable_sp->GetName().AsCString(),
532                 m_variable_sp->GetType()->GetByteSize(scope).getValueOr(0),
533                 data.GetByteSize());
534           }
535           return;
536         }
537 
538         llvm::Optional<size_t> opt_bit_align =
539             m_variable_sp->GetType()->GetLayoutCompilerType().GetTypeBitAlign(scope);
540         if (!opt_bit_align) {
541           err.SetErrorStringWithFormat("can't get the type alignment for %s",
542                                        m_variable_sp->GetName().AsCString());
543           return;
544         }
545 
546         size_t byte_align = (*opt_bit_align + 7) / 8;
547 
548         Status alloc_error;
549         const bool zero_memory = false;
550 
551         m_temporary_allocation = map.Malloc(
552             data.GetByteSize(), byte_align,
553             lldb::ePermissionsReadable | lldb::ePermissionsWritable,
554             IRMemoryMap::eAllocationPolicyMirror, zero_memory, alloc_error);
555 
556         m_temporary_allocation_size = data.GetByteSize();
557 
558         m_original_data = std::make_shared<DataBufferHeap>(data.GetDataStart(),
559                                                            data.GetByteSize());
560 
561         if (!alloc_error.Success()) {
562           err.SetErrorStringWithFormat(
563               "couldn't allocate a temporary region for %s: %s",
564               m_variable_sp->GetName().AsCString(), alloc_error.AsCString());
565           return;
566         }
567 
568         Status write_error;
569 
570         map.WriteMemory(m_temporary_allocation, data.GetDataStart(),
571                         data.GetByteSize(), write_error);
572 
573         if (!write_error.Success()) {
574           err.SetErrorStringWithFormat(
575               "couldn't write to the temporary region for %s: %s",
576               m_variable_sp->GetName().AsCString(), write_error.AsCString());
577           return;
578         }
579 
580         Status pointer_write_error;
581 
582         map.WritePointerToMemory(load_addr, m_temporary_allocation,
583                                  pointer_write_error);
584 
585         if (!pointer_write_error.Success()) {
586           err.SetErrorStringWithFormat(
587               "couldn't write the address of the temporary region for %s: %s",
588               m_variable_sp->GetName().AsCString(),
589               pointer_write_error.AsCString());
590         }
591       }
592     }
593   }
594 
595   void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
596                      lldb::addr_t process_address, lldb::addr_t frame_top,
597                      lldb::addr_t frame_bottom, Status &err) override {
598     Log *log = GetLog(LLDBLog::Expressions);
599 
600     const lldb::addr_t load_addr = process_address + m_offset;
601     if (log) {
602       LLDB_LOGF(log,
603                 "EntityVariable::Dematerialize [address = 0x%" PRIx64
604                 ", m_variable_sp = %s]",
605                 (uint64_t)load_addr, m_variable_sp->GetName().AsCString());
606     }
607 
608     if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
609       ExecutionContextScope *scope = frame_sp.get();
610 
611       if (!scope)
612         scope = map.GetBestExecutionContextScope();
613 
614       lldb::ValueObjectSP valobj_sp =
615           ValueObjectVariable::Create(scope, m_variable_sp);
616 
617       if (!valobj_sp) {
618         err.SetErrorStringWithFormat(
619             "couldn't get a value object for variable %s",
620             m_variable_sp->GetName().AsCString());
621         return;
622       }
623 
624       lldb_private::DataExtractor data;
625 
626       Status extract_error;
627 
628       map.GetMemoryData(data, m_temporary_allocation,
629                         valobj_sp->GetByteSize().getValueOr(0), extract_error);
630 
631       if (!extract_error.Success()) {
632         err.SetErrorStringWithFormat("couldn't get the data for variable %s",
633                                      m_variable_sp->GetName().AsCString());
634         return;
635       }
636 
637       bool actually_write = true;
638 
639       if (m_original_data) {
640         if ((data.GetByteSize() == m_original_data->GetByteSize()) &&
641             !memcmp(m_original_data->GetBytes(), data.GetDataStart(),
642                     data.GetByteSize())) {
643           actually_write = false;
644         }
645       }
646 
647       Status set_error;
648 
649       if (actually_write) {
650         valobj_sp->SetData(data, set_error);
651 
652         if (!set_error.Success()) {
653           err.SetErrorStringWithFormat(
654               "couldn't write the new contents of %s back into the variable",
655               m_variable_sp->GetName().AsCString());
656           return;
657         }
658       }
659 
660       Status free_error;
661 
662       map.Free(m_temporary_allocation, free_error);
663 
664       if (!free_error.Success()) {
665         err.SetErrorStringWithFormat(
666             "couldn't free the temporary region for %s: %s",
667             m_variable_sp->GetName().AsCString(), free_error.AsCString());
668         return;
669       }
670 
671       m_original_data.reset();
672       m_temporary_allocation = LLDB_INVALID_ADDRESS;
673       m_temporary_allocation_size = 0;
674     }
675   }
676 
677   void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
678                  Log *log) override {
679     StreamString dump_stream;
680 
681     const lldb::addr_t load_addr = process_address + m_offset;
682     dump_stream.Printf("0x%" PRIx64 ": EntityVariable\n", load_addr);
683 
684     Status err;
685 
686     lldb::addr_t ptr = LLDB_INVALID_ADDRESS;
687 
688     {
689       dump_stream.Printf("Pointer:\n");
690 
691       DataBufferHeap data(m_size, 0);
692 
693       map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
694 
695       if (!err.Success()) {
696         dump_stream.Printf("  <could not be read>\n");
697       } else {
698         DataExtractor extractor(data.GetBytes(), data.GetByteSize(),
699                                 map.GetByteOrder(), map.GetAddressByteSize());
700 
701         DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
702                      load_addr);
703 
704         lldb::offset_t offset = 0;
705 
706         ptr = extractor.GetAddress(&offset);
707 
708         dump_stream.PutChar('\n');
709       }
710     }
711 
712     if (m_temporary_allocation == LLDB_INVALID_ADDRESS) {
713       dump_stream.Printf("Points to process memory:\n");
714     } else {
715       dump_stream.Printf("Temporary allocation:\n");
716     }
717 
718     if (ptr == LLDB_INVALID_ADDRESS) {
719       dump_stream.Printf("  <could not be be found>\n");
720     } else {
721       DataBufferHeap data(m_temporary_allocation_size, 0);
722 
723       map.ReadMemory(data.GetBytes(), m_temporary_allocation,
724                      m_temporary_allocation_size, err);
725 
726       if (!err.Success()) {
727         dump_stream.Printf("  <could not be read>\n");
728       } else {
729         DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
730                      load_addr);
731 
732         dump_stream.PutChar('\n');
733       }
734     }
735 
736     log->PutString(dump_stream.GetString());
737   }
738 
739   void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {
740     if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
741       Status free_error;
742 
743       map.Free(m_temporary_allocation, free_error);
744 
745       m_temporary_allocation = LLDB_INVALID_ADDRESS;
746       m_temporary_allocation_size = 0;
747     }
748   }
749 
750 private:
751   lldb::VariableSP m_variable_sp;
752   bool m_is_reference;
753   lldb::addr_t m_temporary_allocation;
754   size_t m_temporary_allocation_size;
755   lldb::DataBufferSP m_original_data;
756 };
757 
758 uint32_t Materializer::AddVariable(lldb::VariableSP &variable_sp, Status &err) {
759   EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
760   *iter = std::make_unique<EntityVariable>(variable_sp);
761   uint32_t ret = AddStructMember(**iter);
762   (*iter)->SetOffset(ret);
763   return ret;
764 }
765 
766 class EntityResultVariable : public Materializer::Entity {
767 public:
768   EntityResultVariable(const CompilerType &type, bool is_program_reference,
769                        bool keep_in_memory,
770                        Materializer::PersistentVariableDelegate *delegate)
771       : Entity(), m_type(type), m_is_program_reference(is_program_reference),
772         m_keep_in_memory(keep_in_memory),
773         m_temporary_allocation(LLDB_INVALID_ADDRESS),
774         m_temporary_allocation_size(0), m_delegate(delegate) {
775     // Hard-coding to maximum size of a pointer since all results are
776     // materialized by reference
777     m_size = 8;
778     m_alignment = 8;
779   }
780 
781   void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
782                    lldb::addr_t process_address, Status &err) override {
783     if (!m_is_program_reference) {
784       if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
785         err.SetErrorString("Trying to create a temporary region for the result "
786                            "but one exists");
787         return;
788       }
789 
790       const lldb::addr_t load_addr = process_address + m_offset;
791 
792       ExecutionContextScope *exe_scope = frame_sp.get();
793       if (!exe_scope)
794         exe_scope = map.GetBestExecutionContextScope();
795 
796       llvm::Optional<uint64_t> byte_size = m_type.GetByteSize(exe_scope);
797       if (!byte_size) {
798         err.SetErrorStringWithFormat("can't get size of type \"%s\"",
799                                      m_type.GetTypeName().AsCString());
800         return;
801       }
802 
803       llvm::Optional<size_t> opt_bit_align = m_type.GetTypeBitAlign(exe_scope);
804       if (!opt_bit_align) {
805         err.SetErrorStringWithFormat("can't get the alignment of type  \"%s\"",
806                                      m_type.GetTypeName().AsCString());
807         return;
808       }
809 
810       size_t byte_align = (*opt_bit_align + 7) / 8;
811 
812       Status alloc_error;
813       const bool zero_memory = true;
814 
815       m_temporary_allocation = map.Malloc(
816           *byte_size, byte_align,
817           lldb::ePermissionsReadable | lldb::ePermissionsWritable,
818           IRMemoryMap::eAllocationPolicyMirror, zero_memory, alloc_error);
819       m_temporary_allocation_size = *byte_size;
820 
821       if (!alloc_error.Success()) {
822         err.SetErrorStringWithFormat(
823             "couldn't allocate a temporary region for the result: %s",
824             alloc_error.AsCString());
825         return;
826       }
827 
828       Status pointer_write_error;
829 
830       map.WritePointerToMemory(load_addr, m_temporary_allocation,
831                                pointer_write_error);
832 
833       if (!pointer_write_error.Success()) {
834         err.SetErrorStringWithFormat("couldn't write the address of the "
835                                      "temporary region for the result: %s",
836                                      pointer_write_error.AsCString());
837       }
838     }
839   }
840 
841   void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
842                      lldb::addr_t process_address, lldb::addr_t frame_top,
843                      lldb::addr_t frame_bottom, Status &err) override {
844     err.Clear();
845 
846     ExecutionContextScope *exe_scope = frame_sp.get();
847     if (!exe_scope)
848       exe_scope = map.GetBestExecutionContextScope();
849 
850     if (!exe_scope) {
851       err.SetErrorString("Couldn't dematerialize a result variable: invalid "
852                          "execution context scope");
853       return;
854     }
855 
856     lldb::addr_t address;
857     Status read_error;
858     const lldb::addr_t load_addr = process_address + m_offset;
859 
860     map.ReadPointerFromMemory(&address, load_addr, read_error);
861 
862     if (!read_error.Success()) {
863       err.SetErrorString("Couldn't dematerialize a result variable: couldn't "
864                          "read its address");
865       return;
866     }
867 
868     lldb::TargetSP target_sp = exe_scope->CalculateTarget();
869 
870     if (!target_sp) {
871       err.SetErrorString("Couldn't dematerialize a result variable: no target");
872       return;
873     }
874 
875     auto type_system_or_err =
876         target_sp->GetScratchTypeSystemForLanguage(m_type.GetMinimumLanguage());
877 
878     if (auto error = type_system_or_err.takeError()) {
879       err.SetErrorStringWithFormat("Couldn't dematerialize a result variable: "
880                                    "couldn't get the corresponding type "
881                                    "system: %s",
882                                    llvm::toString(std::move(error)).c_str());
883       return;
884     }
885     PersistentExpressionState *persistent_state =
886         type_system_or_err->GetPersistentExpressionState();
887 
888     if (!persistent_state) {
889       err.SetErrorString("Couldn't dematerialize a result variable: "
890                          "corresponding type system doesn't handle persistent "
891                          "variables");
892       return;
893     }
894 
895     ConstString name = m_delegate
896                            ? m_delegate->GetName()
897                            : persistent_state->GetNextPersistentVariableName();
898 
899     lldb::ExpressionVariableSP ret = persistent_state->CreatePersistentVariable(
900         exe_scope, name, m_type, map.GetByteOrder(), map.GetAddressByteSize());
901 
902     if (!ret) {
903       err.SetErrorStringWithFormat("couldn't dematerialize a result variable: "
904                                    "failed to make persistent variable %s",
905                                    name.AsCString());
906       return;
907     }
908 
909     lldb::ProcessSP process_sp =
910         map.GetBestExecutionContextScope()->CalculateProcess();
911 
912     if (m_delegate) {
913       m_delegate->DidDematerialize(ret);
914     }
915 
916     bool can_persist =
917         (m_is_program_reference && process_sp && process_sp->CanJIT() &&
918          !(address >= frame_bottom && address < frame_top));
919 
920     if (can_persist && m_keep_in_memory) {
921       ret->m_live_sp = ValueObjectConstResult::Create(exe_scope, m_type, name,
922                                                       address, eAddressTypeLoad,
923                                                       map.GetAddressByteSize());
924     }
925 
926     ret->ValueUpdated();
927 
928     const size_t pvar_byte_size = ret->GetByteSize().getValueOr(0);
929     uint8_t *pvar_data = ret->GetValueBytes();
930 
931     map.ReadMemory(pvar_data, address, pvar_byte_size, read_error);
932 
933     if (!read_error.Success()) {
934       err.SetErrorString(
935           "Couldn't dematerialize a result variable: couldn't read its memory");
936       return;
937     }
938 
939     if (!can_persist || !m_keep_in_memory) {
940       ret->m_flags |= ExpressionVariable::EVNeedsAllocation;
941 
942       if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
943         Status free_error;
944         map.Free(m_temporary_allocation, free_error);
945       }
946     } else {
947       ret->m_flags |= ExpressionVariable::EVIsLLDBAllocated;
948     }
949 
950     m_temporary_allocation = LLDB_INVALID_ADDRESS;
951     m_temporary_allocation_size = 0;
952   }
953 
954   void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
955                  Log *log) override {
956     StreamString dump_stream;
957 
958     const lldb::addr_t load_addr = process_address + m_offset;
959 
960     dump_stream.Printf("0x%" PRIx64 ": EntityResultVariable\n", load_addr);
961 
962     Status err;
963 
964     lldb::addr_t ptr = LLDB_INVALID_ADDRESS;
965 
966     {
967       dump_stream.Printf("Pointer:\n");
968 
969       DataBufferHeap data(m_size, 0);
970 
971       map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
972 
973       if (!err.Success()) {
974         dump_stream.Printf("  <could not be read>\n");
975       } else {
976         DataExtractor extractor(data.GetBytes(), data.GetByteSize(),
977                                 map.GetByteOrder(), map.GetAddressByteSize());
978 
979         DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
980                      load_addr);
981 
982         lldb::offset_t offset = 0;
983 
984         ptr = extractor.GetAddress(&offset);
985 
986         dump_stream.PutChar('\n');
987       }
988     }
989 
990     if (m_temporary_allocation == LLDB_INVALID_ADDRESS) {
991       dump_stream.Printf("Points to process memory:\n");
992     } else {
993       dump_stream.Printf("Temporary allocation:\n");
994     }
995 
996     if (ptr == LLDB_INVALID_ADDRESS) {
997       dump_stream.Printf("  <could not be be found>\n");
998     } else {
999       DataBufferHeap data(m_temporary_allocation_size, 0);
1000 
1001       map.ReadMemory(data.GetBytes(), m_temporary_allocation,
1002                      m_temporary_allocation_size, err);
1003 
1004       if (!err.Success()) {
1005         dump_stream.Printf("  <could not be read>\n");
1006       } else {
1007         DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
1008                      load_addr);
1009 
1010         dump_stream.PutChar('\n');
1011       }
1012     }
1013 
1014     log->PutString(dump_stream.GetString());
1015   }
1016 
1017   void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {
1018     if (!m_keep_in_memory && m_temporary_allocation != LLDB_INVALID_ADDRESS) {
1019       Status free_error;
1020 
1021       map.Free(m_temporary_allocation, free_error);
1022     }
1023 
1024     m_temporary_allocation = LLDB_INVALID_ADDRESS;
1025     m_temporary_allocation_size = 0;
1026   }
1027 
1028 private:
1029   CompilerType m_type;
1030   bool m_is_program_reference;
1031   bool m_keep_in_memory;
1032 
1033   lldb::addr_t m_temporary_allocation;
1034   size_t m_temporary_allocation_size;
1035   Materializer::PersistentVariableDelegate *m_delegate;
1036 };
1037 
1038 uint32_t Materializer::AddResultVariable(const CompilerType &type,
1039                                          bool is_program_reference,
1040                                          bool keep_in_memory,
1041                                          PersistentVariableDelegate *delegate,
1042                                          Status &err) {
1043   EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
1044   *iter = std::make_unique<EntityResultVariable>(type, is_program_reference,
1045                                                  keep_in_memory, delegate);
1046   uint32_t ret = AddStructMember(**iter);
1047   (*iter)->SetOffset(ret);
1048   return ret;
1049 }
1050 
1051 class EntitySymbol : public Materializer::Entity {
1052 public:
1053   EntitySymbol(const Symbol &symbol) : Entity(), m_symbol(symbol) {
1054     // Hard-coding to maximum size of a symbol
1055     m_size = 8;
1056     m_alignment = 8;
1057   }
1058 
1059   void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1060                    lldb::addr_t process_address, Status &err) override {
1061     Log *log = GetLog(LLDBLog::Expressions);
1062 
1063     const lldb::addr_t load_addr = process_address + m_offset;
1064 
1065     if (log) {
1066       LLDB_LOGF(log,
1067                 "EntitySymbol::Materialize [address = 0x%" PRIx64
1068                 ", m_symbol = %s]",
1069                 (uint64_t)load_addr, m_symbol.GetName().AsCString());
1070     }
1071 
1072     const Address sym_address = m_symbol.GetAddress();
1073 
1074     ExecutionContextScope *exe_scope = frame_sp.get();
1075     if (!exe_scope)
1076       exe_scope = map.GetBestExecutionContextScope();
1077 
1078     lldb::TargetSP target_sp;
1079 
1080     if (exe_scope)
1081       target_sp = map.GetBestExecutionContextScope()->CalculateTarget();
1082 
1083     if (!target_sp) {
1084       err.SetErrorStringWithFormat(
1085           "couldn't resolve symbol %s because there is no target",
1086           m_symbol.GetName().AsCString());
1087       return;
1088     }
1089 
1090     lldb::addr_t resolved_address = sym_address.GetLoadAddress(target_sp.get());
1091 
1092     if (resolved_address == LLDB_INVALID_ADDRESS)
1093       resolved_address = sym_address.GetFileAddress();
1094 
1095     Status pointer_write_error;
1096 
1097     map.WritePointerToMemory(load_addr, resolved_address, pointer_write_error);
1098 
1099     if (!pointer_write_error.Success()) {
1100       err.SetErrorStringWithFormat(
1101           "couldn't write the address of symbol %s: %s",
1102           m_symbol.GetName().AsCString(), pointer_write_error.AsCString());
1103       return;
1104     }
1105   }
1106 
1107   void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1108                      lldb::addr_t process_address, lldb::addr_t frame_top,
1109                      lldb::addr_t frame_bottom, Status &err) override {
1110     Log *log = GetLog(LLDBLog::Expressions);
1111 
1112     const lldb::addr_t load_addr = process_address + m_offset;
1113 
1114     if (log) {
1115       LLDB_LOGF(log,
1116                 "EntitySymbol::Dematerialize [address = 0x%" PRIx64
1117                 ", m_symbol = %s]",
1118                 (uint64_t)load_addr, m_symbol.GetName().AsCString());
1119     }
1120 
1121     // no work needs to be done
1122   }
1123 
1124   void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
1125                  Log *log) override {
1126     StreamString dump_stream;
1127 
1128     Status err;
1129 
1130     const lldb::addr_t load_addr = process_address + m_offset;
1131 
1132     dump_stream.Printf("0x%" PRIx64 ": EntitySymbol (%s)\n", load_addr,
1133                        m_symbol.GetName().AsCString());
1134 
1135     {
1136       dump_stream.Printf("Pointer:\n");
1137 
1138       DataBufferHeap data(m_size, 0);
1139 
1140       map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
1141 
1142       if (!err.Success()) {
1143         dump_stream.Printf("  <could not be read>\n");
1144       } else {
1145         DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
1146                      load_addr);
1147 
1148         dump_stream.PutChar('\n');
1149       }
1150     }
1151 
1152     log->PutString(dump_stream.GetString());
1153   }
1154 
1155   void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {}
1156 
1157 private:
1158   Symbol m_symbol;
1159 };
1160 
1161 uint32_t Materializer::AddSymbol(const Symbol &symbol_sp, Status &err) {
1162   EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
1163   *iter = std::make_unique<EntitySymbol>(symbol_sp);
1164   uint32_t ret = AddStructMember(**iter);
1165   (*iter)->SetOffset(ret);
1166   return ret;
1167 }
1168 
1169 class EntityRegister : public Materializer::Entity {
1170 public:
1171   EntityRegister(const RegisterInfo &register_info)
1172       : Entity(), m_register_info(register_info) {
1173     // Hard-coding alignment conservatively
1174     m_size = m_register_info.byte_size;
1175     m_alignment = m_register_info.byte_size;
1176   }
1177 
1178   void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1179                    lldb::addr_t process_address, Status &err) override {
1180     Log *log = GetLog(LLDBLog::Expressions);
1181 
1182     const lldb::addr_t load_addr = process_address + m_offset;
1183 
1184     if (log) {
1185       LLDB_LOGF(log,
1186                 "EntityRegister::Materialize [address = 0x%" PRIx64
1187                 ", m_register_info = %s]",
1188                 (uint64_t)load_addr, m_register_info.name);
1189     }
1190 
1191     RegisterValue reg_value;
1192 
1193     if (!frame_sp.get()) {
1194       err.SetErrorStringWithFormat(
1195           "couldn't materialize register %s without a stack frame",
1196           m_register_info.name);
1197       return;
1198     }
1199 
1200     lldb::RegisterContextSP reg_context_sp = frame_sp->GetRegisterContext();
1201 
1202     if (!reg_context_sp->ReadRegister(&m_register_info, reg_value)) {
1203       err.SetErrorStringWithFormat("couldn't read the value of register %s",
1204                                    m_register_info.name);
1205       return;
1206     }
1207 
1208     DataExtractor register_data;
1209 
1210     if (!reg_value.GetData(register_data)) {
1211       err.SetErrorStringWithFormat("couldn't get the data for register %s",
1212                                    m_register_info.name);
1213       return;
1214     }
1215 
1216     if (register_data.GetByteSize() != m_register_info.byte_size) {
1217       err.SetErrorStringWithFormat(
1218           "data for register %s had size %llu but we expected %llu",
1219           m_register_info.name, (unsigned long long)register_data.GetByteSize(),
1220           (unsigned long long)m_register_info.byte_size);
1221       return;
1222     }
1223 
1224     m_register_contents = std::make_shared<DataBufferHeap>(
1225         register_data.GetDataStart(), register_data.GetByteSize());
1226 
1227     Status write_error;
1228 
1229     map.WriteMemory(load_addr, register_data.GetDataStart(),
1230                     register_data.GetByteSize(), write_error);
1231 
1232     if (!write_error.Success()) {
1233       err.SetErrorStringWithFormat(
1234           "couldn't write the contents of register %s: %s",
1235           m_register_info.name, write_error.AsCString());
1236       return;
1237     }
1238   }
1239 
1240   void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1241                      lldb::addr_t process_address, lldb::addr_t frame_top,
1242                      lldb::addr_t frame_bottom, Status &err) override {
1243     Log *log = GetLog(LLDBLog::Expressions);
1244 
1245     const lldb::addr_t load_addr = process_address + m_offset;
1246 
1247     if (log) {
1248       LLDB_LOGF(log,
1249                 "EntityRegister::Dematerialize [address = 0x%" PRIx64
1250                 ", m_register_info = %s]",
1251                 (uint64_t)load_addr, m_register_info.name);
1252     }
1253 
1254     Status extract_error;
1255 
1256     DataExtractor register_data;
1257 
1258     if (!frame_sp.get()) {
1259       err.SetErrorStringWithFormat(
1260           "couldn't dematerialize register %s without a stack frame",
1261           m_register_info.name);
1262       return;
1263     }
1264 
1265     lldb::RegisterContextSP reg_context_sp = frame_sp->GetRegisterContext();
1266 
1267     map.GetMemoryData(register_data, load_addr, m_register_info.byte_size,
1268                       extract_error);
1269 
1270     if (!extract_error.Success()) {
1271       err.SetErrorStringWithFormat("couldn't get the data for register %s: %s",
1272                                    m_register_info.name,
1273                                    extract_error.AsCString());
1274       return;
1275     }
1276 
1277     if (!memcmp(register_data.GetDataStart(), m_register_contents->GetBytes(),
1278                 register_data.GetByteSize())) {
1279       // No write required, and in particular we avoid errors if the register
1280       // wasn't writable
1281 
1282       m_register_contents.reset();
1283       return;
1284     }
1285 
1286     m_register_contents.reset();
1287 
1288     RegisterValue register_value(register_data.GetData(),
1289                                  register_data.GetByteOrder());
1290 
1291     if (!reg_context_sp->WriteRegister(&m_register_info, register_value)) {
1292       err.SetErrorStringWithFormat("couldn't write the value of register %s",
1293                                    m_register_info.name);
1294       return;
1295     }
1296   }
1297 
1298   void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
1299                  Log *log) override {
1300     StreamString dump_stream;
1301 
1302     Status err;
1303 
1304     const lldb::addr_t load_addr = process_address + m_offset;
1305 
1306     dump_stream.Printf("0x%" PRIx64 ": EntityRegister (%s)\n", load_addr,
1307                        m_register_info.name);
1308 
1309     {
1310       dump_stream.Printf("Value:\n");
1311 
1312       DataBufferHeap data(m_size, 0);
1313 
1314       map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
1315 
1316       if (!err.Success()) {
1317         dump_stream.Printf("  <could not be read>\n");
1318       } else {
1319         DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
1320                      load_addr);
1321 
1322         dump_stream.PutChar('\n');
1323       }
1324     }
1325 
1326     log->PutString(dump_stream.GetString());
1327   }
1328 
1329   void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {}
1330 
1331 private:
1332   RegisterInfo m_register_info;
1333   lldb::DataBufferSP m_register_contents;
1334 };
1335 
1336 uint32_t Materializer::AddRegister(const RegisterInfo &register_info,
1337                                    Status &err) {
1338   EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
1339   *iter = std::make_unique<EntityRegister>(register_info);
1340   uint32_t ret = AddStructMember(**iter);
1341   (*iter)->SetOffset(ret);
1342   return ret;
1343 }
1344 
1345 Materializer::~Materializer() {
1346   DematerializerSP dematerializer_sp = m_dematerializer_wp.lock();
1347 
1348   if (dematerializer_sp)
1349     dematerializer_sp->Wipe();
1350 }
1351 
1352 Materializer::DematerializerSP
1353 Materializer::Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1354                           lldb::addr_t process_address, Status &error) {
1355   ExecutionContextScope *exe_scope = frame_sp.get();
1356   if (!exe_scope)
1357     exe_scope = map.GetBestExecutionContextScope();
1358 
1359   DematerializerSP dematerializer_sp = m_dematerializer_wp.lock();
1360 
1361   if (dematerializer_sp) {
1362     error.SetErrorToGenericError();
1363     error.SetErrorString("Couldn't materialize: already materialized");
1364   }
1365 
1366   DematerializerSP ret(
1367       new Dematerializer(*this, frame_sp, map, process_address));
1368 
1369   if (!exe_scope) {
1370     error.SetErrorToGenericError();
1371     error.SetErrorString("Couldn't materialize: target doesn't exist");
1372   }
1373 
1374   for (EntityUP &entity_up : m_entities) {
1375     entity_up->Materialize(frame_sp, map, process_address, error);
1376 
1377     if (!error.Success())
1378       return DematerializerSP();
1379   }
1380 
1381   if (Log *log = GetLog(LLDBLog::Expressions)) {
1382     LLDB_LOGF(
1383         log,
1384         "Materializer::Materialize (frame_sp = %p, process_address = 0x%" PRIx64
1385         ") materialized:",
1386         static_cast<void *>(frame_sp.get()), process_address);
1387     for (EntityUP &entity_up : m_entities)
1388       entity_up->DumpToLog(map, process_address, log);
1389   }
1390 
1391   m_dematerializer_wp = ret;
1392 
1393   return ret;
1394 }
1395 
1396 void Materializer::Dematerializer::Dematerialize(Status &error,
1397                                                  lldb::addr_t frame_bottom,
1398                                                  lldb::addr_t frame_top) {
1399   lldb::StackFrameSP frame_sp;
1400 
1401   lldb::ThreadSP thread_sp = m_thread_wp.lock();
1402   if (thread_sp)
1403     frame_sp = thread_sp->GetFrameWithStackID(m_stack_id);
1404 
1405   ExecutionContextScope *exe_scope = frame_sp.get();
1406   if (!exe_scope)
1407     exe_scope = m_map->GetBestExecutionContextScope();
1408 
1409   if (!IsValid()) {
1410     error.SetErrorToGenericError();
1411     error.SetErrorString("Couldn't dematerialize: invalid dematerializer");
1412   }
1413 
1414   if (!exe_scope) {
1415     error.SetErrorToGenericError();
1416     error.SetErrorString("Couldn't dematerialize: target is gone");
1417   } else {
1418     if (Log *log = GetLog(LLDBLog::Expressions)) {
1419       LLDB_LOGF(log,
1420                 "Materializer::Dematerialize (frame_sp = %p, process_address "
1421                 "= 0x%" PRIx64 ") about to dematerialize:",
1422                 static_cast<void *>(frame_sp.get()), m_process_address);
1423       for (EntityUP &entity_up : m_materializer->m_entities)
1424         entity_up->DumpToLog(*m_map, m_process_address, log);
1425     }
1426 
1427     for (EntityUP &entity_up : m_materializer->m_entities) {
1428       entity_up->Dematerialize(frame_sp, *m_map, m_process_address, frame_top,
1429                                frame_bottom, error);
1430 
1431       if (!error.Success())
1432         break;
1433     }
1434   }
1435 
1436   Wipe();
1437 }
1438 
1439 void Materializer::Dematerializer::Wipe() {
1440   if (!IsValid())
1441     return;
1442 
1443   for (EntityUP &entity_up : m_materializer->m_entities) {
1444     entity_up->Wipe(*m_map, m_process_address);
1445   }
1446 
1447   m_materializer = nullptr;
1448   m_map = nullptr;
1449   m_process_address = LLDB_INVALID_ADDRESS;
1450 }
1451 
1452 Materializer::PersistentVariableDelegate::~PersistentVariableDelegate() =
1453     default;
1454