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         llvm::Optional<size_t> opt_bit_align =
534             m_variable_sp->GetType()->GetLayoutCompilerType().GetTypeBitAlign(scope);
535         if (!opt_bit_align) {
536           err.SetErrorStringWithFormat("can't get the type alignment for %s",
537                                        m_variable_sp->GetName().AsCString());
538           return;
539         }
540 
541         size_t byte_align = (*opt_bit_align + 7) / 8;
542 
543         Status alloc_error;
544         const bool zero_memory = false;
545 
546         m_temporary_allocation = map.Malloc(
547             data.GetByteSize(), byte_align,
548             lldb::ePermissionsReadable | lldb::ePermissionsWritable,
549             IRMemoryMap::eAllocationPolicyMirror, zero_memory, alloc_error);
550 
551         m_temporary_allocation_size = data.GetByteSize();
552 
553         m_original_data = std::make_shared<DataBufferHeap>(data.GetDataStart(),
554                                                            data.GetByteSize());
555 
556         if (!alloc_error.Success()) {
557           err.SetErrorStringWithFormat(
558               "couldn't allocate a temporary region for %s: %s",
559               m_variable_sp->GetName().AsCString(), alloc_error.AsCString());
560           return;
561         }
562 
563         Status write_error;
564 
565         map.WriteMemory(m_temporary_allocation, data.GetDataStart(),
566                         data.GetByteSize(), write_error);
567 
568         if (!write_error.Success()) {
569           err.SetErrorStringWithFormat(
570               "couldn't write to the temporary region for %s: %s",
571               m_variable_sp->GetName().AsCString(), write_error.AsCString());
572           return;
573         }
574 
575         Status pointer_write_error;
576 
577         map.WritePointerToMemory(load_addr, m_temporary_allocation,
578                                  pointer_write_error);
579 
580         if (!pointer_write_error.Success()) {
581           err.SetErrorStringWithFormat(
582               "couldn't write the address of the temporary region for %s: %s",
583               m_variable_sp->GetName().AsCString(),
584               pointer_write_error.AsCString());
585         }
586       }
587     }
588   }
589 
590   void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
591                      lldb::addr_t process_address, lldb::addr_t frame_top,
592                      lldb::addr_t frame_bottom, Status &err) override {
593     Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
594 
595     const lldb::addr_t load_addr = process_address + m_offset;
596     if (log) {
597       LLDB_LOGF(log,
598                 "EntityVariable::Dematerialize [address = 0x%" PRIx64
599                 ", m_variable_sp = %s]",
600                 (uint64_t)load_addr, m_variable_sp->GetName().AsCString());
601     }
602 
603     if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
604       ExecutionContextScope *scope = frame_sp.get();
605 
606       if (!scope)
607         scope = map.GetBestExecutionContextScope();
608 
609       lldb::ValueObjectSP valobj_sp =
610           ValueObjectVariable::Create(scope, m_variable_sp);
611 
612       if (!valobj_sp) {
613         err.SetErrorStringWithFormat(
614             "couldn't get a value object for variable %s",
615             m_variable_sp->GetName().AsCString());
616         return;
617       }
618 
619       lldb_private::DataExtractor data;
620 
621       Status extract_error;
622 
623       map.GetMemoryData(data, m_temporary_allocation, valobj_sp->GetByteSize(),
624                         extract_error);
625 
626       if (!extract_error.Success()) {
627         err.SetErrorStringWithFormat("couldn't get the data for variable %s",
628                                      m_variable_sp->GetName().AsCString());
629         return;
630       }
631 
632       bool actually_write = true;
633 
634       if (m_original_data) {
635         if ((data.GetByteSize() == m_original_data->GetByteSize()) &&
636             !memcmp(m_original_data->GetBytes(), data.GetDataStart(),
637                     data.GetByteSize())) {
638           actually_write = false;
639         }
640       }
641 
642       Status set_error;
643 
644       if (actually_write) {
645         valobj_sp->SetData(data, set_error);
646 
647         if (!set_error.Success()) {
648           err.SetErrorStringWithFormat(
649               "couldn't write the new contents of %s back into the variable",
650               m_variable_sp->GetName().AsCString());
651           return;
652         }
653       }
654 
655       Status free_error;
656 
657       map.Free(m_temporary_allocation, free_error);
658 
659       if (!free_error.Success()) {
660         err.SetErrorStringWithFormat(
661             "couldn't free the temporary region for %s: %s",
662             m_variable_sp->GetName().AsCString(), free_error.AsCString());
663         return;
664       }
665 
666       m_original_data.reset();
667       m_temporary_allocation = LLDB_INVALID_ADDRESS;
668       m_temporary_allocation_size = 0;
669     }
670   }
671 
672   void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
673                  Log *log) override {
674     StreamString dump_stream;
675 
676     const lldb::addr_t load_addr = process_address + m_offset;
677     dump_stream.Printf("0x%" PRIx64 ": EntityVariable\n", load_addr);
678 
679     Status err;
680 
681     lldb::addr_t ptr = LLDB_INVALID_ADDRESS;
682 
683     {
684       dump_stream.Printf("Pointer:\n");
685 
686       DataBufferHeap data(m_size, 0);
687 
688       map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
689 
690       if (!err.Success()) {
691         dump_stream.Printf("  <could not be read>\n");
692       } else {
693         DataExtractor extractor(data.GetBytes(), data.GetByteSize(),
694                                 map.GetByteOrder(), map.GetAddressByteSize());
695 
696         DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
697                      load_addr);
698 
699         lldb::offset_t offset;
700 
701         ptr = extractor.GetPointer(&offset);
702 
703         dump_stream.PutChar('\n');
704       }
705     }
706 
707     if (m_temporary_allocation == LLDB_INVALID_ADDRESS) {
708       dump_stream.Printf("Points to process memory:\n");
709     } else {
710       dump_stream.Printf("Temporary allocation:\n");
711     }
712 
713     if (ptr == LLDB_INVALID_ADDRESS) {
714       dump_stream.Printf("  <could not be be found>\n");
715     } else {
716       DataBufferHeap data(m_temporary_allocation_size, 0);
717 
718       map.ReadMemory(data.GetBytes(), m_temporary_allocation,
719                      m_temporary_allocation_size, err);
720 
721       if (!err.Success()) {
722         dump_stream.Printf("  <could not be read>\n");
723       } else {
724         DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
725                      load_addr);
726 
727         dump_stream.PutChar('\n');
728       }
729     }
730 
731     log->PutString(dump_stream.GetString());
732   }
733 
734   void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {
735     if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
736       Status free_error;
737 
738       map.Free(m_temporary_allocation, free_error);
739 
740       m_temporary_allocation = LLDB_INVALID_ADDRESS;
741       m_temporary_allocation_size = 0;
742     }
743   }
744 
745 private:
746   lldb::VariableSP m_variable_sp;
747   bool m_is_reference;
748   lldb::addr_t m_temporary_allocation;
749   size_t m_temporary_allocation_size;
750   lldb::DataBufferSP m_original_data;
751 };
752 
753 uint32_t Materializer::AddVariable(lldb::VariableSP &variable_sp, Status &err) {
754   EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
755   iter->reset(new EntityVariable(variable_sp));
756   uint32_t ret = AddStructMember(**iter);
757   (*iter)->SetOffset(ret);
758   return ret;
759 }
760 
761 class EntityResultVariable : public Materializer::Entity {
762 public:
763   EntityResultVariable(const CompilerType &type, bool is_program_reference,
764                        bool keep_in_memory,
765                        Materializer::PersistentVariableDelegate *delegate)
766       : Entity(), m_type(type), m_is_program_reference(is_program_reference),
767         m_keep_in_memory(keep_in_memory),
768         m_temporary_allocation(LLDB_INVALID_ADDRESS),
769         m_temporary_allocation_size(0), m_delegate(delegate) {
770     // Hard-coding to maximum size of a pointer since all results are
771     // materialized by reference
772     m_size = 8;
773     m_alignment = 8;
774   }
775 
776   void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
777                    lldb::addr_t process_address, Status &err) override {
778     if (!m_is_program_reference) {
779       if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
780         err.SetErrorString("Trying to create a temporary region for the result "
781                            "but one exists");
782         return;
783       }
784 
785       const lldb::addr_t load_addr = process_address + m_offset;
786 
787       ExecutionContextScope *exe_scope = map.GetBestExecutionContextScope();
788 
789       llvm::Optional<uint64_t> byte_size = m_type.GetByteSize(exe_scope);
790       if (!byte_size) {
791         err.SetErrorString("can't get size of type");
792         return;
793       }
794 
795       llvm::Optional<size_t> opt_bit_align = m_type.GetTypeBitAlign(exe_scope);
796       if (!opt_bit_align) {
797         err.SetErrorStringWithFormat("can't get the type alignment");
798         return;
799       }
800 
801       size_t byte_align = (*opt_bit_align + 7) / 8;
802 
803       Status alloc_error;
804       const bool zero_memory = true;
805 
806       m_temporary_allocation = map.Malloc(
807           *byte_size, byte_align,
808           lldb::ePermissionsReadable | lldb::ePermissionsWritable,
809           IRMemoryMap::eAllocationPolicyMirror, zero_memory, alloc_error);
810       m_temporary_allocation_size = *byte_size;
811 
812       if (!alloc_error.Success()) {
813         err.SetErrorStringWithFormat(
814             "couldn't allocate a temporary region for the result: %s",
815             alloc_error.AsCString());
816         return;
817       }
818 
819       Status pointer_write_error;
820 
821       map.WritePointerToMemory(load_addr, m_temporary_allocation,
822                                pointer_write_error);
823 
824       if (!pointer_write_error.Success()) {
825         err.SetErrorStringWithFormat("couldn't write the address of the "
826                                      "temporary region for the result: %s",
827                                      pointer_write_error.AsCString());
828       }
829     }
830   }
831 
832   void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
833                      lldb::addr_t process_address, lldb::addr_t frame_top,
834                      lldb::addr_t frame_bottom, Status &err) override {
835     err.Clear();
836 
837     ExecutionContextScope *exe_scope = map.GetBestExecutionContextScope();
838 
839     if (!exe_scope) {
840       err.SetErrorString("Couldn't dematerialize a result variable: invalid "
841                          "execution context scope");
842       return;
843     }
844 
845     lldb::addr_t address;
846     Status read_error;
847     const lldb::addr_t load_addr = process_address + m_offset;
848 
849     map.ReadPointerFromMemory(&address, load_addr, read_error);
850 
851     if (!read_error.Success()) {
852       err.SetErrorString("Couldn't dematerialize a result variable: couldn't "
853                          "read its address");
854       return;
855     }
856 
857     lldb::TargetSP target_sp = exe_scope->CalculateTarget();
858 
859     if (!target_sp) {
860       err.SetErrorString("Couldn't dematerialize a result variable: no target");
861       return;
862     }
863 
864     auto type_system_or_err =
865         target_sp->GetScratchTypeSystemForLanguage(m_type.GetMinimumLanguage());
866 
867     if (auto error = type_system_or_err.takeError()) {
868       err.SetErrorStringWithFormat("Couldn't dematerialize a result variable: "
869                                    "couldn't get the corresponding type "
870                                    "system: %s",
871                                    llvm::toString(std::move(error)).c_str());
872       return;
873     }
874     PersistentExpressionState *persistent_state =
875         type_system_or_err->GetPersistentExpressionState();
876 
877     if (!persistent_state) {
878       err.SetErrorString("Couldn't dematerialize a result variable: "
879                          "corresponding type system doesn't handle persistent "
880                          "variables");
881       return;
882     }
883 
884     ConstString name =
885         m_delegate
886             ? m_delegate->GetName()
887             : persistent_state->GetNextPersistentVariableName(
888                   *target_sp, persistent_state->GetPersistentVariablePrefix());
889 
890     lldb::ExpressionVariableSP ret = persistent_state->CreatePersistentVariable(
891         exe_scope, name, m_type, map.GetByteOrder(), map.GetAddressByteSize());
892 
893     if (!ret) {
894       err.SetErrorStringWithFormat("couldn't dematerialize a result variable: "
895                                    "failed to make persistent variable %s",
896                                    name.AsCString());
897       return;
898     }
899 
900     lldb::ProcessSP process_sp =
901         map.GetBestExecutionContextScope()->CalculateProcess();
902 
903     if (m_delegate) {
904       m_delegate->DidDematerialize(ret);
905     }
906 
907     bool can_persist =
908         (m_is_program_reference && process_sp && process_sp->CanJIT() &&
909          !(address >= frame_bottom && address < frame_top));
910 
911     if (can_persist && m_keep_in_memory) {
912       ret->m_live_sp = ValueObjectConstResult::Create(exe_scope, m_type, name,
913                                                       address, eAddressTypeLoad,
914                                                       map.GetAddressByteSize());
915     }
916 
917     ret->ValueUpdated();
918 
919     const size_t pvar_byte_size = ret->GetByteSize();
920     uint8_t *pvar_data = ret->GetValueBytes();
921 
922     map.ReadMemory(pvar_data, address, pvar_byte_size, read_error);
923 
924     if (!read_error.Success()) {
925       err.SetErrorString(
926           "Couldn't dematerialize a result variable: couldn't read its memory");
927       return;
928     }
929 
930     if (!can_persist || !m_keep_in_memory) {
931       ret->m_flags |= ExpressionVariable::EVNeedsAllocation;
932 
933       if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
934         Status free_error;
935         map.Free(m_temporary_allocation, free_error);
936       }
937     } else {
938       ret->m_flags |= ExpressionVariable::EVIsLLDBAllocated;
939     }
940 
941     m_temporary_allocation = LLDB_INVALID_ADDRESS;
942     m_temporary_allocation_size = 0;
943   }
944 
945   void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
946                  Log *log) override {
947     StreamString dump_stream;
948 
949     const lldb::addr_t load_addr = process_address + m_offset;
950 
951     dump_stream.Printf("0x%" PRIx64 ": EntityResultVariable\n", load_addr);
952 
953     Status err;
954 
955     lldb::addr_t ptr = LLDB_INVALID_ADDRESS;
956 
957     {
958       dump_stream.Printf("Pointer:\n");
959 
960       DataBufferHeap data(m_size, 0);
961 
962       map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
963 
964       if (!err.Success()) {
965         dump_stream.Printf("  <could not be read>\n");
966       } else {
967         DataExtractor extractor(data.GetBytes(), data.GetByteSize(),
968                                 map.GetByteOrder(), map.GetAddressByteSize());
969 
970         DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
971                      load_addr);
972 
973         lldb::offset_t offset;
974 
975         ptr = extractor.GetPointer(&offset);
976 
977         dump_stream.PutChar('\n');
978       }
979     }
980 
981     if (m_temporary_allocation == LLDB_INVALID_ADDRESS) {
982       dump_stream.Printf("Points to process memory:\n");
983     } else {
984       dump_stream.Printf("Temporary allocation:\n");
985     }
986 
987     if (ptr == LLDB_INVALID_ADDRESS) {
988       dump_stream.Printf("  <could not be be found>\n");
989     } else {
990       DataBufferHeap data(m_temporary_allocation_size, 0);
991 
992       map.ReadMemory(data.GetBytes(), m_temporary_allocation,
993                      m_temporary_allocation_size, err);
994 
995       if (!err.Success()) {
996         dump_stream.Printf("  <could not be read>\n");
997       } else {
998         DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
999                      load_addr);
1000 
1001         dump_stream.PutChar('\n');
1002       }
1003     }
1004 
1005     log->PutString(dump_stream.GetString());
1006   }
1007 
1008   void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {
1009     if (!m_keep_in_memory && m_temporary_allocation != LLDB_INVALID_ADDRESS) {
1010       Status free_error;
1011 
1012       map.Free(m_temporary_allocation, free_error);
1013     }
1014 
1015     m_temporary_allocation = LLDB_INVALID_ADDRESS;
1016     m_temporary_allocation_size = 0;
1017   }
1018 
1019 private:
1020   CompilerType m_type;
1021   bool m_is_program_reference;
1022   bool m_keep_in_memory;
1023 
1024   lldb::addr_t m_temporary_allocation;
1025   size_t m_temporary_allocation_size;
1026   Materializer::PersistentVariableDelegate *m_delegate;
1027 };
1028 
1029 uint32_t Materializer::AddResultVariable(const CompilerType &type,
1030                                          bool is_program_reference,
1031                                          bool keep_in_memory,
1032                                          PersistentVariableDelegate *delegate,
1033                                          Status &err) {
1034   EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
1035   iter->reset(new EntityResultVariable(type, is_program_reference,
1036                                        keep_in_memory, delegate));
1037   uint32_t ret = AddStructMember(**iter);
1038   (*iter)->SetOffset(ret);
1039   return ret;
1040 }
1041 
1042 class EntitySymbol : public Materializer::Entity {
1043 public:
1044   EntitySymbol(const Symbol &symbol) : Entity(), m_symbol(symbol) {
1045     // Hard-coding to maximum size of a symbol
1046     m_size = 8;
1047     m_alignment = 8;
1048   }
1049 
1050   void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1051                    lldb::addr_t process_address, Status &err) override {
1052     Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
1053 
1054     const lldb::addr_t load_addr = process_address + m_offset;
1055 
1056     if (log) {
1057       LLDB_LOGF(log,
1058                 "EntitySymbol::Materialize [address = 0x%" PRIx64
1059                 ", m_symbol = %s]",
1060                 (uint64_t)load_addr, m_symbol.GetName().AsCString());
1061     }
1062 
1063     const Address sym_address = m_symbol.GetAddress();
1064 
1065     ExecutionContextScope *exe_scope = map.GetBestExecutionContextScope();
1066 
1067     lldb::TargetSP target_sp;
1068 
1069     if (exe_scope)
1070       target_sp = map.GetBestExecutionContextScope()->CalculateTarget();
1071 
1072     if (!target_sp) {
1073       err.SetErrorStringWithFormat(
1074           "couldn't resolve symbol %s because there is no target",
1075           m_symbol.GetName().AsCString());
1076       return;
1077     }
1078 
1079     lldb::addr_t resolved_address = sym_address.GetLoadAddress(target_sp.get());
1080 
1081     if (resolved_address == LLDB_INVALID_ADDRESS)
1082       resolved_address = sym_address.GetFileAddress();
1083 
1084     Status pointer_write_error;
1085 
1086     map.WritePointerToMemory(load_addr, resolved_address, pointer_write_error);
1087 
1088     if (!pointer_write_error.Success()) {
1089       err.SetErrorStringWithFormat(
1090           "couldn't write the address of symbol %s: %s",
1091           m_symbol.GetName().AsCString(), pointer_write_error.AsCString());
1092       return;
1093     }
1094   }
1095 
1096   void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1097                      lldb::addr_t process_address, lldb::addr_t frame_top,
1098                      lldb::addr_t frame_bottom, Status &err) override {
1099     Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
1100 
1101     const lldb::addr_t load_addr = process_address + m_offset;
1102 
1103     if (log) {
1104       LLDB_LOGF(log,
1105                 "EntitySymbol::Dematerialize [address = 0x%" PRIx64
1106                 ", m_symbol = %s]",
1107                 (uint64_t)load_addr, m_symbol.GetName().AsCString());
1108     }
1109 
1110     // no work needs to be done
1111   }
1112 
1113   void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
1114                  Log *log) override {
1115     StreamString dump_stream;
1116 
1117     Status err;
1118 
1119     const lldb::addr_t load_addr = process_address + m_offset;
1120 
1121     dump_stream.Printf("0x%" PRIx64 ": EntitySymbol (%s)\n", load_addr,
1122                        m_symbol.GetName().AsCString());
1123 
1124     {
1125       dump_stream.Printf("Pointer:\n");
1126 
1127       DataBufferHeap data(m_size, 0);
1128 
1129       map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
1130 
1131       if (!err.Success()) {
1132         dump_stream.Printf("  <could not be read>\n");
1133       } else {
1134         DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
1135                      load_addr);
1136 
1137         dump_stream.PutChar('\n');
1138       }
1139     }
1140 
1141     log->PutString(dump_stream.GetString());
1142   }
1143 
1144   void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {}
1145 
1146 private:
1147   Symbol m_symbol;
1148 };
1149 
1150 uint32_t Materializer::AddSymbol(const Symbol &symbol_sp, Status &err) {
1151   EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
1152   iter->reset(new EntitySymbol(symbol_sp));
1153   uint32_t ret = AddStructMember(**iter);
1154   (*iter)->SetOffset(ret);
1155   return ret;
1156 }
1157 
1158 class EntityRegister : public Materializer::Entity {
1159 public:
1160   EntityRegister(const RegisterInfo &register_info)
1161       : Entity(), m_register_info(register_info) {
1162     // Hard-coding alignment conservatively
1163     m_size = m_register_info.byte_size;
1164     m_alignment = m_register_info.byte_size;
1165   }
1166 
1167   void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1168                    lldb::addr_t process_address, Status &err) override {
1169     Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
1170 
1171     const lldb::addr_t load_addr = process_address + m_offset;
1172 
1173     if (log) {
1174       LLDB_LOGF(log,
1175                 "EntityRegister::Materialize [address = 0x%" PRIx64
1176                 ", m_register_info = %s]",
1177                 (uint64_t)load_addr, m_register_info.name);
1178     }
1179 
1180     RegisterValue reg_value;
1181 
1182     if (!frame_sp.get()) {
1183       err.SetErrorStringWithFormat(
1184           "couldn't materialize register %s without a stack frame",
1185           m_register_info.name);
1186       return;
1187     }
1188 
1189     lldb::RegisterContextSP reg_context_sp = frame_sp->GetRegisterContext();
1190 
1191     if (!reg_context_sp->ReadRegister(&m_register_info, reg_value)) {
1192       err.SetErrorStringWithFormat("couldn't read the value of register %s",
1193                                    m_register_info.name);
1194       return;
1195     }
1196 
1197     DataExtractor register_data;
1198 
1199     if (!reg_value.GetData(register_data)) {
1200       err.SetErrorStringWithFormat("couldn't get the data for register %s",
1201                                    m_register_info.name);
1202       return;
1203     }
1204 
1205     if (register_data.GetByteSize() != m_register_info.byte_size) {
1206       err.SetErrorStringWithFormat(
1207           "data for register %s had size %llu but we expected %llu",
1208           m_register_info.name, (unsigned long long)register_data.GetByteSize(),
1209           (unsigned long long)m_register_info.byte_size);
1210       return;
1211     }
1212 
1213     m_register_contents = std::make_shared<DataBufferHeap>(
1214         register_data.GetDataStart(), register_data.GetByteSize());
1215 
1216     Status write_error;
1217 
1218     map.WriteMemory(load_addr, register_data.GetDataStart(),
1219                     register_data.GetByteSize(), write_error);
1220 
1221     if (!write_error.Success()) {
1222       err.SetErrorStringWithFormat(
1223           "couldn't write the contents of register %s: %s",
1224           m_register_info.name, write_error.AsCString());
1225       return;
1226     }
1227   }
1228 
1229   void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1230                      lldb::addr_t process_address, lldb::addr_t frame_top,
1231                      lldb::addr_t frame_bottom, Status &err) override {
1232     Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
1233 
1234     const lldb::addr_t load_addr = process_address + m_offset;
1235 
1236     if (log) {
1237       LLDB_LOGF(log,
1238                 "EntityRegister::Dematerialize [address = 0x%" PRIx64
1239                 ", m_register_info = %s]",
1240                 (uint64_t)load_addr, m_register_info.name);
1241     }
1242 
1243     Status extract_error;
1244 
1245     DataExtractor register_data;
1246 
1247     if (!frame_sp.get()) {
1248       err.SetErrorStringWithFormat(
1249           "couldn't dematerialize register %s without a stack frame",
1250           m_register_info.name);
1251       return;
1252     }
1253 
1254     lldb::RegisterContextSP reg_context_sp = frame_sp->GetRegisterContext();
1255 
1256     map.GetMemoryData(register_data, load_addr, m_register_info.byte_size,
1257                       extract_error);
1258 
1259     if (!extract_error.Success()) {
1260       err.SetErrorStringWithFormat("couldn't get the data for register %s: %s",
1261                                    m_register_info.name,
1262                                    extract_error.AsCString());
1263       return;
1264     }
1265 
1266     if (!memcmp(register_data.GetDataStart(), m_register_contents->GetBytes(),
1267                 register_data.GetByteSize())) {
1268       // No write required, and in particular we avoid errors if the register
1269       // wasn't writable
1270 
1271       m_register_contents.reset();
1272       return;
1273     }
1274 
1275     m_register_contents.reset();
1276 
1277     RegisterValue register_value(
1278         const_cast<uint8_t *>(register_data.GetDataStart()),
1279         register_data.GetByteSize(), register_data.GetByteOrder());
1280 
1281     if (!reg_context_sp->WriteRegister(&m_register_info, register_value)) {
1282       err.SetErrorStringWithFormat("couldn't write the value of register %s",
1283                                    m_register_info.name);
1284       return;
1285     }
1286   }
1287 
1288   void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
1289                  Log *log) override {
1290     StreamString dump_stream;
1291 
1292     Status err;
1293 
1294     const lldb::addr_t load_addr = process_address + m_offset;
1295 
1296     dump_stream.Printf("0x%" PRIx64 ": EntityRegister (%s)\n", load_addr,
1297                        m_register_info.name);
1298 
1299     {
1300       dump_stream.Printf("Value:\n");
1301 
1302       DataBufferHeap data(m_size, 0);
1303 
1304       map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
1305 
1306       if (!err.Success()) {
1307         dump_stream.Printf("  <could not be read>\n");
1308       } else {
1309         DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
1310                      load_addr);
1311 
1312         dump_stream.PutChar('\n');
1313       }
1314     }
1315 
1316     log->PutString(dump_stream.GetString());
1317   }
1318 
1319   void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {}
1320 
1321 private:
1322   RegisterInfo m_register_info;
1323   lldb::DataBufferSP m_register_contents;
1324 };
1325 
1326 uint32_t Materializer::AddRegister(const RegisterInfo &register_info,
1327                                    Status &err) {
1328   EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
1329   iter->reset(new EntityRegister(register_info));
1330   uint32_t ret = AddStructMember(**iter);
1331   (*iter)->SetOffset(ret);
1332   return ret;
1333 }
1334 
1335 Materializer::Materializer()
1336     : m_dematerializer_wp(), m_current_offset(0), m_struct_alignment(8) {}
1337 
1338 Materializer::~Materializer() {
1339   DematerializerSP dematerializer_sp = m_dematerializer_wp.lock();
1340 
1341   if (dematerializer_sp)
1342     dematerializer_sp->Wipe();
1343 }
1344 
1345 Materializer::DematerializerSP
1346 Materializer::Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1347                           lldb::addr_t process_address, Status &error) {
1348   ExecutionContextScope *exe_scope = frame_sp.get();
1349 
1350   if (!exe_scope)
1351     exe_scope = map.GetBestExecutionContextScope();
1352 
1353   DematerializerSP dematerializer_sp = m_dematerializer_wp.lock();
1354 
1355   if (dematerializer_sp) {
1356     error.SetErrorToGenericError();
1357     error.SetErrorString("Couldn't materialize: already materialized");
1358   }
1359 
1360   DematerializerSP ret(
1361       new Dematerializer(*this, frame_sp, map, process_address));
1362 
1363   if (!exe_scope) {
1364     error.SetErrorToGenericError();
1365     error.SetErrorString("Couldn't materialize: target doesn't exist");
1366   }
1367 
1368   for (EntityUP &entity_up : m_entities) {
1369     entity_up->Materialize(frame_sp, map, process_address, error);
1370 
1371     if (!error.Success())
1372       return DematerializerSP();
1373   }
1374 
1375   if (Log *log =
1376           lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)) {
1377     LLDB_LOGF(
1378         log,
1379         "Materializer::Materialize (frame_sp = %p, process_address = 0x%" PRIx64
1380         ") materialized:",
1381         static_cast<void *>(frame_sp.get()), process_address);
1382     for (EntityUP &entity_up : m_entities)
1383       entity_up->DumpToLog(map, process_address, log);
1384   }
1385 
1386   m_dematerializer_wp = ret;
1387 
1388   return ret;
1389 }
1390 
1391 void Materializer::Dematerializer::Dematerialize(Status &error,
1392                                                  lldb::addr_t frame_bottom,
1393                                                  lldb::addr_t frame_top) {
1394   lldb::StackFrameSP frame_sp;
1395 
1396   lldb::ThreadSP thread_sp = m_thread_wp.lock();
1397   if (thread_sp)
1398     frame_sp = thread_sp->GetFrameWithStackID(m_stack_id);
1399 
1400   ExecutionContextScope *exe_scope = m_map->GetBestExecutionContextScope();
1401 
1402   if (!IsValid()) {
1403     error.SetErrorToGenericError();
1404     error.SetErrorString("Couldn't dematerialize: invalid dematerializer");
1405   }
1406 
1407   if (!exe_scope) {
1408     error.SetErrorToGenericError();
1409     error.SetErrorString("Couldn't dematerialize: target is gone");
1410   } else {
1411     if (Log *log =
1412             lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)) {
1413       LLDB_LOGF(log,
1414                 "Materializer::Dematerialize (frame_sp = %p, process_address "
1415                 "= 0x%" PRIx64 ") about to dematerialize:",
1416                 static_cast<void *>(frame_sp.get()), m_process_address);
1417       for (EntityUP &entity_up : m_materializer->m_entities)
1418         entity_up->DumpToLog(*m_map, m_process_address, log);
1419     }
1420 
1421     for (EntityUP &entity_up : m_materializer->m_entities) {
1422       entity_up->Dematerialize(frame_sp, *m_map, m_process_address, frame_top,
1423                                frame_bottom, error);
1424 
1425       if (!error.Success())
1426         break;
1427     }
1428   }
1429 
1430   Wipe();
1431 }
1432 
1433 void Materializer::Dematerializer::Wipe() {
1434   if (!IsValid())
1435     return;
1436 
1437   for (EntityUP &entity_up : m_materializer->m_entities) {
1438     entity_up->Wipe(*m_map, m_process_address);
1439   }
1440 
1441   m_materializer = nullptr;
1442   m_map = nullptr;
1443   m_process_address = LLDB_INVALID_ADDRESS;
1444 }
1445 
1446 Materializer::PersistentVariableDelegate::~PersistentVariableDelegate() =
1447     default;
1448