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