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