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