Materializer.cpp revision 353358
1254721Semaste//===-- Materializer.cpp ----------------------------------------*- C++ -*-===//
2254721Semaste//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6254721Semaste//
7254721Semaste//===----------------------------------------------------------------------===//
8254721Semaste
9314564Sdim#include "lldb/Expression/Materializer.h"
10321369Sdim#include "lldb/Core/DumpDataExtractor.h"
11254721Semaste#include "lldb/Core/ValueObjectConstResult.h"
12254721Semaste#include "lldb/Core/ValueObjectVariable.h"
13296417Sdim#include "lldb/Expression/ExpressionVariable.h"
14254721Semaste#include "lldb/Symbol/ClangASTContext.h"
15254721Semaste#include "lldb/Symbol/Symbol.h"
16254721Semaste#include "lldb/Symbol/Type.h"
17254721Semaste#include "lldb/Symbol/Variable.h"
18254721Semaste#include "lldb/Target/ExecutionContext.h"
19254721Semaste#include "lldb/Target/RegisterContext.h"
20254721Semaste#include "lldb/Target/StackFrame.h"
21254721Semaste#include "lldb/Target/Target.h"
22254721Semaste#include "lldb/Target/Thread.h"
23321369Sdim#include "lldb/Utility/Log.h"
24344779Sdim#include "lldb/Utility/RegisterValue.h"
25254721Semaste
26353358Sdim#include <memory>
27353358Sdim
28254721Semasteusing namespace lldb_private;
29254721Semaste
30314564Sdimuint32_t Materializer::AddStructMember(Entity &entity) {
31314564Sdim  uint32_t size = entity.GetSize();
32314564Sdim  uint32_t alignment = entity.GetAlignment();
33309124Sdim
34314564Sdim  uint32_t ret;
35309124Sdim
36314564Sdim  if (m_current_offset == 0)
37314564Sdim    m_struct_alignment = alignment;
38309124Sdim
39314564Sdim  if (m_current_offset % alignment)
40314564Sdim    m_current_offset += (alignment - (m_current_offset % alignment));
41309124Sdim
42314564Sdim  ret = m_current_offset;
43309124Sdim
44314564Sdim  m_current_offset += size;
45309124Sdim
46314564Sdim  return ret;
47254721Semaste}
48254721Semaste
49314564Sdimvoid Materializer::Entity::SetSizeAndAlignmentFromType(CompilerType &type) {
50344779Sdim  if (llvm::Optional<uint64_t> size = type.GetByteSize(nullptr))
51344779Sdim    m_size = *size;
52309124Sdim
53314564Sdim  uint32_t bit_alignment = type.GetTypeBitAlign();
54309124Sdim
55314564Sdim  if (bit_alignment % 8) {
56314564Sdim    bit_alignment += 8;
57314564Sdim    bit_alignment &= ~((uint32_t)0x111u);
58314564Sdim  }
59309124Sdim
60314564Sdim  m_alignment = bit_alignment / 8;
61254721Semaste}
62254721Semaste
63314564Sdimclass EntityPersistentVariable : public Materializer::Entity {
64254721Semastepublic:
65314564Sdim  EntityPersistentVariable(lldb::ExpressionVariableSP &persistent_variable_sp,
66314564Sdim                           Materializer::PersistentVariableDelegate *delegate)
67314564Sdim      : Entity(), m_persistent_variable_sp(persistent_variable_sp),
68314564Sdim        m_delegate(delegate) {
69314564Sdim    // Hard-coding to maximum size of a pointer since persistent variables are
70314564Sdim    // materialized by reference
71314564Sdim    m_size = 8;
72314564Sdim    m_alignment = 8;
73314564Sdim  }
74309124Sdim
75321369Sdim  void MakeAllocation(IRMemoryMap &map, Status &err) {
76314564Sdim    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
77254721Semaste
78341825Sdim    // Allocate a spare memory area to store the persistent variable's
79341825Sdim    // contents.
80309124Sdim
81321369Sdim    Status allocate_error;
82314564Sdim    const bool zero_memory = false;
83309124Sdim
84314564Sdim    lldb::addr_t mem = map.Malloc(
85314564Sdim        m_persistent_variable_sp->GetByteSize(), 8,
86314564Sdim        lldb::ePermissionsReadable | lldb::ePermissionsWritable,
87314564Sdim        IRMemoryMap::eAllocationPolicyMirror, zero_memory, allocate_error);
88309124Sdim
89314564Sdim    if (!allocate_error.Success()) {
90314564Sdim      err.SetErrorStringWithFormat(
91314564Sdim          "couldn't allocate a memory area to store %s: %s",
92314564Sdim          m_persistent_variable_sp->GetName().GetCString(),
93314564Sdim          allocate_error.AsCString());
94314564Sdim      return;
95314564Sdim    }
96309124Sdim
97314564Sdim    if (log)
98314564Sdim      log->Printf("Allocated %s (0x%" PRIx64 ") successfully",
99314564Sdim                  m_persistent_variable_sp->GetName().GetCString(), mem);
100309124Sdim
101314564Sdim    // Put the location of the spare memory into the live data of the
102314564Sdim    // ValueObject.
103309124Sdim
104314564Sdim    m_persistent_variable_sp->m_live_sp = ValueObjectConstResult::Create(
105314564Sdim        map.GetBestExecutionContextScope(),
106314564Sdim        m_persistent_variable_sp->GetCompilerType(),
107314564Sdim        m_persistent_variable_sp->GetName(), mem, eAddressTypeLoad,
108314564Sdim        map.GetAddressByteSize());
109309124Sdim
110314564Sdim    // Clear the flag if the variable will never be deallocated.
111309124Sdim
112314564Sdim    if (m_persistent_variable_sp->m_flags &
113314564Sdim        ExpressionVariable::EVKeepInTarget) {
114321369Sdim      Status leak_error;
115314564Sdim      map.Leak(mem, leak_error);
116314564Sdim      m_persistent_variable_sp->m_flags &=
117314564Sdim          ~ExpressionVariable::EVNeedsAllocation;
118314564Sdim    }
119309124Sdim
120314564Sdim    // Write the contents of the variable to the area.
121309124Sdim
122321369Sdim    Status write_error;
123309124Sdim
124314564Sdim    map.WriteMemory(mem, m_persistent_variable_sp->GetValueBytes(),
125314564Sdim                    m_persistent_variable_sp->GetByteSize(), write_error);
126309124Sdim
127314564Sdim    if (!write_error.Success()) {
128314564Sdim      err.SetErrorStringWithFormat(
129314564Sdim          "couldn't write %s to the target: %s",
130314564Sdim          m_persistent_variable_sp->GetName().AsCString(),
131314564Sdim          write_error.AsCString());
132314564Sdim      return;
133254721Semaste    }
134314564Sdim  }
135309124Sdim
136321369Sdim  void DestroyAllocation(IRMemoryMap &map, Status &err) {
137321369Sdim    Status deallocate_error;
138309124Sdim
139314564Sdim    map.Free((lldb::addr_t)m_persistent_variable_sp->m_live_sp->GetValue()
140314564Sdim                 .GetScalar()
141314564Sdim                 .ULongLong(),
142314564Sdim             deallocate_error);
143309124Sdim
144314564Sdim    m_persistent_variable_sp->m_live_sp.reset();
145309124Sdim
146314564Sdim    if (!deallocate_error.Success()) {
147314564Sdim      err.SetErrorStringWithFormat(
148314564Sdim          "couldn't deallocate memory for %s: %s",
149314564Sdim          m_persistent_variable_sp->GetName().GetCString(),
150314564Sdim          deallocate_error.AsCString());
151254721Semaste    }
152314564Sdim  }
153309124Sdim
154314564Sdim  void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
155321369Sdim                   lldb::addr_t process_address, Status &err) override {
156314564Sdim    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
157254721Semaste
158314564Sdim    const lldb::addr_t load_addr = process_address + m_offset;
159309124Sdim
160314564Sdim    if (log) {
161314564Sdim      log->Printf("EntityPersistentVariable::Materialize [address = 0x%" PRIx64
162314564Sdim                  ", m_name = %s, m_flags = 0x%hx]",
163314564Sdim                  (uint64_t)load_addr,
164314564Sdim                  m_persistent_variable_sp->GetName().AsCString(),
165314564Sdim                  m_persistent_variable_sp->m_flags);
166314564Sdim    }
167309124Sdim
168314564Sdim    if (m_persistent_variable_sp->m_flags &
169314564Sdim        ExpressionVariable::EVNeedsAllocation) {
170314564Sdim      MakeAllocation(map, err);
171314564Sdim      m_persistent_variable_sp->m_flags |=
172314564Sdim          ExpressionVariable::EVIsLLDBAllocated;
173309124Sdim
174314564Sdim      if (!err.Success())
175314564Sdim        return;
176314564Sdim    }
177309124Sdim
178314564Sdim    if ((m_persistent_variable_sp->m_flags &
179314564Sdim             ExpressionVariable::EVIsProgramReference &&
180314564Sdim         m_persistent_variable_sp->m_live_sp) ||
181314564Sdim        m_persistent_variable_sp->m_flags &
182314564Sdim            ExpressionVariable::EVIsLLDBAllocated) {
183321369Sdim      Status write_error;
184309124Sdim
185314564Sdim      map.WriteScalarToMemory(
186314564Sdim          load_addr,
187314564Sdim          m_persistent_variable_sp->m_live_sp->GetValue().GetScalar(),
188314564Sdim          map.GetAddressByteSize(), write_error);
189309124Sdim
190314564Sdim      if (!write_error.Success()) {
191314564Sdim        err.SetErrorStringWithFormat(
192314564Sdim            "couldn't write the location of %s to memory: %s",
193314564Sdim            m_persistent_variable_sp->GetName().AsCString(),
194314564Sdim            write_error.AsCString());
195314564Sdim      }
196314564Sdim    } else {
197314564Sdim      err.SetErrorStringWithFormat(
198314564Sdim          "no materialization happened for persistent variable %s",
199314564Sdim          m_persistent_variable_sp->GetName().AsCString());
200314564Sdim      return;
201254721Semaste    }
202314564Sdim  }
203309124Sdim
204314564Sdim  void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
205314564Sdim                     lldb::addr_t process_address, lldb::addr_t frame_top,
206321369Sdim                     lldb::addr_t frame_bottom, Status &err) override {
207314564Sdim    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
208309124Sdim
209314564Sdim    const lldb::addr_t load_addr = process_address + m_offset;
210254721Semaste
211314564Sdim    if (log) {
212314564Sdim      log->Printf(
213314564Sdim          "EntityPersistentVariable::Dematerialize [address = 0x%" PRIx64
214314564Sdim          ", m_name = %s, m_flags = 0x%hx]",
215314564Sdim          (uint64_t)process_address + m_offset,
216314564Sdim          m_persistent_variable_sp->GetName().AsCString(),
217314564Sdim          m_persistent_variable_sp->m_flags);
218314564Sdim    }
219309124Sdim
220314564Sdim    if (m_delegate) {
221314564Sdim      m_delegate->DidDematerialize(m_persistent_variable_sp);
222314564Sdim    }
223296417Sdim
224314564Sdim    if ((m_persistent_variable_sp->m_flags &
225314564Sdim         ExpressionVariable::EVIsLLDBAllocated) ||
226314564Sdim        (m_persistent_variable_sp->m_flags &
227314564Sdim         ExpressionVariable::EVIsProgramReference)) {
228314564Sdim      if (m_persistent_variable_sp->m_flags &
229314564Sdim              ExpressionVariable::EVIsProgramReference &&
230314564Sdim          !m_persistent_variable_sp->m_live_sp) {
231314564Sdim        // If the reference comes from the program, then the
232341825Sdim        // ClangExpressionVariable's live variable data hasn't been set up yet.
233341825Sdim        // Do this now.
234309124Sdim
235314564Sdim        lldb::addr_t location;
236321369Sdim        Status read_error;
237309124Sdim
238314564Sdim        map.ReadPointerFromMemory(&location, load_addr, read_error);
239309124Sdim
240314564Sdim        if (!read_error.Success()) {
241314564Sdim          err.SetErrorStringWithFormat(
242314564Sdim              "couldn't read the address of program-allocated variable %s: %s",
243314564Sdim              m_persistent_variable_sp->GetName().GetCString(),
244314564Sdim              read_error.AsCString());
245314564Sdim          return;
246314564Sdim        }
247309124Sdim
248314564Sdim        m_persistent_variable_sp->m_live_sp = ValueObjectConstResult::Create(
249314564Sdim            map.GetBestExecutionContextScope(),
250314564Sdim            m_persistent_variable_sp.get()->GetCompilerType(),
251314564Sdim            m_persistent_variable_sp->GetName(), location, eAddressTypeLoad,
252314564Sdim            m_persistent_variable_sp->GetByteSize());
253309124Sdim
254314564Sdim        if (frame_top != LLDB_INVALID_ADDRESS &&
255314564Sdim            frame_bottom != LLDB_INVALID_ADDRESS && location >= frame_bottom &&
256314564Sdim            location <= frame_top) {
257314564Sdim          // If the variable is resident in the stack frame created by the
258341825Sdim          // expression, then it cannot be relied upon to stay around.  We
259341825Sdim          // treat it as needing reallocation.
260314564Sdim          m_persistent_variable_sp->m_flags |=
261314564Sdim              ExpressionVariable::EVIsLLDBAllocated;
262314564Sdim          m_persistent_variable_sp->m_flags |=
263314564Sdim              ExpressionVariable::EVNeedsAllocation;
264314564Sdim          m_persistent_variable_sp->m_flags |=
265314564Sdim              ExpressionVariable::EVNeedsFreezeDry;
266314564Sdim          m_persistent_variable_sp->m_flags &=
267314564Sdim              ~ExpressionVariable::EVIsProgramReference;
268314564Sdim        }
269314564Sdim      }
270309124Sdim
271314564Sdim      lldb::addr_t mem = m_persistent_variable_sp->m_live_sp->GetValue()
272314564Sdim                             .GetScalar()
273314564Sdim                             .ULongLong();
274309124Sdim
275314564Sdim      if (!m_persistent_variable_sp->m_live_sp) {
276314564Sdim        err.SetErrorStringWithFormat(
277314564Sdim            "couldn't find the memory area used to store %s",
278314564Sdim            m_persistent_variable_sp->GetName().GetCString());
279314564Sdim        return;
280314564Sdim      }
281309124Sdim
282314564Sdim      if (m_persistent_variable_sp->m_live_sp->GetValue()
283314564Sdim              .GetValueAddressType() != eAddressTypeLoad) {
284314564Sdim        err.SetErrorStringWithFormat(
285314564Sdim            "the address of the memory area for %s is in an incorrect format",
286314564Sdim            m_persistent_variable_sp->GetName().GetCString());
287314564Sdim        return;
288314564Sdim      }
289309124Sdim
290314564Sdim      if (m_persistent_variable_sp->m_flags &
291314564Sdim              ExpressionVariable::EVNeedsFreezeDry ||
292314564Sdim          m_persistent_variable_sp->m_flags &
293314564Sdim              ExpressionVariable::EVKeepInTarget) {
294314564Sdim        if (log)
295314564Sdim          log->Printf(
296314564Sdim              "Dematerializing %s from 0x%" PRIx64 " (size = %llu)",
297314564Sdim              m_persistent_variable_sp->GetName().GetCString(), (uint64_t)mem,
298314564Sdim              (unsigned long long)m_persistent_variable_sp->GetByteSize());
299309124Sdim
300314564Sdim        // Read the contents of the spare memory area
301309124Sdim
302314564Sdim        m_persistent_variable_sp->ValueUpdated();
303309124Sdim
304321369Sdim        Status read_error;
305309124Sdim
306314564Sdim        map.ReadMemory(m_persistent_variable_sp->GetValueBytes(), mem,
307314564Sdim                       m_persistent_variable_sp->GetByteSize(), read_error);
308309124Sdim
309314564Sdim        if (!read_error.Success()) {
310314564Sdim          err.SetErrorStringWithFormat(
311314564Sdim              "couldn't read the contents of %s from memory: %s",
312314564Sdim              m_persistent_variable_sp->GetName().GetCString(),
313314564Sdim              read_error.AsCString());
314314564Sdim          return;
315254721Semaste        }
316309124Sdim
317314564Sdim        m_persistent_variable_sp->m_flags &=
318314564Sdim            ~ExpressionVariable::EVNeedsFreezeDry;
319314564Sdim      }
320314564Sdim    } else {
321314564Sdim      err.SetErrorStringWithFormat(
322314564Sdim          "no dematerialization happened for persistent variable %s",
323314564Sdim          m_persistent_variable_sp->GetName().AsCString());
324314564Sdim      return;
325314564Sdim    }
326309124Sdim
327314564Sdim    lldb::ProcessSP process_sp =
328314564Sdim        map.GetBestExecutionContextScope()->CalculateProcess();
329314564Sdim    if (!process_sp || !process_sp->CanJIT()) {
330314564Sdim      // Allocations are not persistent so persistent variables cannot stay
331314564Sdim      // materialized.
332254721Semaste
333314564Sdim      m_persistent_variable_sp->m_flags |=
334314564Sdim          ExpressionVariable::EVNeedsAllocation;
335314564Sdim
336314564Sdim      DestroyAllocation(map, err);
337314564Sdim      if (!err.Success())
338314564Sdim        return;
339314564Sdim    } else if (m_persistent_variable_sp->m_flags &
340314564Sdim                   ExpressionVariable::EVNeedsAllocation &&
341314564Sdim               !(m_persistent_variable_sp->m_flags &
342314564Sdim                 ExpressionVariable::EVKeepInTarget)) {
343314564Sdim      DestroyAllocation(map, err);
344314564Sdim      if (!err.Success())
345314564Sdim        return;
346254721Semaste    }
347314564Sdim  }
348309124Sdim
349314564Sdim  void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
350314564Sdim                 Log *log) override {
351314564Sdim    StreamString dump_stream;
352309124Sdim
353321369Sdim    Status err;
354309124Sdim
355314564Sdim    const lldb::addr_t load_addr = process_address + m_offset;
356254721Semaste
357314564Sdim    dump_stream.Printf("0x%" PRIx64 ": EntityPersistentVariable (%s)\n",
358314564Sdim                       load_addr,
359314564Sdim                       m_persistent_variable_sp->GetName().AsCString());
360309124Sdim
361314564Sdim    {
362314564Sdim      dump_stream.Printf("Pointer:\n");
363309124Sdim
364314564Sdim      DataBufferHeap data(m_size, 0);
365309124Sdim
366314564Sdim      map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
367309124Sdim
368314564Sdim      if (!err.Success()) {
369314564Sdim        dump_stream.Printf("  <could not be read>\n");
370314564Sdim      } else {
371321369Sdim        DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
372321369Sdim                     load_addr);
373309124Sdim
374314564Sdim        dump_stream.PutChar('\n');
375314564Sdim      }
376314564Sdim    }
377309124Sdim
378314564Sdim    {
379314564Sdim      dump_stream.Printf("Target:\n");
380309124Sdim
381314564Sdim      lldb::addr_t target_address;
382309124Sdim
383314564Sdim      map.ReadPointerFromMemory(&target_address, load_addr, err);
384309124Sdim
385314564Sdim      if (!err.Success()) {
386314564Sdim        dump_stream.Printf("  <could not be read>\n");
387314564Sdim      } else {
388314564Sdim        DataBufferHeap data(m_persistent_variable_sp->GetByteSize(), 0);
389309124Sdim
390314564Sdim        map.ReadMemory(data.GetBytes(), target_address,
391314564Sdim                       m_persistent_variable_sp->GetByteSize(), err);
392309124Sdim
393314564Sdim        if (!err.Success()) {
394314564Sdim          dump_stream.Printf("  <could not be read>\n");
395314564Sdim        } else {
396321369Sdim          DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
397321369Sdim                       target_address);
398309124Sdim
399314564Sdim          dump_stream.PutChar('\n');
400254721Semaste        }
401314564Sdim      }
402254721Semaste    }
403309124Sdim
404314564Sdim    log->PutString(dump_stream.GetString());
405314564Sdim  }
406296417Sdim
407314564Sdim  void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {}
408314564Sdim
409254721Semasteprivate:
410314564Sdim  lldb::ExpressionVariableSP m_persistent_variable_sp;
411314564Sdim  Materializer::PersistentVariableDelegate *m_delegate;
412254721Semaste};
413254721Semaste
414314564Sdimuint32_t Materializer::AddPersistentVariable(
415314564Sdim    lldb::ExpressionVariableSP &persistent_variable_sp,
416321369Sdim    PersistentVariableDelegate *delegate, Status &err) {
417314564Sdim  EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
418314564Sdim  iter->reset(new EntityPersistentVariable(persistent_variable_sp, delegate));
419314564Sdim  uint32_t ret = AddStructMember(**iter);
420314564Sdim  (*iter)->SetOffset(ret);
421314564Sdim  return ret;
422254721Semaste}
423254721Semaste
424314564Sdimclass EntityVariable : public Materializer::Entity {
425254721Semastepublic:
426314564Sdim  EntityVariable(lldb::VariableSP &variable_sp)
427314564Sdim      : Entity(), m_variable_sp(variable_sp), m_is_reference(false),
428254721Semaste        m_temporary_allocation(LLDB_INVALID_ADDRESS),
429314564Sdim        m_temporary_allocation_size(0) {
430314564Sdim    // Hard-coding to maximum size of a pointer since all variables are
431314564Sdim    // materialized by reference
432314564Sdim    m_size = 8;
433314564Sdim    m_alignment = 8;
434314564Sdim    m_is_reference =
435314564Sdim        m_variable_sp->GetType()->GetForwardCompilerType().IsReferenceType();
436314564Sdim  }
437314564Sdim
438314564Sdim  void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
439321369Sdim                   lldb::addr_t process_address, Status &err) override {
440314564Sdim    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
441314564Sdim
442314564Sdim    const lldb::addr_t load_addr = process_address + m_offset;
443314564Sdim    if (log) {
444314564Sdim      log->Printf("EntityVariable::Materialize [address = 0x%" PRIx64
445314564Sdim                  ", m_variable_sp = %s]",
446314564Sdim                  (uint64_t)load_addr, m_variable_sp->GetName().AsCString());
447254721Semaste    }
448309124Sdim
449314564Sdim    ExecutionContextScope *scope = frame_sp.get();
450309124Sdim
451314564Sdim    if (!scope)
452314564Sdim      scope = map.GetBestExecutionContextScope();
453309124Sdim
454314564Sdim    lldb::ValueObjectSP valobj_sp =
455314564Sdim        ValueObjectVariable::Create(scope, m_variable_sp);
456309124Sdim
457314564Sdim    if (!valobj_sp) {
458314564Sdim      err.SetErrorStringWithFormat(
459314564Sdim          "couldn't get a value object for variable %s",
460314564Sdim          m_variable_sp->GetName().AsCString());
461314564Sdim      return;
462314564Sdim    }
463309124Sdim
464321369Sdim    Status valobj_error = valobj_sp->GetError();
465309124Sdim
466314564Sdim    if (valobj_error.Fail()) {
467314564Sdim      err.SetErrorStringWithFormat("couldn't get the value of variable %s: %s",
468314564Sdim                                   m_variable_sp->GetName().AsCString(),
469314564Sdim                                   valobj_error.AsCString());
470314564Sdim      return;
471314564Sdim    }
472309124Sdim
473314564Sdim    if (m_is_reference) {
474314564Sdim      DataExtractor valobj_extractor;
475321369Sdim      Status extract_error;
476314564Sdim      valobj_sp->GetData(valobj_extractor, extract_error);
477309124Sdim
478314564Sdim      if (!extract_error.Success()) {
479314564Sdim        err.SetErrorStringWithFormat(
480314564Sdim            "couldn't read contents of reference variable %s: %s",
481314564Sdim            m_variable_sp->GetName().AsCString(), extract_error.AsCString());
482314564Sdim        return;
483314564Sdim      }
484309124Sdim
485314564Sdim      lldb::offset_t offset = 0;
486314564Sdim      lldb::addr_t reference_addr = valobj_extractor.GetAddress(&offset);
487309124Sdim
488321369Sdim      Status write_error;
489314564Sdim      map.WritePointerToMemory(load_addr, reference_addr, write_error);
490309124Sdim
491314564Sdim      if (!write_error.Success()) {
492314564Sdim        err.SetErrorStringWithFormat("couldn't write the contents of reference "
493314564Sdim                                     "variable %s to memory: %s",
494314564Sdim                                     m_variable_sp->GetName().AsCString(),
495314564Sdim                                     write_error.AsCString());
496314564Sdim        return;
497314564Sdim      }
498314564Sdim    } else {
499314564Sdim      AddressType address_type = eAddressTypeInvalid;
500314564Sdim      const bool scalar_is_load_address = false;
501314564Sdim      lldb::addr_t addr_of_valobj =
502314564Sdim          valobj_sp->GetAddressOf(scalar_is_load_address, &address_type);
503314564Sdim      if (addr_of_valobj != LLDB_INVALID_ADDRESS) {
504321369Sdim        Status write_error;
505314564Sdim        map.WritePointerToMemory(load_addr, addr_of_valobj, write_error);
506309124Sdim
507314564Sdim        if (!write_error.Success()) {
508314564Sdim          err.SetErrorStringWithFormat(
509314564Sdim              "couldn't write the address of variable %s to memory: %s",
510314564Sdim              m_variable_sp->GetName().AsCString(), write_error.AsCString());
511314564Sdim          return;
512314564Sdim        }
513314564Sdim      } else {
514314564Sdim        DataExtractor data;
515321369Sdim        Status extract_error;
516314564Sdim        valobj_sp->GetData(data, extract_error);
517314564Sdim        if (!extract_error.Success()) {
518314564Sdim          err.SetErrorStringWithFormat("couldn't get the value of %s: %s",
519314564Sdim                                       m_variable_sp->GetName().AsCString(),
520314564Sdim                                       extract_error.AsCString());
521314564Sdim          return;
522314564Sdim        }
523309124Sdim
524314564Sdim        if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
525314564Sdim          err.SetErrorStringWithFormat(
526314564Sdim              "trying to create a temporary region for %s but one exists",
527314564Sdim              m_variable_sp->GetName().AsCString());
528314564Sdim          return;
529254721Semaste        }
530309124Sdim
531314564Sdim        if (data.GetByteSize() < m_variable_sp->GetType()->GetByteSize()) {
532314564Sdim          if (data.GetByteSize() == 0 &&
533344779Sdim              !m_variable_sp->LocationExpression().IsValid()) {
534314564Sdim            err.SetErrorStringWithFormat("the variable '%s' has no location, "
535314564Sdim                                         "it may have been optimized out",
536314564Sdim                                         m_variable_sp->GetName().AsCString());
537314564Sdim          } else {
538314564Sdim            err.SetErrorStringWithFormat(
539314564Sdim                "size of variable %s (%" PRIu64
540314564Sdim                ") is larger than the ValueObject's size (%" PRIu64 ")",
541314564Sdim                m_variable_sp->GetName().AsCString(),
542353358Sdim                m_variable_sp->GetType()->GetByteSize().getValueOr(0),
543353358Sdim                data.GetByteSize());
544314564Sdim          }
545314564Sdim          return;
546314564Sdim        }
547309124Sdim
548314564Sdim        size_t bit_align =
549314564Sdim            m_variable_sp->GetType()->GetLayoutCompilerType().GetTypeBitAlign();
550314564Sdim        size_t byte_align = (bit_align + 7) / 8;
551309124Sdim
552314564Sdim        if (!byte_align)
553314564Sdim          byte_align = 1;
554309124Sdim
555321369Sdim        Status alloc_error;
556314564Sdim        const bool zero_memory = false;
557309124Sdim
558314564Sdim        m_temporary_allocation = map.Malloc(
559314564Sdim            data.GetByteSize(), byte_align,
560314564Sdim            lldb::ePermissionsReadable | lldb::ePermissionsWritable,
561314564Sdim            IRMemoryMap::eAllocationPolicyMirror, zero_memory, alloc_error);
562309124Sdim
563314564Sdim        m_temporary_allocation_size = data.GetByteSize();
564296417Sdim
565353358Sdim        m_original_data = std::make_shared<DataBufferHeap>(data.GetDataStart(),
566353358Sdim                                                           data.GetByteSize());
567309124Sdim
568314564Sdim        if (!alloc_error.Success()) {
569314564Sdim          err.SetErrorStringWithFormat(
570314564Sdim              "couldn't allocate a temporary region for %s: %s",
571314564Sdim              m_variable_sp->GetName().AsCString(), alloc_error.AsCString());
572314564Sdim          return;
573314564Sdim        }
574309124Sdim
575321369Sdim        Status write_error;
576309124Sdim
577314564Sdim        map.WriteMemory(m_temporary_allocation, data.GetDataStart(),
578314564Sdim                        data.GetByteSize(), write_error);
579309124Sdim
580314564Sdim        if (!write_error.Success()) {
581314564Sdim          err.SetErrorStringWithFormat(
582314564Sdim              "couldn't write to the temporary region for %s: %s",
583314564Sdim              m_variable_sp->GetName().AsCString(), write_error.AsCString());
584314564Sdim          return;
585314564Sdim        }
586309124Sdim
587321369Sdim        Status pointer_write_error;
588309124Sdim
589314564Sdim        map.WritePointerToMemory(load_addr, m_temporary_allocation,
590314564Sdim                                 pointer_write_error);
591309124Sdim
592314564Sdim        if (!pointer_write_error.Success()) {
593314564Sdim          err.SetErrorStringWithFormat(
594314564Sdim              "couldn't write the address of the temporary region for %s: %s",
595314564Sdim              m_variable_sp->GetName().AsCString(),
596314564Sdim              pointer_write_error.AsCString());
597254721Semaste        }
598314564Sdim      }
599254721Semaste    }
600314564Sdim  }
601309124Sdim
602314564Sdim  void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
603314564Sdim                     lldb::addr_t process_address, lldb::addr_t frame_top,
604321369Sdim                     lldb::addr_t frame_bottom, Status &err) override {
605314564Sdim    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
606254721Semaste
607314564Sdim    const lldb::addr_t load_addr = process_address + m_offset;
608314564Sdim    if (log) {
609314564Sdim      log->Printf("EntityVariable::Dematerialize [address = 0x%" PRIx64
610314564Sdim                  ", m_variable_sp = %s]",
611314564Sdim                  (uint64_t)load_addr, m_variable_sp->GetName().AsCString());
612314564Sdim    }
613309124Sdim
614314564Sdim    if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
615314564Sdim      ExecutionContextScope *scope = frame_sp.get();
616309124Sdim
617314564Sdim      if (!scope)
618314564Sdim        scope = map.GetBestExecutionContextScope();
619309124Sdim
620314564Sdim      lldb::ValueObjectSP valobj_sp =
621314564Sdim          ValueObjectVariable::Create(scope, m_variable_sp);
622309124Sdim
623314564Sdim      if (!valobj_sp) {
624314564Sdim        err.SetErrorStringWithFormat(
625314564Sdim            "couldn't get a value object for variable %s",
626314564Sdim            m_variable_sp->GetName().AsCString());
627314564Sdim        return;
628314564Sdim      }
629309124Sdim
630314564Sdim      lldb_private::DataExtractor data;
631309124Sdim
632321369Sdim      Status extract_error;
633309124Sdim
634314564Sdim      map.GetMemoryData(data, m_temporary_allocation, valobj_sp->GetByteSize(),
635314564Sdim                        extract_error);
636309124Sdim
637314564Sdim      if (!extract_error.Success()) {
638314564Sdim        err.SetErrorStringWithFormat("couldn't get the data for variable %s",
639314564Sdim                                     m_variable_sp->GetName().AsCString());
640314564Sdim        return;
641314564Sdim      }
642309124Sdim
643314564Sdim      bool actually_write = true;
644309124Sdim
645314564Sdim      if (m_original_data) {
646314564Sdim        if ((data.GetByteSize() == m_original_data->GetByteSize()) &&
647314564Sdim            !memcmp(m_original_data->GetBytes(), data.GetDataStart(),
648314564Sdim                    data.GetByteSize())) {
649314564Sdim          actually_write = false;
650314564Sdim        }
651314564Sdim      }
652309124Sdim
653321369Sdim      Status set_error;
654309124Sdim
655314564Sdim      if (actually_write) {
656314564Sdim        valobj_sp->SetData(data, set_error);
657309124Sdim
658314564Sdim        if (!set_error.Success()) {
659314564Sdim          err.SetErrorStringWithFormat(
660314564Sdim              "couldn't write the new contents of %s back into the variable",
661314564Sdim              m_variable_sp->GetName().AsCString());
662314564Sdim          return;
663314564Sdim        }
664314564Sdim      }
665309124Sdim
666321369Sdim      Status free_error;
667309124Sdim
668314564Sdim      map.Free(m_temporary_allocation, free_error);
669309124Sdim
670314564Sdim      if (!free_error.Success()) {
671314564Sdim        err.SetErrorStringWithFormat(
672314564Sdim            "couldn't free the temporary region for %s: %s",
673314564Sdim            m_variable_sp->GetName().AsCString(), free_error.AsCString());
674314564Sdim        return;
675314564Sdim      }
676309124Sdim
677314564Sdim      m_original_data.reset();
678314564Sdim      m_temporary_allocation = LLDB_INVALID_ADDRESS;
679314564Sdim      m_temporary_allocation_size = 0;
680254721Semaste    }
681314564Sdim  }
682309124Sdim
683314564Sdim  void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
684314564Sdim                 Log *log) override {
685314564Sdim    StreamString dump_stream;
686254721Semaste
687314564Sdim    const lldb::addr_t load_addr = process_address + m_offset;
688314564Sdim    dump_stream.Printf("0x%" PRIx64 ": EntityVariable\n", load_addr);
689309124Sdim
690321369Sdim    Status err;
691309124Sdim
692314564Sdim    lldb::addr_t ptr = LLDB_INVALID_ADDRESS;
693309124Sdim
694314564Sdim    {
695314564Sdim      dump_stream.Printf("Pointer:\n");
696309124Sdim
697314564Sdim      DataBufferHeap data(m_size, 0);
698309124Sdim
699314564Sdim      map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
700309124Sdim
701314564Sdim      if (!err.Success()) {
702314564Sdim        dump_stream.Printf("  <could not be read>\n");
703314564Sdim      } else {
704314564Sdim        DataExtractor extractor(data.GetBytes(), data.GetByteSize(),
705314564Sdim                                map.GetByteOrder(), map.GetAddressByteSize());
706309124Sdim
707321369Sdim        DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
708321369Sdim                     load_addr);
709309124Sdim
710314564Sdim        lldb::offset_t offset;
711309124Sdim
712314564Sdim        ptr = extractor.GetPointer(&offset);
713309124Sdim
714314564Sdim        dump_stream.PutChar('\n');
715314564Sdim      }
716314564Sdim    }
717309124Sdim
718314564Sdim    if (m_temporary_allocation == LLDB_INVALID_ADDRESS) {
719314564Sdim      dump_stream.Printf("Points to process memory:\n");
720314564Sdim    } else {
721314564Sdim      dump_stream.Printf("Temporary allocation:\n");
722314564Sdim    }
723309124Sdim
724314564Sdim    if (ptr == LLDB_INVALID_ADDRESS) {
725314564Sdim      dump_stream.Printf("  <could not be be found>\n");
726314564Sdim    } else {
727314564Sdim      DataBufferHeap data(m_temporary_allocation_size, 0);
728309124Sdim
729314564Sdim      map.ReadMemory(data.GetBytes(), m_temporary_allocation,
730314564Sdim                     m_temporary_allocation_size, err);
731309124Sdim
732314564Sdim      if (!err.Success()) {
733314564Sdim        dump_stream.Printf("  <could not be read>\n");
734314564Sdim      } else {
735321369Sdim        DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
736321369Sdim                     load_addr);
737309124Sdim
738314564Sdim        dump_stream.PutChar('\n');
739314564Sdim      }
740254721Semaste    }
741309124Sdim
742314564Sdim    log->PutString(dump_stream.GetString());
743314564Sdim  }
744309124Sdim
745314564Sdim  void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {
746314564Sdim    if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
747321369Sdim      Status free_error;
748309124Sdim
749314564Sdim      map.Free(m_temporary_allocation, free_error);
750254721Semaste
751314564Sdim      m_temporary_allocation = LLDB_INVALID_ADDRESS;
752314564Sdim      m_temporary_allocation_size = 0;
753254721Semaste    }
754314564Sdim  }
755296417Sdim
756254721Semasteprivate:
757314564Sdim  lldb::VariableSP m_variable_sp;
758314564Sdim  bool m_is_reference;
759314564Sdim  lldb::addr_t m_temporary_allocation;
760314564Sdim  size_t m_temporary_allocation_size;
761314564Sdim  lldb::DataBufferSP m_original_data;
762254721Semaste};
763254721Semaste
764321369Sdimuint32_t Materializer::AddVariable(lldb::VariableSP &variable_sp, Status &err) {
765314564Sdim  EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
766314564Sdim  iter->reset(new EntityVariable(variable_sp));
767314564Sdim  uint32_t ret = AddStructMember(**iter);
768314564Sdim  (*iter)->SetOffset(ret);
769314564Sdim  return ret;
770254721Semaste}
771254721Semaste
772314564Sdimclass EntityResultVariable : public Materializer::Entity {
773254721Semastepublic:
774314564Sdim  EntityResultVariable(const CompilerType &type, bool is_program_reference,
775314564Sdim                       bool keep_in_memory,
776314564Sdim                       Materializer::PersistentVariableDelegate *delegate)
777314564Sdim      : Entity(), m_type(type), m_is_program_reference(is_program_reference),
778254721Semaste        m_keep_in_memory(keep_in_memory),
779254721Semaste        m_temporary_allocation(LLDB_INVALID_ADDRESS),
780314564Sdim        m_temporary_allocation_size(0), m_delegate(delegate) {
781314564Sdim    // Hard-coding to maximum size of a pointer since all results are
782314564Sdim    // materialized by reference
783314564Sdim    m_size = 8;
784314564Sdim    m_alignment = 8;
785314564Sdim  }
786309124Sdim
787314564Sdim  void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
788321369Sdim                   lldb::addr_t process_address, Status &err) override {
789314564Sdim    if (!m_is_program_reference) {
790314564Sdim      if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
791314564Sdim        err.SetErrorString("Trying to create a temporary region for the result "
792314564Sdim                           "but one exists");
793314564Sdim        return;
794314564Sdim      }
795309124Sdim
796314564Sdim      const lldb::addr_t load_addr = process_address + m_offset;
797254721Semaste
798314564Sdim      ExecutionContextScope *exe_scope = map.GetBestExecutionContextScope();
799309124Sdim
800344779Sdim      llvm::Optional<uint64_t> byte_size = m_type.GetByteSize(exe_scope);
801344779Sdim      if (!byte_size) {
802344779Sdim        err.SetErrorString("can't get size of type");
803344779Sdim        return;
804344779Sdim      }
805314564Sdim      size_t bit_align = m_type.GetTypeBitAlign();
806314564Sdim      size_t byte_align = (bit_align + 7) / 8;
807309124Sdim
808314564Sdim      if (!byte_align)
809314564Sdim        byte_align = 1;
810296417Sdim
811321369Sdim      Status alloc_error;
812314564Sdim      const bool zero_memory = true;
813309124Sdim
814314564Sdim      m_temporary_allocation = map.Malloc(
815344779Sdim          *byte_size, byte_align,
816314564Sdim          lldb::ePermissionsReadable | lldb::ePermissionsWritable,
817314564Sdim          IRMemoryMap::eAllocationPolicyMirror, zero_memory, alloc_error);
818344779Sdim      m_temporary_allocation_size = *byte_size;
819309124Sdim
820314564Sdim      if (!alloc_error.Success()) {
821314564Sdim        err.SetErrorStringWithFormat(
822314564Sdim            "couldn't allocate a temporary region for the result: %s",
823314564Sdim            alloc_error.AsCString());
824314564Sdim        return;
825314564Sdim      }
826309124Sdim
827321369Sdim      Status pointer_write_error;
828309124Sdim
829314564Sdim      map.WritePointerToMemory(load_addr, m_temporary_allocation,
830314564Sdim                               pointer_write_error);
831314564Sdim
832314564Sdim      if (!pointer_write_error.Success()) {
833314564Sdim        err.SetErrorStringWithFormat("couldn't write the address of the "
834314564Sdim                                     "temporary region for the result: %s",
835314564Sdim                                     pointer_write_error.AsCString());
836314564Sdim      }
837254721Semaste    }
838314564Sdim  }
839309124Sdim
840314564Sdim  void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
841314564Sdim                     lldb::addr_t process_address, lldb::addr_t frame_top,
842321369Sdim                     lldb::addr_t frame_bottom, Status &err) override {
843314564Sdim    err.Clear();
844309124Sdim
845314564Sdim    ExecutionContextScope *exe_scope = map.GetBestExecutionContextScope();
846309124Sdim
847314564Sdim    if (!exe_scope) {
848314564Sdim      err.SetErrorString("Couldn't dematerialize a result variable: invalid "
849314564Sdim                         "execution context scope");
850314564Sdim      return;
851314564Sdim    }
852309124Sdim
853314564Sdim    lldb::addr_t address;
854321369Sdim    Status read_error;
855314564Sdim    const lldb::addr_t load_addr = process_address + m_offset;
856309124Sdim
857314564Sdim    map.ReadPointerFromMemory(&address, load_addr, read_error);
858309124Sdim
859314564Sdim    if (!read_error.Success()) {
860314564Sdim      err.SetErrorString("Couldn't dematerialize a result variable: couldn't "
861314564Sdim                         "read its address");
862314564Sdim      return;
863314564Sdim    }
864309124Sdim
865314564Sdim    lldb::TargetSP target_sp = exe_scope->CalculateTarget();
866309124Sdim
867314564Sdim    if (!target_sp) {
868314564Sdim      err.SetErrorString("Couldn't dematerialize a result variable: no target");
869314564Sdim      return;
870314564Sdim    }
871309124Sdim
872321369Sdim    Status type_system_error;
873314564Sdim    TypeSystem *type_system = target_sp->GetScratchTypeSystemForLanguage(
874314564Sdim        &type_system_error, m_type.GetMinimumLanguage());
875309124Sdim
876314564Sdim    if (!type_system) {
877314564Sdim      err.SetErrorStringWithFormat("Couldn't dematerialize a result variable: "
878314564Sdim                                   "couldn't get the corresponding type "
879314564Sdim                                   "system: %s",
880314564Sdim                                   type_system_error.AsCString());
881314564Sdim      return;
882314564Sdim    }
883309124Sdim
884314564Sdim    PersistentExpressionState *persistent_state =
885314564Sdim        type_system->GetPersistentExpressionState();
886309124Sdim
887314564Sdim    if (!persistent_state) {
888314564Sdim      err.SetErrorString("Couldn't dematerialize a result variable: "
889314564Sdim                         "corresponding type system doesn't handle persistent "
890314564Sdim                         "variables");
891314564Sdim      return;
892314564Sdim    }
893309124Sdim
894341825Sdim    ConstString name =
895341825Sdim        m_delegate
896341825Sdim            ? m_delegate->GetName()
897341825Sdim            : persistent_state->GetNextPersistentVariableName(
898341825Sdim                  *target_sp, persistent_state->GetPersistentVariablePrefix());
899309124Sdim
900314564Sdim    lldb::ExpressionVariableSP ret = persistent_state->CreatePersistentVariable(
901314564Sdim        exe_scope, name, m_type, map.GetByteOrder(), map.GetAddressByteSize());
902309124Sdim
903314564Sdim    if (!ret) {
904314564Sdim      err.SetErrorStringWithFormat("couldn't dematerialize a result variable: "
905314564Sdim                                   "failed to make persistent variable %s",
906314564Sdim                                   name.AsCString());
907314564Sdim      return;
908314564Sdim    }
909309124Sdim
910314564Sdim    lldb::ProcessSP process_sp =
911314564Sdim        map.GetBestExecutionContextScope()->CalculateProcess();
912309124Sdim
913314564Sdim    if (m_delegate) {
914314564Sdim      m_delegate->DidDematerialize(ret);
915314564Sdim    }
916309124Sdim
917314564Sdim    bool can_persist =
918314564Sdim        (m_is_program_reference && process_sp && process_sp->CanJIT() &&
919314564Sdim         !(address >= frame_bottom && address < frame_top));
920254721Semaste
921314564Sdim    if (can_persist && m_keep_in_memory) {
922314564Sdim      ret->m_live_sp = ValueObjectConstResult::Create(exe_scope, m_type, name,
923314564Sdim                                                      address, eAddressTypeLoad,
924314564Sdim                                                      map.GetAddressByteSize());
925314564Sdim    }
926309124Sdim
927314564Sdim    ret->ValueUpdated();
928309124Sdim
929314564Sdim    const size_t pvar_byte_size = ret->GetByteSize();
930314564Sdim    uint8_t *pvar_data = ret->GetValueBytes();
931309124Sdim
932314564Sdim    map.ReadMemory(pvar_data, address, pvar_byte_size, read_error);
933309124Sdim
934314564Sdim    if (!read_error.Success()) {
935314564Sdim      err.SetErrorString(
936314564Sdim          "Couldn't dematerialize a result variable: couldn't read its memory");
937314564Sdim      return;
938314564Sdim    }
939309124Sdim
940314564Sdim    if (!can_persist || !m_keep_in_memory) {
941314564Sdim      ret->m_flags |= ExpressionVariable::EVNeedsAllocation;
942309124Sdim
943314564Sdim      if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
944321369Sdim        Status free_error;
945314564Sdim        map.Free(m_temporary_allocation, free_error);
946314564Sdim      }
947314564Sdim    } else {
948314564Sdim      ret->m_flags |= ExpressionVariable::EVIsLLDBAllocated;
949254721Semaste    }
950309124Sdim
951314564Sdim    m_temporary_allocation = LLDB_INVALID_ADDRESS;
952314564Sdim    m_temporary_allocation_size = 0;
953314564Sdim  }
954309124Sdim
955314564Sdim  void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
956314564Sdim                 Log *log) override {
957314564Sdim    StreamString dump_stream;
958254721Semaste
959314564Sdim    const lldb::addr_t load_addr = process_address + m_offset;
960309124Sdim
961314564Sdim    dump_stream.Printf("0x%" PRIx64 ": EntityResultVariable\n", load_addr);
962309124Sdim
963321369Sdim    Status err;
964309124Sdim
965314564Sdim    lldb::addr_t ptr = LLDB_INVALID_ADDRESS;
966309124Sdim
967314564Sdim    {
968314564Sdim      dump_stream.Printf("Pointer:\n");
969309124Sdim
970314564Sdim      DataBufferHeap data(m_size, 0);
971309124Sdim
972314564Sdim      map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
973309124Sdim
974314564Sdim      if (!err.Success()) {
975314564Sdim        dump_stream.Printf("  <could not be read>\n");
976314564Sdim      } else {
977314564Sdim        DataExtractor extractor(data.GetBytes(), data.GetByteSize(),
978314564Sdim                                map.GetByteOrder(), map.GetAddressByteSize());
979309124Sdim
980321369Sdim        DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
981321369Sdim                     load_addr);
982309124Sdim
983314564Sdim        lldb::offset_t offset;
984309124Sdim
985314564Sdim        ptr = extractor.GetPointer(&offset);
986309124Sdim
987314564Sdim        dump_stream.PutChar('\n');
988314564Sdim      }
989314564Sdim    }
990309124Sdim
991314564Sdim    if (m_temporary_allocation == LLDB_INVALID_ADDRESS) {
992314564Sdim      dump_stream.Printf("Points to process memory:\n");
993314564Sdim    } else {
994314564Sdim      dump_stream.Printf("Temporary allocation:\n");
995314564Sdim    }
996309124Sdim
997314564Sdim    if (ptr == LLDB_INVALID_ADDRESS) {
998314564Sdim      dump_stream.Printf("  <could not be be found>\n");
999314564Sdim    } else {
1000314564Sdim      DataBufferHeap data(m_temporary_allocation_size, 0);
1001309124Sdim
1002314564Sdim      map.ReadMemory(data.GetBytes(), m_temporary_allocation,
1003314564Sdim                     m_temporary_allocation_size, err);
1004309124Sdim
1005314564Sdim      if (!err.Success()) {
1006314564Sdim        dump_stream.Printf("  <could not be read>\n");
1007314564Sdim      } else {
1008321369Sdim        DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
1009321369Sdim                     load_addr);
1010309124Sdim
1011314564Sdim        dump_stream.PutChar('\n');
1012314564Sdim      }
1013254721Semaste    }
1014309124Sdim
1015314564Sdim    log->PutString(dump_stream.GetString());
1016314564Sdim  }
1017309124Sdim
1018314564Sdim  void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {
1019314564Sdim    if (!m_keep_in_memory && m_temporary_allocation != LLDB_INVALID_ADDRESS) {
1020321369Sdim      Status free_error;
1021309124Sdim
1022314564Sdim      map.Free(m_temporary_allocation, free_error);
1023254721Semaste    }
1024296417Sdim
1025314564Sdim    m_temporary_allocation = LLDB_INVALID_ADDRESS;
1026314564Sdim    m_temporary_allocation_size = 0;
1027314564Sdim  }
1028314564Sdim
1029254721Semasteprivate:
1030314564Sdim  CompilerType m_type;
1031314564Sdim  bool m_is_program_reference;
1032314564Sdim  bool m_keep_in_memory;
1033309124Sdim
1034314564Sdim  lldb::addr_t m_temporary_allocation;
1035314564Sdim  size_t m_temporary_allocation_size;
1036314564Sdim  Materializer::PersistentVariableDelegate *m_delegate;
1037254721Semaste};
1038254721Semaste
1039314564Sdimuint32_t Materializer::AddResultVariable(const CompilerType &type,
1040314564Sdim                                         bool is_program_reference,
1041314564Sdim                                         bool keep_in_memory,
1042314564Sdim                                         PersistentVariableDelegate *delegate,
1043321369Sdim                                         Status &err) {
1044314564Sdim  EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
1045314564Sdim  iter->reset(new EntityResultVariable(type, is_program_reference,
1046314564Sdim                                       keep_in_memory, delegate));
1047314564Sdim  uint32_t ret = AddStructMember(**iter);
1048314564Sdim  (*iter)->SetOffset(ret);
1049314564Sdim  return ret;
1050254721Semaste}
1051254721Semaste
1052314564Sdimclass EntitySymbol : public Materializer::Entity {
1053254721Semastepublic:
1054314564Sdim  EntitySymbol(const Symbol &symbol) : Entity(), m_symbol(symbol) {
1055314564Sdim    // Hard-coding to maximum size of a symbol
1056314564Sdim    m_size = 8;
1057314564Sdim    m_alignment = 8;
1058314564Sdim  }
1059309124Sdim
1060314564Sdim  void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1061321369Sdim                   lldb::addr_t process_address, Status &err) override {
1062314564Sdim    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
1063254721Semaste
1064314564Sdim    const lldb::addr_t load_addr = process_address + m_offset;
1065254721Semaste
1066314564Sdim    if (log) {
1067314564Sdim      log->Printf("EntitySymbol::Materialize [address = 0x%" PRIx64
1068314564Sdim                  ", m_symbol = %s]",
1069314564Sdim                  (uint64_t)load_addr, m_symbol.GetName().AsCString());
1070314564Sdim    }
1071309124Sdim
1072314564Sdim    const Address sym_address = m_symbol.GetAddress();
1073254721Semaste
1074314564Sdim    ExecutionContextScope *exe_scope = map.GetBestExecutionContextScope();
1075309124Sdim
1076314564Sdim    lldb::TargetSP target_sp;
1077309124Sdim
1078314564Sdim    if (exe_scope)
1079314564Sdim      target_sp = map.GetBestExecutionContextScope()->CalculateTarget();
1080309124Sdim
1081314564Sdim    if (!target_sp) {
1082314564Sdim      err.SetErrorStringWithFormat(
1083314564Sdim          "couldn't resolve symbol %s because there is no target",
1084314564Sdim          m_symbol.GetName().AsCString());
1085314564Sdim      return;
1086314564Sdim    }
1087309124Sdim
1088314564Sdim    lldb::addr_t resolved_address = sym_address.GetLoadAddress(target_sp.get());
1089309124Sdim
1090314564Sdim    if (resolved_address == LLDB_INVALID_ADDRESS)
1091314564Sdim      resolved_address = sym_address.GetFileAddress();
1092309124Sdim
1093321369Sdim    Status pointer_write_error;
1094309124Sdim
1095314564Sdim    map.WritePointerToMemory(load_addr, resolved_address, pointer_write_error);
1096309124Sdim
1097314564Sdim    if (!pointer_write_error.Success()) {
1098314564Sdim      err.SetErrorStringWithFormat(
1099314564Sdim          "couldn't write the address of symbol %s: %s",
1100314564Sdim          m_symbol.GetName().AsCString(), pointer_write_error.AsCString());
1101314564Sdim      return;
1102254721Semaste    }
1103314564Sdim  }
1104309124Sdim
1105314564Sdim  void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1106314564Sdim                     lldb::addr_t process_address, lldb::addr_t frame_top,
1107321369Sdim                     lldb::addr_t frame_bottom, Status &err) override {
1108314564Sdim    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
1109254721Semaste
1110314564Sdim    const lldb::addr_t load_addr = process_address + m_offset;
1111254721Semaste
1112314564Sdim    if (log) {
1113314564Sdim      log->Printf("EntitySymbol::Dematerialize [address = 0x%" PRIx64
1114314564Sdim                  ", m_symbol = %s]",
1115314564Sdim                  (uint64_t)load_addr, m_symbol.GetName().AsCString());
1116254721Semaste    }
1117309124Sdim
1118314564Sdim    // no work needs to be done
1119314564Sdim  }
1120309124Sdim
1121314564Sdim  void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
1122314564Sdim                 Log *log) override {
1123314564Sdim    StreamString dump_stream;
1124309124Sdim
1125321369Sdim    Status err;
1126254721Semaste
1127314564Sdim    const lldb::addr_t load_addr = process_address + m_offset;
1128309124Sdim
1129314564Sdim    dump_stream.Printf("0x%" PRIx64 ": EntitySymbol (%s)\n", load_addr,
1130314564Sdim                       m_symbol.GetName().AsCString());
1131309124Sdim
1132314564Sdim    {
1133314564Sdim      dump_stream.Printf("Pointer:\n");
1134309124Sdim
1135314564Sdim      DataBufferHeap data(m_size, 0);
1136309124Sdim
1137314564Sdim      map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
1138309124Sdim
1139314564Sdim      if (!err.Success()) {
1140314564Sdim        dump_stream.Printf("  <could not be read>\n");
1141314564Sdim      } else {
1142321369Sdim        DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
1143321369Sdim                     load_addr);
1144309124Sdim
1145314564Sdim        dump_stream.PutChar('\n');
1146314564Sdim      }
1147254721Semaste    }
1148309124Sdim
1149314564Sdim    log->PutString(dump_stream.GetString());
1150314564Sdim  }
1151296417Sdim
1152314564Sdim  void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {}
1153314564Sdim
1154254721Semasteprivate:
1155314564Sdim  Symbol m_symbol;
1156254721Semaste};
1157254721Semaste
1158321369Sdimuint32_t Materializer::AddSymbol(const Symbol &symbol_sp, Status &err) {
1159314564Sdim  EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
1160314564Sdim  iter->reset(new EntitySymbol(symbol_sp));
1161314564Sdim  uint32_t ret = AddStructMember(**iter);
1162314564Sdim  (*iter)->SetOffset(ret);
1163314564Sdim  return ret;
1164254721Semaste}
1165254721Semaste
1166314564Sdimclass EntityRegister : public Materializer::Entity {
1167254721Semastepublic:
1168314564Sdim  EntityRegister(const RegisterInfo &register_info)
1169314564Sdim      : Entity(), m_register_info(register_info) {
1170314564Sdim    // Hard-coding alignment conservatively
1171314564Sdim    m_size = m_register_info.byte_size;
1172314564Sdim    m_alignment = m_register_info.byte_size;
1173314564Sdim  }
1174314564Sdim
1175314564Sdim  void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1176321369Sdim                   lldb::addr_t process_address, Status &err) override {
1177314564Sdim    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
1178314564Sdim
1179314564Sdim    const lldb::addr_t load_addr = process_address + m_offset;
1180314564Sdim
1181314564Sdim    if (log) {
1182314564Sdim      log->Printf("EntityRegister::Materialize [address = 0x%" PRIx64
1183314564Sdim                  ", m_register_info = %s]",
1184314564Sdim                  (uint64_t)load_addr, m_register_info.name);
1185254721Semaste    }
1186309124Sdim
1187314564Sdim    RegisterValue reg_value;
1188309124Sdim
1189314564Sdim    if (!frame_sp.get()) {
1190314564Sdim      err.SetErrorStringWithFormat(
1191314564Sdim          "couldn't materialize register %s without a stack frame",
1192314564Sdim          m_register_info.name);
1193314564Sdim      return;
1194314564Sdim    }
1195254721Semaste
1196314564Sdim    lldb::RegisterContextSP reg_context_sp = frame_sp->GetRegisterContext();
1197254721Semaste
1198314564Sdim    if (!reg_context_sp->ReadRegister(&m_register_info, reg_value)) {
1199314564Sdim      err.SetErrorStringWithFormat("couldn't read the value of register %s",
1200314564Sdim                                   m_register_info.name);
1201314564Sdim      return;
1202314564Sdim    }
1203309124Sdim
1204314564Sdim    DataExtractor register_data;
1205309124Sdim
1206314564Sdim    if (!reg_value.GetData(register_data)) {
1207314564Sdim      err.SetErrorStringWithFormat("couldn't get the data for register %s",
1208314564Sdim                                   m_register_info.name);
1209314564Sdim      return;
1210314564Sdim    }
1211309124Sdim
1212314564Sdim    if (register_data.GetByteSize() != m_register_info.byte_size) {
1213314564Sdim      err.SetErrorStringWithFormat(
1214314564Sdim          "data for register %s had size %llu but we expected %llu",
1215314564Sdim          m_register_info.name, (unsigned long long)register_data.GetByteSize(),
1216314564Sdim          (unsigned long long)m_register_info.byte_size);
1217314564Sdim      return;
1218314564Sdim    }
1219309124Sdim
1220353358Sdim    m_register_contents = std::make_shared<DataBufferHeap>(
1221353358Sdim        register_data.GetDataStart(), register_data.GetByteSize());
1222309124Sdim
1223321369Sdim    Status write_error;
1224309124Sdim
1225314564Sdim    map.WriteMemory(load_addr, register_data.GetDataStart(),
1226314564Sdim                    register_data.GetByteSize(), write_error);
1227309124Sdim
1228314564Sdim    if (!write_error.Success()) {
1229314564Sdim      err.SetErrorStringWithFormat(
1230314564Sdim          "couldn't write the contents of register %s: %s",
1231314564Sdim          m_register_info.name, write_error.AsCString());
1232314564Sdim      return;
1233254721Semaste    }
1234314564Sdim  }
1235309124Sdim
1236314564Sdim  void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1237314564Sdim                     lldb::addr_t process_address, lldb::addr_t frame_top,
1238321369Sdim                     lldb::addr_t frame_bottom, Status &err) override {
1239314564Sdim    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
1240309124Sdim
1241314564Sdim    const lldb::addr_t load_addr = process_address + m_offset;
1242254721Semaste
1243314564Sdim    if (log) {
1244314564Sdim      log->Printf("EntityRegister::Dematerialize [address = 0x%" PRIx64
1245314564Sdim                  ", m_register_info = %s]",
1246314564Sdim                  (uint64_t)load_addr, m_register_info.name);
1247314564Sdim    }
1248309124Sdim
1249321369Sdim    Status extract_error;
1250309124Sdim
1251314564Sdim    DataExtractor register_data;
1252309124Sdim
1253314564Sdim    if (!frame_sp.get()) {
1254314564Sdim      err.SetErrorStringWithFormat(
1255314564Sdim          "couldn't dematerialize register %s without a stack frame",
1256314564Sdim          m_register_info.name);
1257314564Sdim      return;
1258314564Sdim    }
1259309124Sdim
1260314564Sdim    lldb::RegisterContextSP reg_context_sp = frame_sp->GetRegisterContext();
1261309124Sdim
1262314564Sdim    map.GetMemoryData(register_data, load_addr, m_register_info.byte_size,
1263314564Sdim                      extract_error);
1264309124Sdim
1265314564Sdim    if (!extract_error.Success()) {
1266314564Sdim      err.SetErrorStringWithFormat("couldn't get the data for register %s: %s",
1267314564Sdim                                   m_register_info.name,
1268314564Sdim                                   extract_error.AsCString());
1269314564Sdim      return;
1270314564Sdim    }
1271309124Sdim
1272314564Sdim    if (!memcmp(register_data.GetDataStart(), m_register_contents->GetBytes(),
1273314564Sdim                register_data.GetByteSize())) {
1274314564Sdim      // No write required, and in particular we avoid errors if the register
1275314564Sdim      // wasn't writable
1276309124Sdim
1277314564Sdim      m_register_contents.reset();
1278314564Sdim      return;
1279314564Sdim    }
1280309124Sdim
1281314564Sdim    m_register_contents.reset();
1282309124Sdim
1283314564Sdim    RegisterValue register_value(
1284314564Sdim        const_cast<uint8_t *>(register_data.GetDataStart()),
1285314564Sdim        register_data.GetByteSize(), register_data.GetByteOrder());
1286309124Sdim
1287314564Sdim    if (!reg_context_sp->WriteRegister(&m_register_info, register_value)) {
1288314564Sdim      err.SetErrorStringWithFormat("couldn't write the value of register %s",
1289314564Sdim                                   m_register_info.name);
1290314564Sdim      return;
1291254721Semaste    }
1292314564Sdim  }
1293309124Sdim
1294314564Sdim  void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
1295314564Sdim                 Log *log) override {
1296314564Sdim    StreamString dump_stream;
1297309124Sdim
1298321369Sdim    Status err;
1299309124Sdim
1300314564Sdim    const lldb::addr_t load_addr = process_address + m_offset;
1301254721Semaste
1302314564Sdim    dump_stream.Printf("0x%" PRIx64 ": EntityRegister (%s)\n", load_addr,
1303314564Sdim                       m_register_info.name);
1304309124Sdim
1305314564Sdim    {
1306314564Sdim      dump_stream.Printf("Value:\n");
1307309124Sdim
1308314564Sdim      DataBufferHeap data(m_size, 0);
1309309124Sdim
1310314564Sdim      map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
1311309124Sdim
1312314564Sdim      if (!err.Success()) {
1313314564Sdim        dump_stream.Printf("  <could not be read>\n");
1314314564Sdim      } else {
1315321369Sdim        DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
1316321369Sdim                     load_addr);
1317309124Sdim
1318314564Sdim        dump_stream.PutChar('\n');
1319314564Sdim      }
1320314564Sdim    }
1321309124Sdim
1322314564Sdim    log->PutString(dump_stream.GetString());
1323314564Sdim  }
1324309124Sdim
1325314564Sdim  void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {}
1326309124Sdim
1327254721Semasteprivate:
1328314564Sdim  RegisterInfo m_register_info;
1329314564Sdim  lldb::DataBufferSP m_register_contents;
1330254721Semaste};
1331254721Semaste
1332314564Sdimuint32_t Materializer::AddRegister(const RegisterInfo &register_info,
1333321369Sdim                                   Status &err) {
1334314564Sdim  EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
1335314564Sdim  iter->reset(new EntityRegister(register_info));
1336314564Sdim  uint32_t ret = AddStructMember(**iter);
1337314564Sdim  (*iter)->SetOffset(ret);
1338314564Sdim  return ret;
1339254721Semaste}
1340254721Semaste
1341314564SdimMaterializer::Materializer()
1342314564Sdim    : m_dematerializer_wp(), m_current_offset(0), m_struct_alignment(8) {}
1343254721Semaste
1344314564SdimMaterializer::~Materializer() {
1345314564Sdim  DematerializerSP dematerializer_sp = m_dematerializer_wp.lock();
1346309124Sdim
1347314564Sdim  if (dematerializer_sp)
1348314564Sdim    dematerializer_sp->Wipe();
1349254721Semaste}
1350254721Semaste
1351254721SemasteMaterializer::DematerializerSP
1352314564SdimMaterializer::Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1353321369Sdim                          lldb::addr_t process_address, Status &error) {
1354314564Sdim  ExecutionContextScope *exe_scope = frame_sp.get();
1355276479Sdim
1356314564Sdim  if (!exe_scope)
1357314564Sdim    exe_scope = map.GetBestExecutionContextScope();
1358276479Sdim
1359314564Sdim  DematerializerSP dematerializer_sp = m_dematerializer_wp.lock();
1360276479Sdim
1361314564Sdim  if (dematerializer_sp) {
1362314564Sdim    error.SetErrorToGenericError();
1363314564Sdim    error.SetErrorString("Couldn't materialize: already materialized");
1364314564Sdim  }
1365276479Sdim
1366314564Sdim  DematerializerSP ret(
1367314564Sdim      new Dematerializer(*this, frame_sp, map, process_address));
1368276479Sdim
1369314564Sdim  if (!exe_scope) {
1370314564Sdim    error.SetErrorToGenericError();
1371314564Sdim    error.SetErrorString("Couldn't materialize: target doesn't exist");
1372314564Sdim  }
1373276479Sdim
1374314564Sdim  for (EntityUP &entity_up : m_entities) {
1375314564Sdim    entity_up->Materialize(frame_sp, map, process_address, error);
1376276479Sdim
1377314564Sdim    if (!error.Success())
1378314564Sdim      return DematerializerSP();
1379314564Sdim  }
1380276479Sdim
1381314564Sdim  if (Log *log =
1382314564Sdim          lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)) {
1383314564Sdim    log->Printf(
1384314564Sdim        "Materializer::Materialize (frame_sp = %p, process_address = 0x%" PRIx64
1385314564Sdim        ") materialized:",
1386314564Sdim        static_cast<void *>(frame_sp.get()), process_address);
1387314564Sdim    for (EntityUP &entity_up : m_entities)
1388314564Sdim      entity_up->DumpToLog(map, process_address, log);
1389314564Sdim  }
1390276479Sdim
1391314564Sdim  m_dematerializer_wp = ret;
1392276479Sdim
1393314564Sdim  return ret;
1394254721Semaste}
1395254721Semaste
1396321369Sdimvoid Materializer::Dematerializer::Dematerialize(Status &error,
1397314564Sdim                                                 lldb::addr_t frame_bottom,
1398314564Sdim                                                 lldb::addr_t frame_top) {
1399314564Sdim  lldb::StackFrameSP frame_sp;
1400254721Semaste
1401314564Sdim  lldb::ThreadSP thread_sp = m_thread_wp.lock();
1402314564Sdim  if (thread_sp)
1403314564Sdim    frame_sp = thread_sp->GetFrameWithStackID(m_stack_id);
1404276479Sdim
1405314564Sdim  ExecutionContextScope *exe_scope = m_map->GetBestExecutionContextScope();
1406276479Sdim
1407314564Sdim  if (!IsValid()) {
1408314564Sdim    error.SetErrorToGenericError();
1409314564Sdim    error.SetErrorString("Couldn't dematerialize: invalid dematerializer");
1410314564Sdim  }
1411276479Sdim
1412314564Sdim  if (!exe_scope) {
1413314564Sdim    error.SetErrorToGenericError();
1414314564Sdim    error.SetErrorString("Couldn't dematerialize: target is gone");
1415314564Sdim  } else {
1416314564Sdim    if (Log *log =
1417314564Sdim            lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)) {
1418314564Sdim      log->Printf("Materializer::Dematerialize (frame_sp = %p, process_address "
1419314564Sdim                  "= 0x%" PRIx64 ") about to dematerialize:",
1420314564Sdim                  static_cast<void *>(frame_sp.get()), m_process_address);
1421314564Sdim      for (EntityUP &entity_up : m_materializer->m_entities)
1422314564Sdim        entity_up->DumpToLog(*m_map, m_process_address, log);
1423254721Semaste    }
1424276479Sdim
1425314564Sdim    for (EntityUP &entity_up : m_materializer->m_entities) {
1426314564Sdim      entity_up->Dematerialize(frame_sp, *m_map, m_process_address, frame_top,
1427314564Sdim                               frame_bottom, error);
1428276479Sdim
1429314564Sdim      if (!error.Success())
1430314564Sdim        break;
1431254721Semaste    }
1432314564Sdim  }
1433276479Sdim
1434314564Sdim  Wipe();
1435254721Semaste}
1436254721Semaste
1437314564Sdimvoid Materializer::Dematerializer::Wipe() {
1438314564Sdim  if (!IsValid())
1439314564Sdim    return;
1440309124Sdim
1441314564Sdim  for (EntityUP &entity_up : m_materializer->m_entities) {
1442314564Sdim    entity_up->Wipe(*m_map, m_process_address);
1443314564Sdim  }
1444254721Semaste
1445314564Sdim  m_materializer = nullptr;
1446314564Sdim  m_map = nullptr;
1447314564Sdim  m_process_address = LLDB_INVALID_ADDRESS;
1448254721Semaste}
1449296417Sdim
1450314564SdimMaterializer::PersistentVariableDelegate::~PersistentVariableDelegate() =
1451314564Sdim    default;
1452