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