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