1//===-- Materializer.cpp ----------------------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "lldb/Expression/Materializer.h"
10#include "lldb/Core/DumpDataExtractor.h"
11#include "lldb/Core/ValueObjectConstResult.h"
12#include "lldb/Core/ValueObjectVariable.h"
13#include "lldb/Expression/ExpressionVariable.h"
14#include "lldb/Symbol/Symbol.h"
15#include "lldb/Symbol/Type.h"
16#include "lldb/Symbol/Variable.h"
17#include "lldb/Target/ExecutionContext.h"
18#include "lldb/Target/RegisterContext.h"
19#include "lldb/Target/StackFrame.h"
20#include "lldb/Target/Target.h"
21#include "lldb/Target/Thread.h"
22#include "lldb/Utility/Log.h"
23#include "lldb/Utility/RegisterValue.h"
24
25#include <memory>
26
27using namespace lldb_private;
28
29uint32_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
48class EntityPersistentVariable : public Materializer::Entity {
49public:
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
393private:
394  lldb::ExpressionVariableSP m_persistent_variable_sp;
395  Materializer::PersistentVariableDelegate *m_delegate;
396};
397
398uint32_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->reset(new EntityPersistentVariable(persistent_variable_sp, delegate));
403  uint32_t ret = AddStructMember(**iter);
404  (*iter)->SetOffset(ret);
405  return ret;
406}
407
408class EntityVariable : public Materializer::Entity {
409public:
410  EntityVariable(lldb::VariableSP &variable_sp)
411      : Entity(), m_variable_sp(variable_sp), m_is_reference(false),
412        m_temporary_allocation(LLDB_INVALID_ADDRESS),
413        m_temporary_allocation_size(0) {
414    // Hard-coding to maximum size of a pointer since all variables are
415    // materialized by reference
416    m_size = 8;
417    m_alignment = 8;
418    m_is_reference =
419        m_variable_sp->GetType()->GetForwardCompilerType().IsReferenceType();
420  }
421
422  void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
423                   lldb::addr_t process_address, Status &err) override {
424    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
425
426    const lldb::addr_t load_addr = process_address + m_offset;
427    if (log) {
428      LLDB_LOGF(log,
429                "EntityVariable::Materialize [address = 0x%" PRIx64
430                ", m_variable_sp = %s]",
431                (uint64_t)load_addr, m_variable_sp->GetName().AsCString());
432    }
433
434    ExecutionContextScope *scope = frame_sp.get();
435
436    if (!scope)
437      scope = map.GetBestExecutionContextScope();
438
439    lldb::ValueObjectSP valobj_sp =
440        ValueObjectVariable::Create(scope, m_variable_sp);
441
442    if (!valobj_sp) {
443      err.SetErrorStringWithFormat(
444          "couldn't get a value object for variable %s",
445          m_variable_sp->GetName().AsCString());
446      return;
447    }
448
449    Status valobj_error = valobj_sp->GetError();
450
451    if (valobj_error.Fail()) {
452      err.SetErrorStringWithFormat("couldn't get the value of variable %s: %s",
453                                   m_variable_sp->GetName().AsCString(),
454                                   valobj_error.AsCString());
455      return;
456    }
457
458    if (m_is_reference) {
459      DataExtractor valobj_extractor;
460      Status extract_error;
461      valobj_sp->GetData(valobj_extractor, extract_error);
462
463      if (!extract_error.Success()) {
464        err.SetErrorStringWithFormat(
465            "couldn't read contents of reference variable %s: %s",
466            m_variable_sp->GetName().AsCString(), extract_error.AsCString());
467        return;
468      }
469
470      lldb::offset_t offset = 0;
471      lldb::addr_t reference_addr = valobj_extractor.GetAddress(&offset);
472
473      Status write_error;
474      map.WritePointerToMemory(load_addr, reference_addr, write_error);
475
476      if (!write_error.Success()) {
477        err.SetErrorStringWithFormat("couldn't write the contents of reference "
478                                     "variable %s to memory: %s",
479                                     m_variable_sp->GetName().AsCString(),
480                                     write_error.AsCString());
481        return;
482      }
483    } else {
484      AddressType address_type = eAddressTypeInvalid;
485      const bool scalar_is_load_address = false;
486      lldb::addr_t addr_of_valobj =
487          valobj_sp->GetAddressOf(scalar_is_load_address, &address_type);
488      if (addr_of_valobj != LLDB_INVALID_ADDRESS) {
489        Status write_error;
490        map.WritePointerToMemory(load_addr, addr_of_valobj, write_error);
491
492        if (!write_error.Success()) {
493          err.SetErrorStringWithFormat(
494              "couldn't write the address of variable %s to memory: %s",
495              m_variable_sp->GetName().AsCString(), write_error.AsCString());
496          return;
497        }
498      } else {
499        DataExtractor data;
500        Status extract_error;
501        valobj_sp->GetData(data, extract_error);
502        if (!extract_error.Success()) {
503          err.SetErrorStringWithFormat("couldn't get the value of %s: %s",
504                                       m_variable_sp->GetName().AsCString(),
505                                       extract_error.AsCString());
506          return;
507        }
508
509        if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
510          err.SetErrorStringWithFormat(
511              "trying to create a temporary region for %s but one exists",
512              m_variable_sp->GetName().AsCString());
513          return;
514        }
515
516        if (data.GetByteSize() < m_variable_sp->GetType()->GetByteSize()) {
517          if (data.GetByteSize() == 0 &&
518              !m_variable_sp->LocationExpression().IsValid()) {
519            err.SetErrorStringWithFormat("the variable '%s' has no location, "
520                                         "it may have been optimized out",
521                                         m_variable_sp->GetName().AsCString());
522          } else {
523            err.SetErrorStringWithFormat(
524                "size of variable %s (%" PRIu64
525                ") is larger than the ValueObject's size (%" PRIu64 ")",
526                m_variable_sp->GetName().AsCString(),
527                m_variable_sp->GetType()->GetByteSize().getValueOr(0),
528                data.GetByteSize());
529          }
530          return;
531        }
532
533        llvm::Optional<size_t> opt_bit_align =
534            m_variable_sp->GetType()->GetLayoutCompilerType().GetTypeBitAlign(scope);
535        if (!opt_bit_align) {
536          err.SetErrorStringWithFormat("can't get the type alignment for %s",
537                                       m_variable_sp->GetName().AsCString());
538          return;
539        }
540
541        size_t byte_align = (*opt_bit_align + 7) / 8;
542
543        Status alloc_error;
544        const bool zero_memory = false;
545
546        m_temporary_allocation = map.Malloc(
547            data.GetByteSize(), byte_align,
548            lldb::ePermissionsReadable | lldb::ePermissionsWritable,
549            IRMemoryMap::eAllocationPolicyMirror, zero_memory, alloc_error);
550
551        m_temporary_allocation_size = data.GetByteSize();
552
553        m_original_data = std::make_shared<DataBufferHeap>(data.GetDataStart(),
554                                                           data.GetByteSize());
555
556        if (!alloc_error.Success()) {
557          err.SetErrorStringWithFormat(
558              "couldn't allocate a temporary region for %s: %s",
559              m_variable_sp->GetName().AsCString(), alloc_error.AsCString());
560          return;
561        }
562
563        Status write_error;
564
565        map.WriteMemory(m_temporary_allocation, data.GetDataStart(),
566                        data.GetByteSize(), write_error);
567
568        if (!write_error.Success()) {
569          err.SetErrorStringWithFormat(
570              "couldn't write to the temporary region for %s: %s",
571              m_variable_sp->GetName().AsCString(), write_error.AsCString());
572          return;
573        }
574
575        Status pointer_write_error;
576
577        map.WritePointerToMemory(load_addr, m_temporary_allocation,
578                                 pointer_write_error);
579
580        if (!pointer_write_error.Success()) {
581          err.SetErrorStringWithFormat(
582              "couldn't write the address of the temporary region for %s: %s",
583              m_variable_sp->GetName().AsCString(),
584              pointer_write_error.AsCString());
585        }
586      }
587    }
588  }
589
590  void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
591                     lldb::addr_t process_address, lldb::addr_t frame_top,
592                     lldb::addr_t frame_bottom, Status &err) override {
593    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
594
595    const lldb::addr_t load_addr = process_address + m_offset;
596    if (log) {
597      LLDB_LOGF(log,
598                "EntityVariable::Dematerialize [address = 0x%" PRIx64
599                ", m_variable_sp = %s]",
600                (uint64_t)load_addr, m_variable_sp->GetName().AsCString());
601    }
602
603    if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
604      ExecutionContextScope *scope = frame_sp.get();
605
606      if (!scope)
607        scope = map.GetBestExecutionContextScope();
608
609      lldb::ValueObjectSP valobj_sp =
610          ValueObjectVariable::Create(scope, m_variable_sp);
611
612      if (!valobj_sp) {
613        err.SetErrorStringWithFormat(
614            "couldn't get a value object for variable %s",
615            m_variable_sp->GetName().AsCString());
616        return;
617      }
618
619      lldb_private::DataExtractor data;
620
621      Status extract_error;
622
623      map.GetMemoryData(data, m_temporary_allocation, valobj_sp->GetByteSize(),
624                        extract_error);
625
626      if (!extract_error.Success()) {
627        err.SetErrorStringWithFormat("couldn't get the data for variable %s",
628                                     m_variable_sp->GetName().AsCString());
629        return;
630      }
631
632      bool actually_write = true;
633
634      if (m_original_data) {
635        if ((data.GetByteSize() == m_original_data->GetByteSize()) &&
636            !memcmp(m_original_data->GetBytes(), data.GetDataStart(),
637                    data.GetByteSize())) {
638          actually_write = false;
639        }
640      }
641
642      Status set_error;
643
644      if (actually_write) {
645        valobj_sp->SetData(data, set_error);
646
647        if (!set_error.Success()) {
648          err.SetErrorStringWithFormat(
649              "couldn't write the new contents of %s back into the variable",
650              m_variable_sp->GetName().AsCString());
651          return;
652        }
653      }
654
655      Status free_error;
656
657      map.Free(m_temporary_allocation, free_error);
658
659      if (!free_error.Success()) {
660        err.SetErrorStringWithFormat(
661            "couldn't free the temporary region for %s: %s",
662            m_variable_sp->GetName().AsCString(), free_error.AsCString());
663        return;
664      }
665
666      m_original_data.reset();
667      m_temporary_allocation = LLDB_INVALID_ADDRESS;
668      m_temporary_allocation_size = 0;
669    }
670  }
671
672  void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
673                 Log *log) override {
674    StreamString dump_stream;
675
676    const lldb::addr_t load_addr = process_address + m_offset;
677    dump_stream.Printf("0x%" PRIx64 ": EntityVariable\n", load_addr);
678
679    Status err;
680
681    lldb::addr_t ptr = LLDB_INVALID_ADDRESS;
682
683    {
684      dump_stream.Printf("Pointer:\n");
685
686      DataBufferHeap data(m_size, 0);
687
688      map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
689
690      if (!err.Success()) {
691        dump_stream.Printf("  <could not be read>\n");
692      } else {
693        DataExtractor extractor(data.GetBytes(), data.GetByteSize(),
694                                map.GetByteOrder(), map.GetAddressByteSize());
695
696        DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
697                     load_addr);
698
699        lldb::offset_t offset;
700
701        ptr = extractor.GetPointer(&offset);
702
703        dump_stream.PutChar('\n');
704      }
705    }
706
707    if (m_temporary_allocation == LLDB_INVALID_ADDRESS) {
708      dump_stream.Printf("Points to process memory:\n");
709    } else {
710      dump_stream.Printf("Temporary allocation:\n");
711    }
712
713    if (ptr == LLDB_INVALID_ADDRESS) {
714      dump_stream.Printf("  <could not be be found>\n");
715    } else {
716      DataBufferHeap data(m_temporary_allocation_size, 0);
717
718      map.ReadMemory(data.GetBytes(), m_temporary_allocation,
719                     m_temporary_allocation_size, err);
720
721      if (!err.Success()) {
722        dump_stream.Printf("  <could not be read>\n");
723      } else {
724        DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
725                     load_addr);
726
727        dump_stream.PutChar('\n');
728      }
729    }
730
731    log->PutString(dump_stream.GetString());
732  }
733
734  void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {
735    if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
736      Status free_error;
737
738      map.Free(m_temporary_allocation, free_error);
739
740      m_temporary_allocation = LLDB_INVALID_ADDRESS;
741      m_temporary_allocation_size = 0;
742    }
743  }
744
745private:
746  lldb::VariableSP m_variable_sp;
747  bool m_is_reference;
748  lldb::addr_t m_temporary_allocation;
749  size_t m_temporary_allocation_size;
750  lldb::DataBufferSP m_original_data;
751};
752
753uint32_t Materializer::AddVariable(lldb::VariableSP &variable_sp, Status &err) {
754  EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
755  iter->reset(new EntityVariable(variable_sp));
756  uint32_t ret = AddStructMember(**iter);
757  (*iter)->SetOffset(ret);
758  return ret;
759}
760
761class EntityResultVariable : public Materializer::Entity {
762public:
763  EntityResultVariable(const CompilerType &type, bool is_program_reference,
764                       bool keep_in_memory,
765                       Materializer::PersistentVariableDelegate *delegate)
766      : Entity(), m_type(type), m_is_program_reference(is_program_reference),
767        m_keep_in_memory(keep_in_memory),
768        m_temporary_allocation(LLDB_INVALID_ADDRESS),
769        m_temporary_allocation_size(0), m_delegate(delegate) {
770    // Hard-coding to maximum size of a pointer since all results are
771    // materialized by reference
772    m_size = 8;
773    m_alignment = 8;
774  }
775
776  void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
777                   lldb::addr_t process_address, Status &err) override {
778    if (!m_is_program_reference) {
779      if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
780        err.SetErrorString("Trying to create a temporary region for the result "
781                           "but one exists");
782        return;
783      }
784
785      const lldb::addr_t load_addr = process_address + m_offset;
786
787      ExecutionContextScope *exe_scope = map.GetBestExecutionContextScope();
788
789      llvm::Optional<uint64_t> byte_size = m_type.GetByteSize(exe_scope);
790      if (!byte_size) {
791        err.SetErrorString("can't get size of type");
792        return;
793      }
794
795      llvm::Optional<size_t> opt_bit_align = m_type.GetTypeBitAlign(exe_scope);
796      if (!opt_bit_align) {
797        err.SetErrorStringWithFormat("can't get the type alignment");
798        return;
799      }
800
801      size_t byte_align = (*opt_bit_align + 7) / 8;
802
803      Status alloc_error;
804      const bool zero_memory = true;
805
806      m_temporary_allocation = map.Malloc(
807          *byte_size, byte_align,
808          lldb::ePermissionsReadable | lldb::ePermissionsWritable,
809          IRMemoryMap::eAllocationPolicyMirror, zero_memory, alloc_error);
810      m_temporary_allocation_size = *byte_size;
811
812      if (!alloc_error.Success()) {
813        err.SetErrorStringWithFormat(
814            "couldn't allocate a temporary region for the result: %s",
815            alloc_error.AsCString());
816        return;
817      }
818
819      Status pointer_write_error;
820
821      map.WritePointerToMemory(load_addr, m_temporary_allocation,
822                               pointer_write_error);
823
824      if (!pointer_write_error.Success()) {
825        err.SetErrorStringWithFormat("couldn't write the address of the "
826                                     "temporary region for the result: %s",
827                                     pointer_write_error.AsCString());
828      }
829    }
830  }
831
832  void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
833                     lldb::addr_t process_address, lldb::addr_t frame_top,
834                     lldb::addr_t frame_bottom, Status &err) override {
835    err.Clear();
836
837    ExecutionContextScope *exe_scope = map.GetBestExecutionContextScope();
838
839    if (!exe_scope) {
840      err.SetErrorString("Couldn't dematerialize a result variable: invalid "
841                         "execution context scope");
842      return;
843    }
844
845    lldb::addr_t address;
846    Status read_error;
847    const lldb::addr_t load_addr = process_address + m_offset;
848
849    map.ReadPointerFromMemory(&address, load_addr, read_error);
850
851    if (!read_error.Success()) {
852      err.SetErrorString("Couldn't dematerialize a result variable: couldn't "
853                         "read its address");
854      return;
855    }
856
857    lldb::TargetSP target_sp = exe_scope->CalculateTarget();
858
859    if (!target_sp) {
860      err.SetErrorString("Couldn't dematerialize a result variable: no target");
861      return;
862    }
863
864    auto type_system_or_err =
865        target_sp->GetScratchTypeSystemForLanguage(m_type.GetMinimumLanguage());
866
867    if (auto error = type_system_or_err.takeError()) {
868      err.SetErrorStringWithFormat("Couldn't dematerialize a result variable: "
869                                   "couldn't get the corresponding type "
870                                   "system: %s",
871                                   llvm::toString(std::move(error)).c_str());
872      return;
873    }
874    PersistentExpressionState *persistent_state =
875        type_system_or_err->GetPersistentExpressionState();
876
877    if (!persistent_state) {
878      err.SetErrorString("Couldn't dematerialize a result variable: "
879                         "corresponding type system doesn't handle persistent "
880                         "variables");
881      return;
882    }
883
884    ConstString name =
885        m_delegate
886            ? m_delegate->GetName()
887            : persistent_state->GetNextPersistentVariableName(
888                  *target_sp, persistent_state->GetPersistentVariablePrefix());
889
890    lldb::ExpressionVariableSP ret = persistent_state->CreatePersistentVariable(
891        exe_scope, name, m_type, map.GetByteOrder(), map.GetAddressByteSize());
892
893    if (!ret) {
894      err.SetErrorStringWithFormat("couldn't dematerialize a result variable: "
895                                   "failed to make persistent variable %s",
896                                   name.AsCString());
897      return;
898    }
899
900    lldb::ProcessSP process_sp =
901        map.GetBestExecutionContextScope()->CalculateProcess();
902
903    if (m_delegate) {
904      m_delegate->DidDematerialize(ret);
905    }
906
907    bool can_persist =
908        (m_is_program_reference && process_sp && process_sp->CanJIT() &&
909         !(address >= frame_bottom && address < frame_top));
910
911    if (can_persist && m_keep_in_memory) {
912      ret->m_live_sp = ValueObjectConstResult::Create(exe_scope, m_type, name,
913                                                      address, eAddressTypeLoad,
914                                                      map.GetAddressByteSize());
915    }
916
917    ret->ValueUpdated();
918
919    const size_t pvar_byte_size = ret->GetByteSize();
920    uint8_t *pvar_data = ret->GetValueBytes();
921
922    map.ReadMemory(pvar_data, address, pvar_byte_size, read_error);
923
924    if (!read_error.Success()) {
925      err.SetErrorString(
926          "Couldn't dematerialize a result variable: couldn't read its memory");
927      return;
928    }
929
930    if (!can_persist || !m_keep_in_memory) {
931      ret->m_flags |= ExpressionVariable::EVNeedsAllocation;
932
933      if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
934        Status free_error;
935        map.Free(m_temporary_allocation, free_error);
936      }
937    } else {
938      ret->m_flags |= ExpressionVariable::EVIsLLDBAllocated;
939    }
940
941    m_temporary_allocation = LLDB_INVALID_ADDRESS;
942    m_temporary_allocation_size = 0;
943  }
944
945  void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
946                 Log *log) override {
947    StreamString dump_stream;
948
949    const lldb::addr_t load_addr = process_address + m_offset;
950
951    dump_stream.Printf("0x%" PRIx64 ": EntityResultVariable\n", load_addr);
952
953    Status err;
954
955    lldb::addr_t ptr = LLDB_INVALID_ADDRESS;
956
957    {
958      dump_stream.Printf("Pointer:\n");
959
960      DataBufferHeap data(m_size, 0);
961
962      map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
963
964      if (!err.Success()) {
965        dump_stream.Printf("  <could not be read>\n");
966      } else {
967        DataExtractor extractor(data.GetBytes(), data.GetByteSize(),
968                                map.GetByteOrder(), map.GetAddressByteSize());
969
970        DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
971                     load_addr);
972
973        lldb::offset_t offset;
974
975        ptr = extractor.GetPointer(&offset);
976
977        dump_stream.PutChar('\n');
978      }
979    }
980
981    if (m_temporary_allocation == LLDB_INVALID_ADDRESS) {
982      dump_stream.Printf("Points to process memory:\n");
983    } else {
984      dump_stream.Printf("Temporary allocation:\n");
985    }
986
987    if (ptr == LLDB_INVALID_ADDRESS) {
988      dump_stream.Printf("  <could not be be found>\n");
989    } else {
990      DataBufferHeap data(m_temporary_allocation_size, 0);
991
992      map.ReadMemory(data.GetBytes(), m_temporary_allocation,
993                     m_temporary_allocation_size, err);
994
995      if (!err.Success()) {
996        dump_stream.Printf("  <could not be read>\n");
997      } else {
998        DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
999                     load_addr);
1000
1001        dump_stream.PutChar('\n');
1002      }
1003    }
1004
1005    log->PutString(dump_stream.GetString());
1006  }
1007
1008  void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {
1009    if (!m_keep_in_memory && m_temporary_allocation != LLDB_INVALID_ADDRESS) {
1010      Status free_error;
1011
1012      map.Free(m_temporary_allocation, free_error);
1013    }
1014
1015    m_temporary_allocation = LLDB_INVALID_ADDRESS;
1016    m_temporary_allocation_size = 0;
1017  }
1018
1019private:
1020  CompilerType m_type;
1021  bool m_is_program_reference;
1022  bool m_keep_in_memory;
1023
1024  lldb::addr_t m_temporary_allocation;
1025  size_t m_temporary_allocation_size;
1026  Materializer::PersistentVariableDelegate *m_delegate;
1027};
1028
1029uint32_t Materializer::AddResultVariable(const CompilerType &type,
1030                                         bool is_program_reference,
1031                                         bool keep_in_memory,
1032                                         PersistentVariableDelegate *delegate,
1033                                         Status &err) {
1034  EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
1035  iter->reset(new EntityResultVariable(type, is_program_reference,
1036                                       keep_in_memory, delegate));
1037  uint32_t ret = AddStructMember(**iter);
1038  (*iter)->SetOffset(ret);
1039  return ret;
1040}
1041
1042class EntitySymbol : public Materializer::Entity {
1043public:
1044  EntitySymbol(const Symbol &symbol) : Entity(), m_symbol(symbol) {
1045    // Hard-coding to maximum size of a symbol
1046    m_size = 8;
1047    m_alignment = 8;
1048  }
1049
1050  void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1051                   lldb::addr_t process_address, Status &err) override {
1052    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
1053
1054    const lldb::addr_t load_addr = process_address + m_offset;
1055
1056    if (log) {
1057      LLDB_LOGF(log,
1058                "EntitySymbol::Materialize [address = 0x%" PRIx64
1059                ", m_symbol = %s]",
1060                (uint64_t)load_addr, m_symbol.GetName().AsCString());
1061    }
1062
1063    const Address sym_address = m_symbol.GetAddress();
1064
1065    ExecutionContextScope *exe_scope = map.GetBestExecutionContextScope();
1066
1067    lldb::TargetSP target_sp;
1068
1069    if (exe_scope)
1070      target_sp = map.GetBestExecutionContextScope()->CalculateTarget();
1071
1072    if (!target_sp) {
1073      err.SetErrorStringWithFormat(
1074          "couldn't resolve symbol %s because there is no target",
1075          m_symbol.GetName().AsCString());
1076      return;
1077    }
1078
1079    lldb::addr_t resolved_address = sym_address.GetLoadAddress(target_sp.get());
1080
1081    if (resolved_address == LLDB_INVALID_ADDRESS)
1082      resolved_address = sym_address.GetFileAddress();
1083
1084    Status pointer_write_error;
1085
1086    map.WritePointerToMemory(load_addr, resolved_address, pointer_write_error);
1087
1088    if (!pointer_write_error.Success()) {
1089      err.SetErrorStringWithFormat(
1090          "couldn't write the address of symbol %s: %s",
1091          m_symbol.GetName().AsCString(), pointer_write_error.AsCString());
1092      return;
1093    }
1094  }
1095
1096  void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1097                     lldb::addr_t process_address, lldb::addr_t frame_top,
1098                     lldb::addr_t frame_bottom, Status &err) override {
1099    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
1100
1101    const lldb::addr_t load_addr = process_address + m_offset;
1102
1103    if (log) {
1104      LLDB_LOGF(log,
1105                "EntitySymbol::Dematerialize [address = 0x%" PRIx64
1106                ", m_symbol = %s]",
1107                (uint64_t)load_addr, m_symbol.GetName().AsCString());
1108    }
1109
1110    // no work needs to be done
1111  }
1112
1113  void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
1114                 Log *log) override {
1115    StreamString dump_stream;
1116
1117    Status err;
1118
1119    const lldb::addr_t load_addr = process_address + m_offset;
1120
1121    dump_stream.Printf("0x%" PRIx64 ": EntitySymbol (%s)\n", load_addr,
1122                       m_symbol.GetName().AsCString());
1123
1124    {
1125      dump_stream.Printf("Pointer:\n");
1126
1127      DataBufferHeap data(m_size, 0);
1128
1129      map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
1130
1131      if (!err.Success()) {
1132        dump_stream.Printf("  <could not be read>\n");
1133      } else {
1134        DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
1135                     load_addr);
1136
1137        dump_stream.PutChar('\n');
1138      }
1139    }
1140
1141    log->PutString(dump_stream.GetString());
1142  }
1143
1144  void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {}
1145
1146private:
1147  Symbol m_symbol;
1148};
1149
1150uint32_t Materializer::AddSymbol(const Symbol &symbol_sp, Status &err) {
1151  EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
1152  iter->reset(new EntitySymbol(symbol_sp));
1153  uint32_t ret = AddStructMember(**iter);
1154  (*iter)->SetOffset(ret);
1155  return ret;
1156}
1157
1158class EntityRegister : public Materializer::Entity {
1159public:
1160  EntityRegister(const RegisterInfo &register_info)
1161      : Entity(), m_register_info(register_info) {
1162    // Hard-coding alignment conservatively
1163    m_size = m_register_info.byte_size;
1164    m_alignment = m_register_info.byte_size;
1165  }
1166
1167  void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1168                   lldb::addr_t process_address, Status &err) override {
1169    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
1170
1171    const lldb::addr_t load_addr = process_address + m_offset;
1172
1173    if (log) {
1174      LLDB_LOGF(log,
1175                "EntityRegister::Materialize [address = 0x%" PRIx64
1176                ", m_register_info = %s]",
1177                (uint64_t)load_addr, m_register_info.name);
1178    }
1179
1180    RegisterValue reg_value;
1181
1182    if (!frame_sp.get()) {
1183      err.SetErrorStringWithFormat(
1184          "couldn't materialize register %s without a stack frame",
1185          m_register_info.name);
1186      return;
1187    }
1188
1189    lldb::RegisterContextSP reg_context_sp = frame_sp->GetRegisterContext();
1190
1191    if (!reg_context_sp->ReadRegister(&m_register_info, reg_value)) {
1192      err.SetErrorStringWithFormat("couldn't read the value of register %s",
1193                                   m_register_info.name);
1194      return;
1195    }
1196
1197    DataExtractor register_data;
1198
1199    if (!reg_value.GetData(register_data)) {
1200      err.SetErrorStringWithFormat("couldn't get the data for register %s",
1201                                   m_register_info.name);
1202      return;
1203    }
1204
1205    if (register_data.GetByteSize() != m_register_info.byte_size) {
1206      err.SetErrorStringWithFormat(
1207          "data for register %s had size %llu but we expected %llu",
1208          m_register_info.name, (unsigned long long)register_data.GetByteSize(),
1209          (unsigned long long)m_register_info.byte_size);
1210      return;
1211    }
1212
1213    m_register_contents = std::make_shared<DataBufferHeap>(
1214        register_data.GetDataStart(), register_data.GetByteSize());
1215
1216    Status write_error;
1217
1218    map.WriteMemory(load_addr, register_data.GetDataStart(),
1219                    register_data.GetByteSize(), write_error);
1220
1221    if (!write_error.Success()) {
1222      err.SetErrorStringWithFormat(
1223          "couldn't write the contents of register %s: %s",
1224          m_register_info.name, write_error.AsCString());
1225      return;
1226    }
1227  }
1228
1229  void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1230                     lldb::addr_t process_address, lldb::addr_t frame_top,
1231                     lldb::addr_t frame_bottom, Status &err) override {
1232    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
1233
1234    const lldb::addr_t load_addr = process_address + m_offset;
1235
1236    if (log) {
1237      LLDB_LOGF(log,
1238                "EntityRegister::Dematerialize [address = 0x%" PRIx64
1239                ", m_register_info = %s]",
1240                (uint64_t)load_addr, m_register_info.name);
1241    }
1242
1243    Status extract_error;
1244
1245    DataExtractor register_data;
1246
1247    if (!frame_sp.get()) {
1248      err.SetErrorStringWithFormat(
1249          "couldn't dematerialize register %s without a stack frame",
1250          m_register_info.name);
1251      return;
1252    }
1253
1254    lldb::RegisterContextSP reg_context_sp = frame_sp->GetRegisterContext();
1255
1256    map.GetMemoryData(register_data, load_addr, m_register_info.byte_size,
1257                      extract_error);
1258
1259    if (!extract_error.Success()) {
1260      err.SetErrorStringWithFormat("couldn't get the data for register %s: %s",
1261                                   m_register_info.name,
1262                                   extract_error.AsCString());
1263      return;
1264    }
1265
1266    if (!memcmp(register_data.GetDataStart(), m_register_contents->GetBytes(),
1267                register_data.GetByteSize())) {
1268      // No write required, and in particular we avoid errors if the register
1269      // wasn't writable
1270
1271      m_register_contents.reset();
1272      return;
1273    }
1274
1275    m_register_contents.reset();
1276
1277    RegisterValue register_value(
1278        const_cast<uint8_t *>(register_data.GetDataStart()),
1279        register_data.GetByteSize(), register_data.GetByteOrder());
1280
1281    if (!reg_context_sp->WriteRegister(&m_register_info, register_value)) {
1282      err.SetErrorStringWithFormat("couldn't write the value of register %s",
1283                                   m_register_info.name);
1284      return;
1285    }
1286  }
1287
1288  void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
1289                 Log *log) override {
1290    StreamString dump_stream;
1291
1292    Status err;
1293
1294    const lldb::addr_t load_addr = process_address + m_offset;
1295
1296    dump_stream.Printf("0x%" PRIx64 ": EntityRegister (%s)\n", load_addr,
1297                       m_register_info.name);
1298
1299    {
1300      dump_stream.Printf("Value:\n");
1301
1302      DataBufferHeap data(m_size, 0);
1303
1304      map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
1305
1306      if (!err.Success()) {
1307        dump_stream.Printf("  <could not be read>\n");
1308      } else {
1309        DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
1310                     load_addr);
1311
1312        dump_stream.PutChar('\n');
1313      }
1314    }
1315
1316    log->PutString(dump_stream.GetString());
1317  }
1318
1319  void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {}
1320
1321private:
1322  RegisterInfo m_register_info;
1323  lldb::DataBufferSP m_register_contents;
1324};
1325
1326uint32_t Materializer::AddRegister(const RegisterInfo &register_info,
1327                                   Status &err) {
1328  EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
1329  iter->reset(new EntityRegister(register_info));
1330  uint32_t ret = AddStructMember(**iter);
1331  (*iter)->SetOffset(ret);
1332  return ret;
1333}
1334
1335Materializer::Materializer()
1336    : m_dematerializer_wp(), m_current_offset(0), m_struct_alignment(8) {}
1337
1338Materializer::~Materializer() {
1339  DematerializerSP dematerializer_sp = m_dematerializer_wp.lock();
1340
1341  if (dematerializer_sp)
1342    dematerializer_sp->Wipe();
1343}
1344
1345Materializer::DematerializerSP
1346Materializer::Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1347                          lldb::addr_t process_address, Status &error) {
1348  ExecutionContextScope *exe_scope = frame_sp.get();
1349
1350  if (!exe_scope)
1351    exe_scope = map.GetBestExecutionContextScope();
1352
1353  DematerializerSP dematerializer_sp = m_dematerializer_wp.lock();
1354
1355  if (dematerializer_sp) {
1356    error.SetErrorToGenericError();
1357    error.SetErrorString("Couldn't materialize: already materialized");
1358  }
1359
1360  DematerializerSP ret(
1361      new Dematerializer(*this, frame_sp, map, process_address));
1362
1363  if (!exe_scope) {
1364    error.SetErrorToGenericError();
1365    error.SetErrorString("Couldn't materialize: target doesn't exist");
1366  }
1367
1368  for (EntityUP &entity_up : m_entities) {
1369    entity_up->Materialize(frame_sp, map, process_address, error);
1370
1371    if (!error.Success())
1372      return DematerializerSP();
1373  }
1374
1375  if (Log *log =
1376          lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)) {
1377    LLDB_LOGF(
1378        log,
1379        "Materializer::Materialize (frame_sp = %p, process_address = 0x%" PRIx64
1380        ") materialized:",
1381        static_cast<void *>(frame_sp.get()), process_address);
1382    for (EntityUP &entity_up : m_entities)
1383      entity_up->DumpToLog(map, process_address, log);
1384  }
1385
1386  m_dematerializer_wp = ret;
1387
1388  return ret;
1389}
1390
1391void Materializer::Dematerializer::Dematerialize(Status &error,
1392                                                 lldb::addr_t frame_bottom,
1393                                                 lldb::addr_t frame_top) {
1394  lldb::StackFrameSP frame_sp;
1395
1396  lldb::ThreadSP thread_sp = m_thread_wp.lock();
1397  if (thread_sp)
1398    frame_sp = thread_sp->GetFrameWithStackID(m_stack_id);
1399
1400  ExecutionContextScope *exe_scope = m_map->GetBestExecutionContextScope();
1401
1402  if (!IsValid()) {
1403    error.SetErrorToGenericError();
1404    error.SetErrorString("Couldn't dematerialize: invalid dematerializer");
1405  }
1406
1407  if (!exe_scope) {
1408    error.SetErrorToGenericError();
1409    error.SetErrorString("Couldn't dematerialize: target is gone");
1410  } else {
1411    if (Log *log =
1412            lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)) {
1413      LLDB_LOGF(log,
1414                "Materializer::Dematerialize (frame_sp = %p, process_address "
1415                "= 0x%" PRIx64 ") about to dematerialize:",
1416                static_cast<void *>(frame_sp.get()), m_process_address);
1417      for (EntityUP &entity_up : m_materializer->m_entities)
1418        entity_up->DumpToLog(*m_map, m_process_address, log);
1419    }
1420
1421    for (EntityUP &entity_up : m_materializer->m_entities) {
1422      entity_up->Dematerialize(frame_sp, *m_map, m_process_address, frame_top,
1423                               frame_bottom, error);
1424
1425      if (!error.Success())
1426        break;
1427    }
1428  }
1429
1430  Wipe();
1431}
1432
1433void Materializer::Dematerializer::Wipe() {
1434  if (!IsValid())
1435    return;
1436
1437  for (EntityUP &entity_up : m_materializer->m_entities) {
1438    entity_up->Wipe(*m_map, m_process_address);
1439  }
1440
1441  m_materializer = nullptr;
1442  m_map = nullptr;
1443  m_process_address = LLDB_INVALID_ADDRESS;
1444}
1445
1446Materializer::PersistentVariableDelegate::~PersistentVariableDelegate() =
1447    default;
1448