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