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