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     Status type_system_error;
873     TypeSystem *type_system = target_sp->GetScratchTypeSystemForLanguage(
874         &type_system_error, m_type.GetMinimumLanguage());
875 
876     if (!type_system) {
877       err.SetErrorStringWithFormat("Couldn't dematerialize a result variable: "
878                                    "couldn't get the corresponding type "
879                                    "system: %s",
880                                    type_system_error.AsCString());
881       return;
882     }
883 
884     PersistentExpressionState *persistent_state =
885         type_system->GetPersistentExpressionState();
886 
887     if (!persistent_state) {
888       err.SetErrorString("Couldn't dematerialize a result variable: "
889                          "corresponding type system doesn't handle persistent "
890                          "variables");
891       return;
892     }
893 
894     ConstString name =
895         m_delegate
896             ? m_delegate->GetName()
897             : persistent_state->GetNextPersistentVariableName(
898                   *target_sp, persistent_state->GetPersistentVariablePrefix());
899 
900     lldb::ExpressionVariableSP ret = persistent_state->CreatePersistentVariable(
901         exe_scope, name, m_type, map.GetByteOrder(), map.GetAddressByteSize());
902 
903     if (!ret) {
904       err.SetErrorStringWithFormat("couldn't dematerialize a result variable: "
905                                    "failed to make persistent variable %s",
906                                    name.AsCString());
907       return;
908     }
909 
910     lldb::ProcessSP process_sp =
911         map.GetBestExecutionContextScope()->CalculateProcess();
912 
913     if (m_delegate) {
914       m_delegate->DidDematerialize(ret);
915     }
916 
917     bool can_persist =
918         (m_is_program_reference && process_sp && process_sp->CanJIT() &&
919          !(address >= frame_bottom && address < frame_top));
920 
921     if (can_persist && m_keep_in_memory) {
922       ret->m_live_sp = ValueObjectConstResult::Create(exe_scope, m_type, name,
923                                                       address, eAddressTypeLoad,
924                                                       map.GetAddressByteSize());
925     }
926 
927     ret->ValueUpdated();
928 
929     const size_t pvar_byte_size = ret->GetByteSize();
930     uint8_t *pvar_data = ret->GetValueBytes();
931 
932     map.ReadMemory(pvar_data, address, pvar_byte_size, read_error);
933 
934     if (!read_error.Success()) {
935       err.SetErrorString(
936           "Couldn't dematerialize a result variable: couldn't read its memory");
937       return;
938     }
939 
940     if (!can_persist || !m_keep_in_memory) {
941       ret->m_flags |= ExpressionVariable::EVNeedsAllocation;
942 
943       if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
944         Status free_error;
945         map.Free(m_temporary_allocation, free_error);
946       }
947     } else {
948       ret->m_flags |= ExpressionVariable::EVIsLLDBAllocated;
949     }
950 
951     m_temporary_allocation = LLDB_INVALID_ADDRESS;
952     m_temporary_allocation_size = 0;
953   }
954 
955   void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
956                  Log *log) override {
957     StreamString dump_stream;
958 
959     const lldb::addr_t load_addr = process_address + m_offset;
960 
961     dump_stream.Printf("0x%" PRIx64 ": EntityResultVariable\n", load_addr);
962 
963     Status err;
964 
965     lldb::addr_t ptr = LLDB_INVALID_ADDRESS;
966 
967     {
968       dump_stream.Printf("Pointer:\n");
969 
970       DataBufferHeap data(m_size, 0);
971 
972       map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
973 
974       if (!err.Success()) {
975         dump_stream.Printf("  <could not be read>\n");
976       } else {
977         DataExtractor extractor(data.GetBytes(), data.GetByteSize(),
978                                 map.GetByteOrder(), map.GetAddressByteSize());
979 
980         DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
981                      load_addr);
982 
983         lldb::offset_t offset;
984 
985         ptr = extractor.GetPointer(&offset);
986 
987         dump_stream.PutChar('\n');
988       }
989     }
990 
991     if (m_temporary_allocation == LLDB_INVALID_ADDRESS) {
992       dump_stream.Printf("Points to process memory:\n");
993     } else {
994       dump_stream.Printf("Temporary allocation:\n");
995     }
996 
997     if (ptr == LLDB_INVALID_ADDRESS) {
998       dump_stream.Printf("  <could not be be found>\n");
999     } else {
1000       DataBufferHeap data(m_temporary_allocation_size, 0);
1001 
1002       map.ReadMemory(data.GetBytes(), m_temporary_allocation,
1003                      m_temporary_allocation_size, err);
1004 
1005       if (!err.Success()) {
1006         dump_stream.Printf("  <could not be read>\n");
1007       } else {
1008         DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
1009                      load_addr);
1010 
1011         dump_stream.PutChar('\n');
1012       }
1013     }
1014 
1015     log->PutString(dump_stream.GetString());
1016   }
1017 
1018   void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {
1019     if (!m_keep_in_memory && m_temporary_allocation != LLDB_INVALID_ADDRESS) {
1020       Status free_error;
1021 
1022       map.Free(m_temporary_allocation, free_error);
1023     }
1024 
1025     m_temporary_allocation = LLDB_INVALID_ADDRESS;
1026     m_temporary_allocation_size = 0;
1027   }
1028 
1029 private:
1030   CompilerType m_type;
1031   bool m_is_program_reference;
1032   bool m_keep_in_memory;
1033 
1034   lldb::addr_t m_temporary_allocation;
1035   size_t m_temporary_allocation_size;
1036   Materializer::PersistentVariableDelegate *m_delegate;
1037 };
1038 
1039 uint32_t Materializer::AddResultVariable(const CompilerType &type,
1040                                          bool is_program_reference,
1041                                          bool keep_in_memory,
1042                                          PersistentVariableDelegate *delegate,
1043                                          Status &err) {
1044   EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
1045   iter->reset(new EntityResultVariable(type, is_program_reference,
1046                                        keep_in_memory, delegate));
1047   uint32_t ret = AddStructMember(**iter);
1048   (*iter)->SetOffset(ret);
1049   return ret;
1050 }
1051 
1052 class EntitySymbol : public Materializer::Entity {
1053 public:
1054   EntitySymbol(const Symbol &symbol) : Entity(), m_symbol(symbol) {
1055     // Hard-coding to maximum size of a symbol
1056     m_size = 8;
1057     m_alignment = 8;
1058   }
1059 
1060   void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1061                    lldb::addr_t process_address, Status &err) override {
1062     Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
1063 
1064     const lldb::addr_t load_addr = process_address + m_offset;
1065 
1066     if (log) {
1067       LLDB_LOGF(log,
1068                 "EntitySymbol::Materialize [address = 0x%" PRIx64
1069                 ", m_symbol = %s]",
1070                 (uint64_t)load_addr, m_symbol.GetName().AsCString());
1071     }
1072 
1073     const Address sym_address = m_symbol.GetAddress();
1074 
1075     ExecutionContextScope *exe_scope = map.GetBestExecutionContextScope();
1076 
1077     lldb::TargetSP target_sp;
1078 
1079     if (exe_scope)
1080       target_sp = map.GetBestExecutionContextScope()->CalculateTarget();
1081 
1082     if (!target_sp) {
1083       err.SetErrorStringWithFormat(
1084           "couldn't resolve symbol %s because there is no target",
1085           m_symbol.GetName().AsCString());
1086       return;
1087     }
1088 
1089     lldb::addr_t resolved_address = sym_address.GetLoadAddress(target_sp.get());
1090 
1091     if (resolved_address == LLDB_INVALID_ADDRESS)
1092       resolved_address = sym_address.GetFileAddress();
1093 
1094     Status pointer_write_error;
1095 
1096     map.WritePointerToMemory(load_addr, resolved_address, pointer_write_error);
1097 
1098     if (!pointer_write_error.Success()) {
1099       err.SetErrorStringWithFormat(
1100           "couldn't write the address of symbol %s: %s",
1101           m_symbol.GetName().AsCString(), pointer_write_error.AsCString());
1102       return;
1103     }
1104   }
1105 
1106   void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1107                      lldb::addr_t process_address, lldb::addr_t frame_top,
1108                      lldb::addr_t frame_bottom, Status &err) override {
1109     Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
1110 
1111     const lldb::addr_t load_addr = process_address + m_offset;
1112 
1113     if (log) {
1114       LLDB_LOGF(log,
1115                 "EntitySymbol::Dematerialize [address = 0x%" PRIx64
1116                 ", m_symbol = %s]",
1117                 (uint64_t)load_addr, m_symbol.GetName().AsCString());
1118     }
1119 
1120     // no work needs to be done
1121   }
1122 
1123   void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
1124                  Log *log) override {
1125     StreamString dump_stream;
1126 
1127     Status err;
1128 
1129     const lldb::addr_t load_addr = process_address + m_offset;
1130 
1131     dump_stream.Printf("0x%" PRIx64 ": EntitySymbol (%s)\n", load_addr,
1132                        m_symbol.GetName().AsCString());
1133 
1134     {
1135       dump_stream.Printf("Pointer:\n");
1136 
1137       DataBufferHeap data(m_size, 0);
1138 
1139       map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
1140 
1141       if (!err.Success()) {
1142         dump_stream.Printf("  <could not be read>\n");
1143       } else {
1144         DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
1145                      load_addr);
1146 
1147         dump_stream.PutChar('\n');
1148       }
1149     }
1150 
1151     log->PutString(dump_stream.GetString());
1152   }
1153 
1154   void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {}
1155 
1156 private:
1157   Symbol m_symbol;
1158 };
1159 
1160 uint32_t Materializer::AddSymbol(const Symbol &symbol_sp, Status &err) {
1161   EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
1162   iter->reset(new EntitySymbol(symbol_sp));
1163   uint32_t ret = AddStructMember(**iter);
1164   (*iter)->SetOffset(ret);
1165   return ret;
1166 }
1167 
1168 class EntityRegister : public Materializer::Entity {
1169 public:
1170   EntityRegister(const RegisterInfo &register_info)
1171       : Entity(), m_register_info(register_info) {
1172     // Hard-coding alignment conservatively
1173     m_size = m_register_info.byte_size;
1174     m_alignment = m_register_info.byte_size;
1175   }
1176 
1177   void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1178                    lldb::addr_t process_address, Status &err) override {
1179     Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
1180 
1181     const lldb::addr_t load_addr = process_address + m_offset;
1182 
1183     if (log) {
1184       LLDB_LOGF(log,
1185                 "EntityRegister::Materialize [address = 0x%" PRIx64
1186                 ", m_register_info = %s]",
1187                 (uint64_t)load_addr, m_register_info.name);
1188     }
1189 
1190     RegisterValue reg_value;
1191 
1192     if (!frame_sp.get()) {
1193       err.SetErrorStringWithFormat(
1194           "couldn't materialize register %s without a stack frame",
1195           m_register_info.name);
1196       return;
1197     }
1198 
1199     lldb::RegisterContextSP reg_context_sp = frame_sp->GetRegisterContext();
1200 
1201     if (!reg_context_sp->ReadRegister(&m_register_info, reg_value)) {
1202       err.SetErrorStringWithFormat("couldn't read the value of register %s",
1203                                    m_register_info.name);
1204       return;
1205     }
1206 
1207     DataExtractor register_data;
1208 
1209     if (!reg_value.GetData(register_data)) {
1210       err.SetErrorStringWithFormat("couldn't get the data for register %s",
1211                                    m_register_info.name);
1212       return;
1213     }
1214 
1215     if (register_data.GetByteSize() != m_register_info.byte_size) {
1216       err.SetErrorStringWithFormat(
1217           "data for register %s had size %llu but we expected %llu",
1218           m_register_info.name, (unsigned long long)register_data.GetByteSize(),
1219           (unsigned long long)m_register_info.byte_size);
1220       return;
1221     }
1222 
1223     m_register_contents = std::make_shared<DataBufferHeap>(
1224         register_data.GetDataStart(), register_data.GetByteSize());
1225 
1226     Status write_error;
1227 
1228     map.WriteMemory(load_addr, register_data.GetDataStart(),
1229                     register_data.GetByteSize(), write_error);
1230 
1231     if (!write_error.Success()) {
1232       err.SetErrorStringWithFormat(
1233           "couldn't write the contents of register %s: %s",
1234           m_register_info.name, write_error.AsCString());
1235       return;
1236     }
1237   }
1238 
1239   void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1240                      lldb::addr_t process_address, lldb::addr_t frame_top,
1241                      lldb::addr_t frame_bottom, Status &err) override {
1242     Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
1243 
1244     const lldb::addr_t load_addr = process_address + m_offset;
1245 
1246     if (log) {
1247       LLDB_LOGF(log,
1248                 "EntityRegister::Dematerialize [address = 0x%" PRIx64
1249                 ", m_register_info = %s]",
1250                 (uint64_t)load_addr, m_register_info.name);
1251     }
1252 
1253     Status extract_error;
1254 
1255     DataExtractor register_data;
1256 
1257     if (!frame_sp.get()) {
1258       err.SetErrorStringWithFormat(
1259           "couldn't dematerialize register %s without a stack frame",
1260           m_register_info.name);
1261       return;
1262     }
1263 
1264     lldb::RegisterContextSP reg_context_sp = frame_sp->GetRegisterContext();
1265 
1266     map.GetMemoryData(register_data, load_addr, m_register_info.byte_size,
1267                       extract_error);
1268 
1269     if (!extract_error.Success()) {
1270       err.SetErrorStringWithFormat("couldn't get the data for register %s: %s",
1271                                    m_register_info.name,
1272                                    extract_error.AsCString());
1273       return;
1274     }
1275 
1276     if (!memcmp(register_data.GetDataStart(), m_register_contents->GetBytes(),
1277                 register_data.GetByteSize())) {
1278       // No write required, and in particular we avoid errors if the register
1279       // wasn't writable
1280 
1281       m_register_contents.reset();
1282       return;
1283     }
1284 
1285     m_register_contents.reset();
1286 
1287     RegisterValue register_value(
1288         const_cast<uint8_t *>(register_data.GetDataStart()),
1289         register_data.GetByteSize(), register_data.GetByteOrder());
1290 
1291     if (!reg_context_sp->WriteRegister(&m_register_info, register_value)) {
1292       err.SetErrorStringWithFormat("couldn't write the value of register %s",
1293                                    m_register_info.name);
1294       return;
1295     }
1296   }
1297 
1298   void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
1299                  Log *log) override {
1300     StreamString dump_stream;
1301 
1302     Status err;
1303 
1304     const lldb::addr_t load_addr = process_address + m_offset;
1305 
1306     dump_stream.Printf("0x%" PRIx64 ": EntityRegister (%s)\n", load_addr,
1307                        m_register_info.name);
1308 
1309     {
1310       dump_stream.Printf("Value:\n");
1311 
1312       DataBufferHeap data(m_size, 0);
1313 
1314       map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
1315 
1316       if (!err.Success()) {
1317         dump_stream.Printf("  <could not be read>\n");
1318       } else {
1319         DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
1320                      load_addr);
1321 
1322         dump_stream.PutChar('\n');
1323       }
1324     }
1325 
1326     log->PutString(dump_stream.GetString());
1327   }
1328 
1329   void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {}
1330 
1331 private:
1332   RegisterInfo m_register_info;
1333   lldb::DataBufferSP m_register_contents;
1334 };
1335 
1336 uint32_t Materializer::AddRegister(const RegisterInfo &register_info,
1337                                    Status &err) {
1338   EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
1339   iter->reset(new EntityRegister(register_info));
1340   uint32_t ret = AddStructMember(**iter);
1341   (*iter)->SetOffset(ret);
1342   return ret;
1343 }
1344 
1345 Materializer::Materializer()
1346     : m_dematerializer_wp(), m_current_offset(0), m_struct_alignment(8) {}
1347 
1348 Materializer::~Materializer() {
1349   DematerializerSP dematerializer_sp = m_dematerializer_wp.lock();
1350 
1351   if (dematerializer_sp)
1352     dematerializer_sp->Wipe();
1353 }
1354 
1355 Materializer::DematerializerSP
1356 Materializer::Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1357                           lldb::addr_t process_address, Status &error) {
1358   ExecutionContextScope *exe_scope = frame_sp.get();
1359 
1360   if (!exe_scope)
1361     exe_scope = map.GetBestExecutionContextScope();
1362 
1363   DematerializerSP dematerializer_sp = m_dematerializer_wp.lock();
1364 
1365   if (dematerializer_sp) {
1366     error.SetErrorToGenericError();
1367     error.SetErrorString("Couldn't materialize: already materialized");
1368   }
1369 
1370   DematerializerSP ret(
1371       new Dematerializer(*this, frame_sp, map, process_address));
1372 
1373   if (!exe_scope) {
1374     error.SetErrorToGenericError();
1375     error.SetErrorString("Couldn't materialize: target doesn't exist");
1376   }
1377 
1378   for (EntityUP &entity_up : m_entities) {
1379     entity_up->Materialize(frame_sp, map, process_address, error);
1380 
1381     if (!error.Success())
1382       return DematerializerSP();
1383   }
1384 
1385   if (Log *log =
1386           lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)) {
1387     LLDB_LOGF(
1388         log,
1389         "Materializer::Materialize (frame_sp = %p, process_address = 0x%" PRIx64
1390         ") materialized:",
1391         static_cast<void *>(frame_sp.get()), process_address);
1392     for (EntityUP &entity_up : m_entities)
1393       entity_up->DumpToLog(map, process_address, log);
1394   }
1395 
1396   m_dematerializer_wp = ret;
1397 
1398   return ret;
1399 }
1400 
1401 void Materializer::Dematerializer::Dematerialize(Status &error,
1402                                                  lldb::addr_t frame_bottom,
1403                                                  lldb::addr_t frame_top) {
1404   lldb::StackFrameSP frame_sp;
1405 
1406   lldb::ThreadSP thread_sp = m_thread_wp.lock();
1407   if (thread_sp)
1408     frame_sp = thread_sp->GetFrameWithStackID(m_stack_id);
1409 
1410   ExecutionContextScope *exe_scope = m_map->GetBestExecutionContextScope();
1411 
1412   if (!IsValid()) {
1413     error.SetErrorToGenericError();
1414     error.SetErrorString("Couldn't dematerialize: invalid dematerializer");
1415   }
1416 
1417   if (!exe_scope) {
1418     error.SetErrorToGenericError();
1419     error.SetErrorString("Couldn't dematerialize: target is gone");
1420   } else {
1421     if (Log *log =
1422             lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)) {
1423       LLDB_LOGF(log,
1424                 "Materializer::Dematerialize (frame_sp = %p, process_address "
1425                 "= 0x%" PRIx64 ") about to dematerialize:",
1426                 static_cast<void *>(frame_sp.get()), m_process_address);
1427       for (EntityUP &entity_up : m_materializer->m_entities)
1428         entity_up->DumpToLog(*m_map, m_process_address, log);
1429     }
1430 
1431     for (EntityUP &entity_up : m_materializer->m_entities) {
1432       entity_up->Dematerialize(frame_sp, *m_map, m_process_address, frame_top,
1433                                frame_bottom, error);
1434 
1435       if (!error.Success())
1436         break;
1437     }
1438   }
1439 
1440   Wipe();
1441 }
1442 
1443 void Materializer::Dematerializer::Wipe() {
1444   if (!IsValid())
1445     return;
1446 
1447   for (EntityUP &entity_up : m_materializer->m_entities) {
1448     entity_up->Wipe(*m_map, m_process_address);
1449   }
1450 
1451   m_materializer = nullptr;
1452   m_map = nullptr;
1453   m_process_address = LLDB_INVALID_ADDRESS;
1454 }
1455 
1456 Materializer::PersistentVariableDelegate::~PersistentVariableDelegate() =
1457     default;
1458