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