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