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