Materializer.cpp revision 344779
1254721Semaste//===-- Materializer.cpp ----------------------------------------*- C++ -*-===//
2254721Semaste//
3254721Semaste//                     The LLVM Compiler Infrastructure
4254721Semaste//
5254721Semaste// This file is distributed under the University of Illinois Open Source
6254721Semaste// License. See LICENSE.TXT for details.
7254721Semaste//
8254721Semaste//===----------------------------------------------------------------------===//
9254721Semaste
10314564Sdim#include "lldb/Expression/Materializer.h"
11321369Sdim#include "lldb/Core/DumpDataExtractor.h"
12254721Semaste#include "lldb/Core/ValueObjectConstResult.h"
13254721Semaste#include "lldb/Core/ValueObjectVariable.h"
14296417Sdim#include "lldb/Expression/ExpressionVariable.h"
15254721Semaste#include "lldb/Symbol/ClangASTContext.h"
16254721Semaste#include "lldb/Symbol/Symbol.h"
17254721Semaste#include "lldb/Symbol/Type.h"
18254721Semaste#include "lldb/Symbol/Variable.h"
19254721Semaste#include "lldb/Target/ExecutionContext.h"
20254721Semaste#include "lldb/Target/RegisterContext.h"
21254721Semaste#include "lldb/Target/StackFrame.h"
22254721Semaste#include "lldb/Target/Target.h"
23254721Semaste#include "lldb/Target/Thread.h"
24321369Sdim#include "lldb/Utility/Log.h"
25344779Sdim#include "lldb/Utility/RegisterValue.h"
26254721Semaste
27254721Semasteusing namespace lldb_private;
28254721Semaste
29314564Sdimuint32_t Materializer::AddStructMember(Entity &entity) {
30314564Sdim  uint32_t size = entity.GetSize();
31314564Sdim  uint32_t alignment = entity.GetAlignment();
32309124Sdim
33314564Sdim  uint32_t ret;
34309124Sdim
35314564Sdim  if (m_current_offset == 0)
36314564Sdim    m_struct_alignment = alignment;
37309124Sdim
38314564Sdim  if (m_current_offset % alignment)
39314564Sdim    m_current_offset += (alignment - (m_current_offset % alignment));
40309124Sdim
41314564Sdim  ret = m_current_offset;
42309124Sdim
43314564Sdim  m_current_offset += size;
44309124Sdim
45314564Sdim  return ret;
46254721Semaste}
47254721Semaste
48314564Sdimvoid Materializer::Entity::SetSizeAndAlignmentFromType(CompilerType &type) {
49344779Sdim  if (llvm::Optional<uint64_t> size = type.GetByteSize(nullptr))
50344779Sdim    m_size = *size;
51309124Sdim
52314564Sdim  uint32_t bit_alignment = type.GetTypeBitAlign();
53309124Sdim
54314564Sdim  if (bit_alignment % 8) {
55314564Sdim    bit_alignment += 8;
56314564Sdim    bit_alignment &= ~((uint32_t)0x111u);
57314564Sdim  }
58309124Sdim
59314564Sdim  m_alignment = bit_alignment / 8;
60254721Semaste}
61254721Semaste
62314564Sdimclass EntityPersistentVariable : public Materializer::Entity {
63254721Semastepublic:
64314564Sdim  EntityPersistentVariable(lldb::ExpressionVariableSP &persistent_variable_sp,
65314564Sdim                           Materializer::PersistentVariableDelegate *delegate)
66314564Sdim      : Entity(), m_persistent_variable_sp(persistent_variable_sp),
67314564Sdim        m_delegate(delegate) {
68314564Sdim    // Hard-coding to maximum size of a pointer since persistent variables are
69314564Sdim    // materialized by reference
70314564Sdim    m_size = 8;
71314564Sdim    m_alignment = 8;
72314564Sdim  }
73309124Sdim
74321369Sdim  void MakeAllocation(IRMemoryMap &map, Status &err) {
75314564Sdim    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
76254721Semaste
77341825Sdim    // Allocate a spare memory area to store the persistent variable's
78341825Sdim    // contents.
79309124Sdim
80321369Sdim    Status allocate_error;
81314564Sdim    const bool zero_memory = false;
82309124Sdim
83314564Sdim    lldb::addr_t mem = map.Malloc(
84314564Sdim        m_persistent_variable_sp->GetByteSize(), 8,
85314564Sdim        lldb::ePermissionsReadable | lldb::ePermissionsWritable,
86314564Sdim        IRMemoryMap::eAllocationPolicyMirror, zero_memory, allocate_error);
87309124Sdim
88314564Sdim    if (!allocate_error.Success()) {
89314564Sdim      err.SetErrorStringWithFormat(
90314564Sdim          "couldn't allocate a memory area to store %s: %s",
91314564Sdim          m_persistent_variable_sp->GetName().GetCString(),
92314564Sdim          allocate_error.AsCString());
93314564Sdim      return;
94314564Sdim    }
95309124Sdim
96314564Sdim    if (log)
97314564Sdim      log->Printf("Allocated %s (0x%" PRIx64 ") successfully",
98314564Sdim                  m_persistent_variable_sp->GetName().GetCString(), mem);
99309124Sdim
100314564Sdim    // Put the location of the spare memory into the live data of the
101314564Sdim    // ValueObject.
102309124Sdim
103314564Sdim    m_persistent_variable_sp->m_live_sp = ValueObjectConstResult::Create(
104314564Sdim        map.GetBestExecutionContextScope(),
105314564Sdim        m_persistent_variable_sp->GetCompilerType(),
106314564Sdim        m_persistent_variable_sp->GetName(), mem, eAddressTypeLoad,
107314564Sdim        map.GetAddressByteSize());
108309124Sdim
109314564Sdim    // Clear the flag if the variable will never be deallocated.
110309124Sdim
111314564Sdim    if (m_persistent_variable_sp->m_flags &
112314564Sdim        ExpressionVariable::EVKeepInTarget) {
113321369Sdim      Status leak_error;
114314564Sdim      map.Leak(mem, leak_error);
115314564Sdim      m_persistent_variable_sp->m_flags &=
116314564Sdim          ~ExpressionVariable::EVNeedsAllocation;
117314564Sdim    }
118309124Sdim
119314564Sdim    // Write the contents of the variable to the area.
120309124Sdim
121321369Sdim    Status write_error;
122309124Sdim
123314564Sdim    map.WriteMemory(mem, m_persistent_variable_sp->GetValueBytes(),
124314564Sdim                    m_persistent_variable_sp->GetByteSize(), write_error);
125309124Sdim
126314564Sdim    if (!write_error.Success()) {
127314564Sdim      err.SetErrorStringWithFormat(
128314564Sdim          "couldn't write %s to the target: %s",
129314564Sdim          m_persistent_variable_sp->GetName().AsCString(),
130314564Sdim          write_error.AsCString());
131314564Sdim      return;
132254721Semaste    }
133314564Sdim  }
134309124Sdim
135321369Sdim  void DestroyAllocation(IRMemoryMap &map, Status &err) {
136321369Sdim    Status deallocate_error;
137309124Sdim
138314564Sdim    map.Free((lldb::addr_t)m_persistent_variable_sp->m_live_sp->GetValue()
139314564Sdim                 .GetScalar()
140314564Sdim                 .ULongLong(),
141314564Sdim             deallocate_error);
142309124Sdim
143314564Sdim    m_persistent_variable_sp->m_live_sp.reset();
144309124Sdim
145314564Sdim    if (!deallocate_error.Success()) {
146314564Sdim      err.SetErrorStringWithFormat(
147314564Sdim          "couldn't deallocate memory for %s: %s",
148314564Sdim          m_persistent_variable_sp->GetName().GetCString(),
149314564Sdim          deallocate_error.AsCString());
150254721Semaste    }
151314564Sdim  }
152309124Sdim
153314564Sdim  void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
154321369Sdim                   lldb::addr_t process_address, Status &err) override {
155314564Sdim    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
156254721Semaste
157314564Sdim    const lldb::addr_t load_addr = process_address + m_offset;
158309124Sdim
159314564Sdim    if (log) {
160314564Sdim      log->Printf("EntityPersistentVariable::Materialize [address = 0x%" PRIx64
161314564Sdim                  ", m_name = %s, m_flags = 0x%hx]",
162314564Sdim                  (uint64_t)load_addr,
163314564Sdim                  m_persistent_variable_sp->GetName().AsCString(),
164314564Sdim                  m_persistent_variable_sp->m_flags);
165314564Sdim    }
166309124Sdim
167314564Sdim    if (m_persistent_variable_sp->m_flags &
168314564Sdim        ExpressionVariable::EVNeedsAllocation) {
169314564Sdim      MakeAllocation(map, err);
170314564Sdim      m_persistent_variable_sp->m_flags |=
171314564Sdim          ExpressionVariable::EVIsLLDBAllocated;
172309124Sdim
173314564Sdim      if (!err.Success())
174314564Sdim        return;
175314564Sdim    }
176309124Sdim
177314564Sdim    if ((m_persistent_variable_sp->m_flags &
178314564Sdim             ExpressionVariable::EVIsProgramReference &&
179314564Sdim         m_persistent_variable_sp->m_live_sp) ||
180314564Sdim        m_persistent_variable_sp->m_flags &
181314564Sdim            ExpressionVariable::EVIsLLDBAllocated) {
182321369Sdim      Status write_error;
183309124Sdim
184314564Sdim      map.WriteScalarToMemory(
185314564Sdim          load_addr,
186314564Sdim          m_persistent_variable_sp->m_live_sp->GetValue().GetScalar(),
187314564Sdim          map.GetAddressByteSize(), write_error);
188309124Sdim
189314564Sdim      if (!write_error.Success()) {
190314564Sdim        err.SetErrorStringWithFormat(
191314564Sdim            "couldn't write the location of %s to memory: %s",
192314564Sdim            m_persistent_variable_sp->GetName().AsCString(),
193314564Sdim            write_error.AsCString());
194314564Sdim      }
195314564Sdim    } else {
196314564Sdim      err.SetErrorStringWithFormat(
197314564Sdim          "no materialization happened for persistent variable %s",
198314564Sdim          m_persistent_variable_sp->GetName().AsCString());
199314564Sdim      return;
200254721Semaste    }
201314564Sdim  }
202309124Sdim
203314564Sdim  void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
204314564Sdim                     lldb::addr_t process_address, lldb::addr_t frame_top,
205321369Sdim                     lldb::addr_t frame_bottom, Status &err) override {
206314564Sdim    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
207309124Sdim
208314564Sdim    const lldb::addr_t load_addr = process_address + m_offset;
209254721Semaste
210314564Sdim    if (log) {
211314564Sdim      log->Printf(
212314564Sdim          "EntityPersistentVariable::Dematerialize [address = 0x%" PRIx64
213314564Sdim          ", m_name = %s, m_flags = 0x%hx]",
214314564Sdim          (uint64_t)process_address + m_offset,
215314564Sdim          m_persistent_variable_sp->GetName().AsCString(),
216314564Sdim          m_persistent_variable_sp->m_flags);
217314564Sdim    }
218309124Sdim
219314564Sdim    if (m_delegate) {
220314564Sdim      m_delegate->DidDematerialize(m_persistent_variable_sp);
221314564Sdim    }
222296417Sdim
223314564Sdim    if ((m_persistent_variable_sp->m_flags &
224314564Sdim         ExpressionVariable::EVIsLLDBAllocated) ||
225314564Sdim        (m_persistent_variable_sp->m_flags &
226314564Sdim         ExpressionVariable::EVIsProgramReference)) {
227314564Sdim      if (m_persistent_variable_sp->m_flags &
228314564Sdim              ExpressionVariable::EVIsProgramReference &&
229314564Sdim          !m_persistent_variable_sp->m_live_sp) {
230314564Sdim        // If the reference comes from the program, then the
231341825Sdim        // ClangExpressionVariable's live variable data hasn't been set up yet.
232341825Sdim        // Do this now.
233309124Sdim
234314564Sdim        lldb::addr_t location;
235321369Sdim        Status read_error;
236309124Sdim
237314564Sdim        map.ReadPointerFromMemory(&location, load_addr, read_error);
238309124Sdim
239314564Sdim        if (!read_error.Success()) {
240314564Sdim          err.SetErrorStringWithFormat(
241314564Sdim              "couldn't read the address of program-allocated variable %s: %s",
242314564Sdim              m_persistent_variable_sp->GetName().GetCString(),
243314564Sdim              read_error.AsCString());
244314564Sdim          return;
245314564Sdim        }
246309124Sdim
247314564Sdim        m_persistent_variable_sp->m_live_sp = ValueObjectConstResult::Create(
248314564Sdim            map.GetBestExecutionContextScope(),
249314564Sdim            m_persistent_variable_sp.get()->GetCompilerType(),
250314564Sdim            m_persistent_variable_sp->GetName(), location, eAddressTypeLoad,
251314564Sdim            m_persistent_variable_sp->GetByteSize());
252309124Sdim
253314564Sdim        if (frame_top != LLDB_INVALID_ADDRESS &&
254314564Sdim            frame_bottom != LLDB_INVALID_ADDRESS && location >= frame_bottom &&
255314564Sdim            location <= frame_top) {
256314564Sdim          // If the variable is resident in the stack frame created by the
257341825Sdim          // expression, then it cannot be relied upon to stay around.  We
258341825Sdim          // treat it as needing reallocation.
259314564Sdim          m_persistent_variable_sp->m_flags |=
260314564Sdim              ExpressionVariable::EVIsLLDBAllocated;
261314564Sdim          m_persistent_variable_sp->m_flags |=
262314564Sdim              ExpressionVariable::EVNeedsAllocation;
263314564Sdim          m_persistent_variable_sp->m_flags |=
264314564Sdim              ExpressionVariable::EVNeedsFreezeDry;
265314564Sdim          m_persistent_variable_sp->m_flags &=
266314564Sdim              ~ExpressionVariable::EVIsProgramReference;
267314564Sdim        }
268314564Sdim      }
269309124Sdim
270314564Sdim      lldb::addr_t mem = m_persistent_variable_sp->m_live_sp->GetValue()
271314564Sdim                             .GetScalar()
272314564Sdim                             .ULongLong();
273309124Sdim
274314564Sdim      if (!m_persistent_variable_sp->m_live_sp) {
275314564Sdim        err.SetErrorStringWithFormat(
276314564Sdim            "couldn't find the memory area used to store %s",
277314564Sdim            m_persistent_variable_sp->GetName().GetCString());
278314564Sdim        return;
279314564Sdim      }
280309124Sdim
281314564Sdim      if (m_persistent_variable_sp->m_live_sp->GetValue()
282314564Sdim              .GetValueAddressType() != eAddressTypeLoad) {
283314564Sdim        err.SetErrorStringWithFormat(
284314564Sdim            "the address of the memory area for %s is in an incorrect format",
285314564Sdim            m_persistent_variable_sp->GetName().GetCString());
286314564Sdim        return;
287314564Sdim      }
288309124Sdim
289314564Sdim      if (m_persistent_variable_sp->m_flags &
290314564Sdim              ExpressionVariable::EVNeedsFreezeDry ||
291314564Sdim          m_persistent_variable_sp->m_flags &
292314564Sdim              ExpressionVariable::EVKeepInTarget) {
293314564Sdim        if (log)
294314564Sdim          log->Printf(
295314564Sdim              "Dematerializing %s from 0x%" PRIx64 " (size = %llu)",
296314564Sdim              m_persistent_variable_sp->GetName().GetCString(), (uint64_t)mem,
297314564Sdim              (unsigned long long)m_persistent_variable_sp->GetByteSize());
298309124Sdim
299314564Sdim        // Read the contents of the spare memory area
300309124Sdim
301314564Sdim        m_persistent_variable_sp->ValueUpdated();
302309124Sdim
303321369Sdim        Status read_error;
304309124Sdim
305314564Sdim        map.ReadMemory(m_persistent_variable_sp->GetValueBytes(), mem,
306314564Sdim                       m_persistent_variable_sp->GetByteSize(), read_error);
307309124Sdim
308314564Sdim        if (!read_error.Success()) {
309314564Sdim          err.SetErrorStringWithFormat(
310314564Sdim              "couldn't read the contents of %s from memory: %s",
311314564Sdim              m_persistent_variable_sp->GetName().GetCString(),
312314564Sdim              read_error.AsCString());
313314564Sdim          return;
314254721Semaste        }
315309124Sdim
316314564Sdim        m_persistent_variable_sp->m_flags &=
317314564Sdim            ~ExpressionVariable::EVNeedsFreezeDry;
318314564Sdim      }
319314564Sdim    } else {
320314564Sdim      err.SetErrorStringWithFormat(
321314564Sdim          "no dematerialization happened for persistent variable %s",
322314564Sdim          m_persistent_variable_sp->GetName().AsCString());
323314564Sdim      return;
324314564Sdim    }
325309124Sdim
326314564Sdim    lldb::ProcessSP process_sp =
327314564Sdim        map.GetBestExecutionContextScope()->CalculateProcess();
328314564Sdim    if (!process_sp || !process_sp->CanJIT()) {
329314564Sdim      // Allocations are not persistent so persistent variables cannot stay
330314564Sdim      // materialized.
331254721Semaste
332314564Sdim      m_persistent_variable_sp->m_flags |=
333314564Sdim          ExpressionVariable::EVNeedsAllocation;
334314564Sdim
335314564Sdim      DestroyAllocation(map, err);
336314564Sdim      if (!err.Success())
337314564Sdim        return;
338314564Sdim    } else if (m_persistent_variable_sp->m_flags &
339314564Sdim                   ExpressionVariable::EVNeedsAllocation &&
340314564Sdim               !(m_persistent_variable_sp->m_flags &
341314564Sdim                 ExpressionVariable::EVKeepInTarget)) {
342314564Sdim      DestroyAllocation(map, err);
343314564Sdim      if (!err.Success())
344314564Sdim        return;
345254721Semaste    }
346314564Sdim  }
347309124Sdim
348314564Sdim  void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
349314564Sdim                 Log *log) override {
350314564Sdim    StreamString dump_stream;
351309124Sdim
352321369Sdim    Status err;
353309124Sdim
354314564Sdim    const lldb::addr_t load_addr = process_address + m_offset;
355254721Semaste
356314564Sdim    dump_stream.Printf("0x%" PRIx64 ": EntityPersistentVariable (%s)\n",
357314564Sdim                       load_addr,
358314564Sdim                       m_persistent_variable_sp->GetName().AsCString());
359309124Sdim
360314564Sdim    {
361314564Sdim      dump_stream.Printf("Pointer:\n");
362309124Sdim
363314564Sdim      DataBufferHeap data(m_size, 0);
364309124Sdim
365314564Sdim      map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
366309124Sdim
367314564Sdim      if (!err.Success()) {
368314564Sdim        dump_stream.Printf("  <could not be read>\n");
369314564Sdim      } else {
370321369Sdim        DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
371321369Sdim                     load_addr);
372309124Sdim
373314564Sdim        dump_stream.PutChar('\n');
374314564Sdim      }
375314564Sdim    }
376309124Sdim
377314564Sdim    {
378314564Sdim      dump_stream.Printf("Target:\n");
379309124Sdim
380314564Sdim      lldb::addr_t target_address;
381309124Sdim
382314564Sdim      map.ReadPointerFromMemory(&target_address, load_addr, err);
383309124Sdim
384314564Sdim      if (!err.Success()) {
385314564Sdim        dump_stream.Printf("  <could not be read>\n");
386314564Sdim      } else {
387314564Sdim        DataBufferHeap data(m_persistent_variable_sp->GetByteSize(), 0);
388309124Sdim
389314564Sdim        map.ReadMemory(data.GetBytes(), target_address,
390314564Sdim                       m_persistent_variable_sp->GetByteSize(), err);
391309124Sdim
392314564Sdim        if (!err.Success()) {
393314564Sdim          dump_stream.Printf("  <could not be read>\n");
394314564Sdim        } else {
395321369Sdim          DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
396321369Sdim                       target_address);
397309124Sdim
398314564Sdim          dump_stream.PutChar('\n');
399254721Semaste        }
400314564Sdim      }
401254721Semaste    }
402309124Sdim
403314564Sdim    log->PutString(dump_stream.GetString());
404314564Sdim  }
405296417Sdim
406314564Sdim  void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {}
407314564Sdim
408254721Semasteprivate:
409314564Sdim  lldb::ExpressionVariableSP m_persistent_variable_sp;
410314564Sdim  Materializer::PersistentVariableDelegate *m_delegate;
411254721Semaste};
412254721Semaste
413314564Sdimuint32_t Materializer::AddPersistentVariable(
414314564Sdim    lldb::ExpressionVariableSP &persistent_variable_sp,
415321369Sdim    PersistentVariableDelegate *delegate, Status &err) {
416314564Sdim  EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
417314564Sdim  iter->reset(new EntityPersistentVariable(persistent_variable_sp, delegate));
418314564Sdim  uint32_t ret = AddStructMember(**iter);
419314564Sdim  (*iter)->SetOffset(ret);
420314564Sdim  return ret;
421254721Semaste}
422254721Semaste
423314564Sdimclass EntityVariable : public Materializer::Entity {
424254721Semastepublic:
425314564Sdim  EntityVariable(lldb::VariableSP &variable_sp)
426314564Sdim      : Entity(), m_variable_sp(variable_sp), m_is_reference(false),
427254721Semaste        m_temporary_allocation(LLDB_INVALID_ADDRESS),
428314564Sdim        m_temporary_allocation_size(0) {
429314564Sdim    // Hard-coding to maximum size of a pointer since all variables are
430314564Sdim    // materialized by reference
431314564Sdim    m_size = 8;
432314564Sdim    m_alignment = 8;
433314564Sdim    m_is_reference =
434314564Sdim        m_variable_sp->GetType()->GetForwardCompilerType().IsReferenceType();
435314564Sdim  }
436314564Sdim
437314564Sdim  void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
438321369Sdim                   lldb::addr_t process_address, Status &err) override {
439314564Sdim    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
440314564Sdim
441314564Sdim    const lldb::addr_t load_addr = process_address + m_offset;
442314564Sdim    if (log) {
443314564Sdim      log->Printf("EntityVariable::Materialize [address = 0x%" PRIx64
444314564Sdim                  ", m_variable_sp = %s]",
445314564Sdim                  (uint64_t)load_addr, m_variable_sp->GetName().AsCString());
446254721Semaste    }
447309124Sdim
448314564Sdim    ExecutionContextScope *scope = frame_sp.get();
449309124Sdim
450314564Sdim    if (!scope)
451314564Sdim      scope = map.GetBestExecutionContextScope();
452309124Sdim
453314564Sdim    lldb::ValueObjectSP valobj_sp =
454314564Sdim        ValueObjectVariable::Create(scope, m_variable_sp);
455309124Sdim
456314564Sdim    if (!valobj_sp) {
457314564Sdim      err.SetErrorStringWithFormat(
458314564Sdim          "couldn't get a value object for variable %s",
459314564Sdim          m_variable_sp->GetName().AsCString());
460314564Sdim      return;
461314564Sdim    }
462309124Sdim
463321369Sdim    Status valobj_error = valobj_sp->GetError();
464309124Sdim
465314564Sdim    if (valobj_error.Fail()) {
466314564Sdim      err.SetErrorStringWithFormat("couldn't get the value of variable %s: %s",
467314564Sdim                                   m_variable_sp->GetName().AsCString(),
468314564Sdim                                   valobj_error.AsCString());
469314564Sdim      return;
470314564Sdim    }
471309124Sdim
472314564Sdim    if (m_is_reference) {
473314564Sdim      DataExtractor valobj_extractor;
474321369Sdim      Status extract_error;
475314564Sdim      valobj_sp->GetData(valobj_extractor, extract_error);
476309124Sdim
477314564Sdim      if (!extract_error.Success()) {
478314564Sdim        err.SetErrorStringWithFormat(
479314564Sdim            "couldn't read contents of reference variable %s: %s",
480314564Sdim            m_variable_sp->GetName().AsCString(), extract_error.AsCString());
481314564Sdim        return;
482314564Sdim      }
483309124Sdim
484314564Sdim      lldb::offset_t offset = 0;
485314564Sdim      lldb::addr_t reference_addr = valobj_extractor.GetAddress(&offset);
486309124Sdim
487321369Sdim      Status write_error;
488314564Sdim      map.WritePointerToMemory(load_addr, reference_addr, write_error);
489309124Sdim
490314564Sdim      if (!write_error.Success()) {
491314564Sdim        err.SetErrorStringWithFormat("couldn't write the contents of reference "
492314564Sdim                                     "variable %s to memory: %s",
493314564Sdim                                     m_variable_sp->GetName().AsCString(),
494314564Sdim                                     write_error.AsCString());
495314564Sdim        return;
496314564Sdim      }
497314564Sdim    } else {
498314564Sdim      AddressType address_type = eAddressTypeInvalid;
499314564Sdim      const bool scalar_is_load_address = false;
500314564Sdim      lldb::addr_t addr_of_valobj =
501314564Sdim          valobj_sp->GetAddressOf(scalar_is_load_address, &address_type);
502314564Sdim      if (addr_of_valobj != LLDB_INVALID_ADDRESS) {
503321369Sdim        Status write_error;
504314564Sdim        map.WritePointerToMemory(load_addr, addr_of_valobj, write_error);
505309124Sdim
506314564Sdim        if (!write_error.Success()) {
507314564Sdim          err.SetErrorStringWithFormat(
508314564Sdim              "couldn't write the address of variable %s to memory: %s",
509314564Sdim              m_variable_sp->GetName().AsCString(), write_error.AsCString());
510314564Sdim          return;
511314564Sdim        }
512314564Sdim      } else {
513314564Sdim        DataExtractor data;
514321369Sdim        Status extract_error;
515314564Sdim        valobj_sp->GetData(data, extract_error);
516314564Sdim        if (!extract_error.Success()) {
517314564Sdim          err.SetErrorStringWithFormat("couldn't get the value of %s: %s",
518314564Sdim                                       m_variable_sp->GetName().AsCString(),
519314564Sdim                                       extract_error.AsCString());
520314564Sdim          return;
521314564Sdim        }
522309124Sdim
523314564Sdim        if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
524314564Sdim          err.SetErrorStringWithFormat(
525314564Sdim              "trying to create a temporary region for %s but one exists",
526314564Sdim              m_variable_sp->GetName().AsCString());
527314564Sdim          return;
528254721Semaste        }
529309124Sdim
530314564Sdim        if (data.GetByteSize() < m_variable_sp->GetType()->GetByteSize()) {
531314564Sdim          if (data.GetByteSize() == 0 &&
532344779Sdim              !m_variable_sp->LocationExpression().IsValid()) {
533314564Sdim            err.SetErrorStringWithFormat("the variable '%s' has no location, "
534314564Sdim                                         "it may have been optimized out",
535314564Sdim                                         m_variable_sp->GetName().AsCString());
536314564Sdim          } else {
537314564Sdim            err.SetErrorStringWithFormat(
538314564Sdim                "size of variable %s (%" PRIu64
539314564Sdim                ") is larger than the ValueObject's size (%" PRIu64 ")",
540314564Sdim                m_variable_sp->GetName().AsCString(),
541314564Sdim                m_variable_sp->GetType()->GetByteSize(), data.GetByteSize());
542314564Sdim          }
543314564Sdim          return;
544314564Sdim        }
545309124Sdim
546314564Sdim        size_t bit_align =
547314564Sdim            m_variable_sp->GetType()->GetLayoutCompilerType().GetTypeBitAlign();
548314564Sdim        size_t byte_align = (bit_align + 7) / 8;
549309124Sdim
550314564Sdim        if (!byte_align)
551314564Sdim          byte_align = 1;
552309124Sdim
553321369Sdim        Status alloc_error;
554314564Sdim        const bool zero_memory = false;
555309124Sdim
556314564Sdim        m_temporary_allocation = map.Malloc(
557314564Sdim            data.GetByteSize(), byte_align,
558314564Sdim            lldb::ePermissionsReadable | lldb::ePermissionsWritable,
559314564Sdim            IRMemoryMap::eAllocationPolicyMirror, zero_memory, alloc_error);
560309124Sdim
561314564Sdim        m_temporary_allocation_size = data.GetByteSize();
562296417Sdim
563314564Sdim        m_original_data.reset(
564314564Sdim            new DataBufferHeap(data.GetDataStart(), data.GetByteSize()));
565309124Sdim
566314564Sdim        if (!alloc_error.Success()) {
567314564Sdim          err.SetErrorStringWithFormat(
568314564Sdim              "couldn't allocate a temporary region for %s: %s",
569314564Sdim              m_variable_sp->GetName().AsCString(), alloc_error.AsCString());
570314564Sdim          return;
571314564Sdim        }
572309124Sdim
573321369Sdim        Status write_error;
574309124Sdim
575314564Sdim        map.WriteMemory(m_temporary_allocation, data.GetDataStart(),
576314564Sdim                        data.GetByteSize(), write_error);
577309124Sdim
578314564Sdim        if (!write_error.Success()) {
579314564Sdim          err.SetErrorStringWithFormat(
580314564Sdim              "couldn't write to the temporary region for %s: %s",
581314564Sdim              m_variable_sp->GetName().AsCString(), write_error.AsCString());
582314564Sdim          return;
583314564Sdim        }
584309124Sdim
585321369Sdim        Status pointer_write_error;
586309124Sdim
587314564Sdim        map.WritePointerToMemory(load_addr, m_temporary_allocation,
588314564Sdim                                 pointer_write_error);
589309124Sdim
590314564Sdim        if (!pointer_write_error.Success()) {
591314564Sdim          err.SetErrorStringWithFormat(
592314564Sdim              "couldn't write the address of the temporary region for %s: %s",
593314564Sdim              m_variable_sp->GetName().AsCString(),
594314564Sdim              pointer_write_error.AsCString());
595254721Semaste        }
596314564Sdim      }
597254721Semaste    }
598314564Sdim  }
599309124Sdim
600314564Sdim  void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
601314564Sdim                     lldb::addr_t process_address, lldb::addr_t frame_top,
602321369Sdim                     lldb::addr_t frame_bottom, Status &err) override {
603314564Sdim    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
604254721Semaste
605314564Sdim    const lldb::addr_t load_addr = process_address + m_offset;
606314564Sdim    if (log) {
607314564Sdim      log->Printf("EntityVariable::Dematerialize [address = 0x%" PRIx64
608314564Sdim                  ", m_variable_sp = %s]",
609314564Sdim                  (uint64_t)load_addr, m_variable_sp->GetName().AsCString());
610314564Sdim    }
611309124Sdim
612314564Sdim    if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
613314564Sdim      ExecutionContextScope *scope = frame_sp.get();
614309124Sdim
615314564Sdim      if (!scope)
616314564Sdim        scope = map.GetBestExecutionContextScope();
617309124Sdim
618314564Sdim      lldb::ValueObjectSP valobj_sp =
619314564Sdim          ValueObjectVariable::Create(scope, m_variable_sp);
620309124Sdim
621314564Sdim      if (!valobj_sp) {
622314564Sdim        err.SetErrorStringWithFormat(
623314564Sdim            "couldn't get a value object for variable %s",
624314564Sdim            m_variable_sp->GetName().AsCString());
625314564Sdim        return;
626314564Sdim      }
627309124Sdim
628314564Sdim      lldb_private::DataExtractor data;
629309124Sdim
630321369Sdim      Status extract_error;
631309124Sdim
632314564Sdim      map.GetMemoryData(data, m_temporary_allocation, valobj_sp->GetByteSize(),
633314564Sdim                        extract_error);
634309124Sdim
635314564Sdim      if (!extract_error.Success()) {
636314564Sdim        err.SetErrorStringWithFormat("couldn't get the data for variable %s",
637314564Sdim                                     m_variable_sp->GetName().AsCString());
638314564Sdim        return;
639314564Sdim      }
640309124Sdim
641314564Sdim      bool actually_write = true;
642309124Sdim
643314564Sdim      if (m_original_data) {
644314564Sdim        if ((data.GetByteSize() == m_original_data->GetByteSize()) &&
645314564Sdim            !memcmp(m_original_data->GetBytes(), data.GetDataStart(),
646314564Sdim                    data.GetByteSize())) {
647314564Sdim          actually_write = false;
648314564Sdim        }
649314564Sdim      }
650309124Sdim
651321369Sdim      Status set_error;
652309124Sdim
653314564Sdim      if (actually_write) {
654314564Sdim        valobj_sp->SetData(data, set_error);
655309124Sdim
656314564Sdim        if (!set_error.Success()) {
657314564Sdim          err.SetErrorStringWithFormat(
658314564Sdim              "couldn't write the new contents of %s back into the variable",
659314564Sdim              m_variable_sp->GetName().AsCString());
660314564Sdim          return;
661314564Sdim        }
662314564Sdim      }
663309124Sdim
664321369Sdim      Status free_error;
665309124Sdim
666314564Sdim      map.Free(m_temporary_allocation, free_error);
667309124Sdim
668314564Sdim      if (!free_error.Success()) {
669314564Sdim        err.SetErrorStringWithFormat(
670314564Sdim            "couldn't free the temporary region for %s: %s",
671314564Sdim            m_variable_sp->GetName().AsCString(), free_error.AsCString());
672314564Sdim        return;
673314564Sdim      }
674309124Sdim
675314564Sdim      m_original_data.reset();
676314564Sdim      m_temporary_allocation = LLDB_INVALID_ADDRESS;
677314564Sdim      m_temporary_allocation_size = 0;
678254721Semaste    }
679314564Sdim  }
680309124Sdim
681314564Sdim  void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
682314564Sdim                 Log *log) override {
683314564Sdim    StreamString dump_stream;
684254721Semaste
685314564Sdim    const lldb::addr_t load_addr = process_address + m_offset;
686314564Sdim    dump_stream.Printf("0x%" PRIx64 ": EntityVariable\n", load_addr);
687309124Sdim
688321369Sdim    Status err;
689309124Sdim
690314564Sdim    lldb::addr_t ptr = LLDB_INVALID_ADDRESS;
691309124Sdim
692314564Sdim    {
693314564Sdim      dump_stream.Printf("Pointer:\n");
694309124Sdim
695314564Sdim      DataBufferHeap data(m_size, 0);
696309124Sdim
697314564Sdim      map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
698309124Sdim
699314564Sdim      if (!err.Success()) {
700314564Sdim        dump_stream.Printf("  <could not be read>\n");
701314564Sdim      } else {
702314564Sdim        DataExtractor extractor(data.GetBytes(), data.GetByteSize(),
703314564Sdim                                map.GetByteOrder(), map.GetAddressByteSize());
704309124Sdim
705321369Sdim        DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
706321369Sdim                     load_addr);
707309124Sdim
708314564Sdim        lldb::offset_t offset;
709309124Sdim
710314564Sdim        ptr = extractor.GetPointer(&offset);
711309124Sdim
712314564Sdim        dump_stream.PutChar('\n');
713314564Sdim      }
714314564Sdim    }
715309124Sdim
716314564Sdim    if (m_temporary_allocation == LLDB_INVALID_ADDRESS) {
717314564Sdim      dump_stream.Printf("Points to process memory:\n");
718314564Sdim    } else {
719314564Sdim      dump_stream.Printf("Temporary allocation:\n");
720314564Sdim    }
721309124Sdim
722314564Sdim    if (ptr == LLDB_INVALID_ADDRESS) {
723314564Sdim      dump_stream.Printf("  <could not be be found>\n");
724314564Sdim    } else {
725314564Sdim      DataBufferHeap data(m_temporary_allocation_size, 0);
726309124Sdim
727314564Sdim      map.ReadMemory(data.GetBytes(), m_temporary_allocation,
728314564Sdim                     m_temporary_allocation_size, err);
729309124Sdim
730314564Sdim      if (!err.Success()) {
731314564Sdim        dump_stream.Printf("  <could not be read>\n");
732314564Sdim      } else {
733321369Sdim        DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
734321369Sdim                     load_addr);
735309124Sdim
736314564Sdim        dump_stream.PutChar('\n');
737314564Sdim      }
738254721Semaste    }
739309124Sdim
740314564Sdim    log->PutString(dump_stream.GetString());
741314564Sdim  }
742309124Sdim
743314564Sdim  void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {
744314564Sdim    if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
745321369Sdim      Status free_error;
746309124Sdim
747314564Sdim      map.Free(m_temporary_allocation, free_error);
748254721Semaste
749314564Sdim      m_temporary_allocation = LLDB_INVALID_ADDRESS;
750314564Sdim      m_temporary_allocation_size = 0;
751254721Semaste    }
752314564Sdim  }
753296417Sdim
754254721Semasteprivate:
755314564Sdim  lldb::VariableSP m_variable_sp;
756314564Sdim  bool m_is_reference;
757314564Sdim  lldb::addr_t m_temporary_allocation;
758314564Sdim  size_t m_temporary_allocation_size;
759314564Sdim  lldb::DataBufferSP m_original_data;
760254721Semaste};
761254721Semaste
762321369Sdimuint32_t Materializer::AddVariable(lldb::VariableSP &variable_sp, Status &err) {
763314564Sdim  EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
764314564Sdim  iter->reset(new EntityVariable(variable_sp));
765314564Sdim  uint32_t ret = AddStructMember(**iter);
766314564Sdim  (*iter)->SetOffset(ret);
767314564Sdim  return ret;
768254721Semaste}
769254721Semaste
770314564Sdimclass EntityResultVariable : public Materializer::Entity {
771254721Semastepublic:
772314564Sdim  EntityResultVariable(const CompilerType &type, bool is_program_reference,
773314564Sdim                       bool keep_in_memory,
774314564Sdim                       Materializer::PersistentVariableDelegate *delegate)
775314564Sdim      : Entity(), m_type(type), m_is_program_reference(is_program_reference),
776254721Semaste        m_keep_in_memory(keep_in_memory),
777254721Semaste        m_temporary_allocation(LLDB_INVALID_ADDRESS),
778314564Sdim        m_temporary_allocation_size(0), m_delegate(delegate) {
779314564Sdim    // Hard-coding to maximum size of a pointer since all results are
780314564Sdim    // materialized by reference
781314564Sdim    m_size = 8;
782314564Sdim    m_alignment = 8;
783314564Sdim  }
784309124Sdim
785314564Sdim  void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
786321369Sdim                   lldb::addr_t process_address, Status &err) override {
787314564Sdim    if (!m_is_program_reference) {
788314564Sdim      if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
789314564Sdim        err.SetErrorString("Trying to create a temporary region for the result "
790314564Sdim                           "but one exists");
791314564Sdim        return;
792314564Sdim      }
793309124Sdim
794314564Sdim      const lldb::addr_t load_addr = process_address + m_offset;
795254721Semaste
796314564Sdim      ExecutionContextScope *exe_scope = map.GetBestExecutionContextScope();
797309124Sdim
798344779Sdim      llvm::Optional<uint64_t> byte_size = m_type.GetByteSize(exe_scope);
799344779Sdim      if (!byte_size) {
800344779Sdim        err.SetErrorString("can't get size of type");
801344779Sdim        return;
802344779Sdim      }
803314564Sdim      size_t bit_align = m_type.GetTypeBitAlign();
804314564Sdim      size_t byte_align = (bit_align + 7) / 8;
805309124Sdim
806314564Sdim      if (!byte_align)
807314564Sdim        byte_align = 1;
808296417Sdim
809321369Sdim      Status alloc_error;
810314564Sdim      const bool zero_memory = true;
811309124Sdim
812314564Sdim      m_temporary_allocation = map.Malloc(
813344779Sdim          *byte_size, byte_align,
814314564Sdim          lldb::ePermissionsReadable | lldb::ePermissionsWritable,
815314564Sdim          IRMemoryMap::eAllocationPolicyMirror, zero_memory, alloc_error);
816344779Sdim      m_temporary_allocation_size = *byte_size;
817309124Sdim
818314564Sdim      if (!alloc_error.Success()) {
819314564Sdim        err.SetErrorStringWithFormat(
820314564Sdim            "couldn't allocate a temporary region for the result: %s",
821314564Sdim            alloc_error.AsCString());
822314564Sdim        return;
823314564Sdim      }
824309124Sdim
825321369Sdim      Status pointer_write_error;
826309124Sdim
827314564Sdim      map.WritePointerToMemory(load_addr, m_temporary_allocation,
828314564Sdim                               pointer_write_error);
829314564Sdim
830314564Sdim      if (!pointer_write_error.Success()) {
831314564Sdim        err.SetErrorStringWithFormat("couldn't write the address of the "
832314564Sdim                                     "temporary region for the result: %s",
833314564Sdim                                     pointer_write_error.AsCString());
834314564Sdim      }
835254721Semaste    }
836314564Sdim  }
837309124Sdim
838314564Sdim  void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
839314564Sdim                     lldb::addr_t process_address, lldb::addr_t frame_top,
840321369Sdim                     lldb::addr_t frame_bottom, Status &err) override {
841314564Sdim    err.Clear();
842309124Sdim
843314564Sdim    ExecutionContextScope *exe_scope = map.GetBestExecutionContextScope();
844309124Sdim
845314564Sdim    if (!exe_scope) {
846314564Sdim      err.SetErrorString("Couldn't dematerialize a result variable: invalid "
847314564Sdim                         "execution context scope");
848314564Sdim      return;
849314564Sdim    }
850309124Sdim
851314564Sdim    lldb::addr_t address;
852321369Sdim    Status read_error;
853314564Sdim    const lldb::addr_t load_addr = process_address + m_offset;
854309124Sdim
855314564Sdim    map.ReadPointerFromMemory(&address, load_addr, read_error);
856309124Sdim
857314564Sdim    if (!read_error.Success()) {
858314564Sdim      err.SetErrorString("Couldn't dematerialize a result variable: couldn't "
859314564Sdim                         "read its address");
860314564Sdim      return;
861314564Sdim    }
862309124Sdim
863314564Sdim    lldb::TargetSP target_sp = exe_scope->CalculateTarget();
864309124Sdim
865314564Sdim    if (!target_sp) {
866314564Sdim      err.SetErrorString("Couldn't dematerialize a result variable: no target");
867314564Sdim      return;
868314564Sdim    }
869309124Sdim
870321369Sdim    Status type_system_error;
871314564Sdim    TypeSystem *type_system = target_sp->GetScratchTypeSystemForLanguage(
872314564Sdim        &type_system_error, m_type.GetMinimumLanguage());
873309124Sdim
874314564Sdim    if (!type_system) {
875314564Sdim      err.SetErrorStringWithFormat("Couldn't dematerialize a result variable: "
876314564Sdim                                   "couldn't get the corresponding type "
877314564Sdim                                   "system: %s",
878314564Sdim                                   type_system_error.AsCString());
879314564Sdim      return;
880314564Sdim    }
881309124Sdim
882314564Sdim    PersistentExpressionState *persistent_state =
883314564Sdim        type_system->GetPersistentExpressionState();
884309124Sdim
885314564Sdim    if (!persistent_state) {
886314564Sdim      err.SetErrorString("Couldn't dematerialize a result variable: "
887314564Sdim                         "corresponding type system doesn't handle persistent "
888314564Sdim                         "variables");
889314564Sdim      return;
890314564Sdim    }
891309124Sdim
892341825Sdim    ConstString name =
893341825Sdim        m_delegate
894341825Sdim            ? m_delegate->GetName()
895341825Sdim            : persistent_state->GetNextPersistentVariableName(
896341825Sdim                  *target_sp, persistent_state->GetPersistentVariablePrefix());
897309124Sdim
898314564Sdim    lldb::ExpressionVariableSP ret = persistent_state->CreatePersistentVariable(
899314564Sdim        exe_scope, name, m_type, map.GetByteOrder(), map.GetAddressByteSize());
900309124Sdim
901314564Sdim    if (!ret) {
902314564Sdim      err.SetErrorStringWithFormat("couldn't dematerialize a result variable: "
903314564Sdim                                   "failed to make persistent variable %s",
904314564Sdim                                   name.AsCString());
905314564Sdim      return;
906314564Sdim    }
907309124Sdim
908314564Sdim    lldb::ProcessSP process_sp =
909314564Sdim        map.GetBestExecutionContextScope()->CalculateProcess();
910309124Sdim
911314564Sdim    if (m_delegate) {
912314564Sdim      m_delegate->DidDematerialize(ret);
913314564Sdim    }
914309124Sdim
915314564Sdim    bool can_persist =
916314564Sdim        (m_is_program_reference && process_sp && process_sp->CanJIT() &&
917314564Sdim         !(address >= frame_bottom && address < frame_top));
918254721Semaste
919314564Sdim    if (can_persist && m_keep_in_memory) {
920314564Sdim      ret->m_live_sp = ValueObjectConstResult::Create(exe_scope, m_type, name,
921314564Sdim                                                      address, eAddressTypeLoad,
922314564Sdim                                                      map.GetAddressByteSize());
923314564Sdim    }
924309124Sdim
925314564Sdim    ret->ValueUpdated();
926309124Sdim
927314564Sdim    const size_t pvar_byte_size = ret->GetByteSize();
928314564Sdim    uint8_t *pvar_data = ret->GetValueBytes();
929309124Sdim
930314564Sdim    map.ReadMemory(pvar_data, address, pvar_byte_size, read_error);
931309124Sdim
932314564Sdim    if (!read_error.Success()) {
933314564Sdim      err.SetErrorString(
934314564Sdim          "Couldn't dematerialize a result variable: couldn't read its memory");
935314564Sdim      return;
936314564Sdim    }
937309124Sdim
938314564Sdim    if (!can_persist || !m_keep_in_memory) {
939314564Sdim      ret->m_flags |= ExpressionVariable::EVNeedsAllocation;
940309124Sdim
941314564Sdim      if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
942321369Sdim        Status free_error;
943314564Sdim        map.Free(m_temporary_allocation, free_error);
944314564Sdim      }
945314564Sdim    } else {
946314564Sdim      ret->m_flags |= ExpressionVariable::EVIsLLDBAllocated;
947254721Semaste    }
948309124Sdim
949314564Sdim    m_temporary_allocation = LLDB_INVALID_ADDRESS;
950314564Sdim    m_temporary_allocation_size = 0;
951314564Sdim  }
952309124Sdim
953314564Sdim  void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
954314564Sdim                 Log *log) override {
955314564Sdim    StreamString dump_stream;
956254721Semaste
957314564Sdim    const lldb::addr_t load_addr = process_address + m_offset;
958309124Sdim
959314564Sdim    dump_stream.Printf("0x%" PRIx64 ": EntityResultVariable\n", load_addr);
960309124Sdim
961321369Sdim    Status err;
962309124Sdim
963314564Sdim    lldb::addr_t ptr = LLDB_INVALID_ADDRESS;
964309124Sdim
965314564Sdim    {
966314564Sdim      dump_stream.Printf("Pointer:\n");
967309124Sdim
968314564Sdim      DataBufferHeap data(m_size, 0);
969309124Sdim
970314564Sdim      map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
971309124Sdim
972314564Sdim      if (!err.Success()) {
973314564Sdim        dump_stream.Printf("  <could not be read>\n");
974314564Sdim      } else {
975314564Sdim        DataExtractor extractor(data.GetBytes(), data.GetByteSize(),
976314564Sdim                                map.GetByteOrder(), map.GetAddressByteSize());
977309124Sdim
978321369Sdim        DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
979321369Sdim                     load_addr);
980309124Sdim
981314564Sdim        lldb::offset_t offset;
982309124Sdim
983314564Sdim        ptr = extractor.GetPointer(&offset);
984309124Sdim
985314564Sdim        dump_stream.PutChar('\n');
986314564Sdim      }
987314564Sdim    }
988309124Sdim
989314564Sdim    if (m_temporary_allocation == LLDB_INVALID_ADDRESS) {
990314564Sdim      dump_stream.Printf("Points to process memory:\n");
991314564Sdim    } else {
992314564Sdim      dump_stream.Printf("Temporary allocation:\n");
993314564Sdim    }
994309124Sdim
995314564Sdim    if (ptr == LLDB_INVALID_ADDRESS) {
996314564Sdim      dump_stream.Printf("  <could not be be found>\n");
997314564Sdim    } else {
998314564Sdim      DataBufferHeap data(m_temporary_allocation_size, 0);
999309124Sdim
1000314564Sdim      map.ReadMemory(data.GetBytes(), m_temporary_allocation,
1001314564Sdim                     m_temporary_allocation_size, err);
1002309124Sdim
1003314564Sdim      if (!err.Success()) {
1004314564Sdim        dump_stream.Printf("  <could not be read>\n");
1005314564Sdim      } else {
1006321369Sdim        DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
1007321369Sdim                     load_addr);
1008309124Sdim
1009314564Sdim        dump_stream.PutChar('\n');
1010314564Sdim      }
1011254721Semaste    }
1012309124Sdim
1013314564Sdim    log->PutString(dump_stream.GetString());
1014314564Sdim  }
1015309124Sdim
1016314564Sdim  void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {
1017314564Sdim    if (!m_keep_in_memory && m_temporary_allocation != LLDB_INVALID_ADDRESS) {
1018321369Sdim      Status free_error;
1019309124Sdim
1020314564Sdim      map.Free(m_temporary_allocation, free_error);
1021254721Semaste    }
1022296417Sdim
1023314564Sdim    m_temporary_allocation = LLDB_INVALID_ADDRESS;
1024314564Sdim    m_temporary_allocation_size = 0;
1025314564Sdim  }
1026314564Sdim
1027254721Semasteprivate:
1028314564Sdim  CompilerType m_type;
1029314564Sdim  bool m_is_program_reference;
1030314564Sdim  bool m_keep_in_memory;
1031309124Sdim
1032314564Sdim  lldb::addr_t m_temporary_allocation;
1033314564Sdim  size_t m_temporary_allocation_size;
1034314564Sdim  Materializer::PersistentVariableDelegate *m_delegate;
1035254721Semaste};
1036254721Semaste
1037314564Sdimuint32_t Materializer::AddResultVariable(const CompilerType &type,
1038314564Sdim                                         bool is_program_reference,
1039314564Sdim                                         bool keep_in_memory,
1040314564Sdim                                         PersistentVariableDelegate *delegate,
1041321369Sdim                                         Status &err) {
1042314564Sdim  EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
1043314564Sdim  iter->reset(new EntityResultVariable(type, is_program_reference,
1044314564Sdim                                       keep_in_memory, delegate));
1045314564Sdim  uint32_t ret = AddStructMember(**iter);
1046314564Sdim  (*iter)->SetOffset(ret);
1047314564Sdim  return ret;
1048254721Semaste}
1049254721Semaste
1050314564Sdimclass EntitySymbol : public Materializer::Entity {
1051254721Semastepublic:
1052314564Sdim  EntitySymbol(const Symbol &symbol) : Entity(), m_symbol(symbol) {
1053314564Sdim    // Hard-coding to maximum size of a symbol
1054314564Sdim    m_size = 8;
1055314564Sdim    m_alignment = 8;
1056314564Sdim  }
1057309124Sdim
1058314564Sdim  void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1059321369Sdim                   lldb::addr_t process_address, Status &err) override {
1060314564Sdim    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
1061254721Semaste
1062314564Sdim    const lldb::addr_t load_addr = process_address + m_offset;
1063254721Semaste
1064314564Sdim    if (log) {
1065314564Sdim      log->Printf("EntitySymbol::Materialize [address = 0x%" PRIx64
1066314564Sdim                  ", m_symbol = %s]",
1067314564Sdim                  (uint64_t)load_addr, m_symbol.GetName().AsCString());
1068314564Sdim    }
1069309124Sdim
1070314564Sdim    const Address sym_address = m_symbol.GetAddress();
1071254721Semaste
1072314564Sdim    ExecutionContextScope *exe_scope = map.GetBestExecutionContextScope();
1073309124Sdim
1074314564Sdim    lldb::TargetSP target_sp;
1075309124Sdim
1076314564Sdim    if (exe_scope)
1077314564Sdim      target_sp = map.GetBestExecutionContextScope()->CalculateTarget();
1078309124Sdim
1079314564Sdim    if (!target_sp) {
1080314564Sdim      err.SetErrorStringWithFormat(
1081314564Sdim          "couldn't resolve symbol %s because there is no target",
1082314564Sdim          m_symbol.GetName().AsCString());
1083314564Sdim      return;
1084314564Sdim    }
1085309124Sdim
1086314564Sdim    lldb::addr_t resolved_address = sym_address.GetLoadAddress(target_sp.get());
1087309124Sdim
1088314564Sdim    if (resolved_address == LLDB_INVALID_ADDRESS)
1089314564Sdim      resolved_address = sym_address.GetFileAddress();
1090309124Sdim
1091321369Sdim    Status pointer_write_error;
1092309124Sdim
1093314564Sdim    map.WritePointerToMemory(load_addr, resolved_address, pointer_write_error);
1094309124Sdim
1095314564Sdim    if (!pointer_write_error.Success()) {
1096314564Sdim      err.SetErrorStringWithFormat(
1097314564Sdim          "couldn't write the address of symbol %s: %s",
1098314564Sdim          m_symbol.GetName().AsCString(), pointer_write_error.AsCString());
1099314564Sdim      return;
1100254721Semaste    }
1101314564Sdim  }
1102309124Sdim
1103314564Sdim  void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1104314564Sdim                     lldb::addr_t process_address, lldb::addr_t frame_top,
1105321369Sdim                     lldb::addr_t frame_bottom, Status &err) override {
1106314564Sdim    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
1107254721Semaste
1108314564Sdim    const lldb::addr_t load_addr = process_address + m_offset;
1109254721Semaste
1110314564Sdim    if (log) {
1111314564Sdim      log->Printf("EntitySymbol::Dematerialize [address = 0x%" PRIx64
1112314564Sdim                  ", m_symbol = %s]",
1113314564Sdim                  (uint64_t)load_addr, m_symbol.GetName().AsCString());
1114254721Semaste    }
1115309124Sdim
1116314564Sdim    // no work needs to be done
1117314564Sdim  }
1118309124Sdim
1119314564Sdim  void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
1120314564Sdim                 Log *log) override {
1121314564Sdim    StreamString dump_stream;
1122309124Sdim
1123321369Sdim    Status err;
1124254721Semaste
1125314564Sdim    const lldb::addr_t load_addr = process_address + m_offset;
1126309124Sdim
1127314564Sdim    dump_stream.Printf("0x%" PRIx64 ": EntitySymbol (%s)\n", load_addr,
1128314564Sdim                       m_symbol.GetName().AsCString());
1129309124Sdim
1130314564Sdim    {
1131314564Sdim      dump_stream.Printf("Pointer:\n");
1132309124Sdim
1133314564Sdim      DataBufferHeap data(m_size, 0);
1134309124Sdim
1135314564Sdim      map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
1136309124Sdim
1137314564Sdim      if (!err.Success()) {
1138314564Sdim        dump_stream.Printf("  <could not be read>\n");
1139314564Sdim      } else {
1140321369Sdim        DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
1141321369Sdim                     load_addr);
1142309124Sdim
1143314564Sdim        dump_stream.PutChar('\n');
1144314564Sdim      }
1145254721Semaste    }
1146309124Sdim
1147314564Sdim    log->PutString(dump_stream.GetString());
1148314564Sdim  }
1149296417Sdim
1150314564Sdim  void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {}
1151314564Sdim
1152254721Semasteprivate:
1153314564Sdim  Symbol m_symbol;
1154254721Semaste};
1155254721Semaste
1156321369Sdimuint32_t Materializer::AddSymbol(const Symbol &symbol_sp, Status &err) {
1157314564Sdim  EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
1158314564Sdim  iter->reset(new EntitySymbol(symbol_sp));
1159314564Sdim  uint32_t ret = AddStructMember(**iter);
1160314564Sdim  (*iter)->SetOffset(ret);
1161314564Sdim  return ret;
1162254721Semaste}
1163254721Semaste
1164314564Sdimclass EntityRegister : public Materializer::Entity {
1165254721Semastepublic:
1166314564Sdim  EntityRegister(const RegisterInfo &register_info)
1167314564Sdim      : Entity(), m_register_info(register_info) {
1168314564Sdim    // Hard-coding alignment conservatively
1169314564Sdim    m_size = m_register_info.byte_size;
1170314564Sdim    m_alignment = m_register_info.byte_size;
1171314564Sdim  }
1172314564Sdim
1173314564Sdim  void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1174321369Sdim                   lldb::addr_t process_address, Status &err) override {
1175314564Sdim    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
1176314564Sdim
1177314564Sdim    const lldb::addr_t load_addr = process_address + m_offset;
1178314564Sdim
1179314564Sdim    if (log) {
1180314564Sdim      log->Printf("EntityRegister::Materialize [address = 0x%" PRIx64
1181314564Sdim                  ", m_register_info = %s]",
1182314564Sdim                  (uint64_t)load_addr, m_register_info.name);
1183254721Semaste    }
1184309124Sdim
1185314564Sdim    RegisterValue reg_value;
1186309124Sdim
1187314564Sdim    if (!frame_sp.get()) {
1188314564Sdim      err.SetErrorStringWithFormat(
1189314564Sdim          "couldn't materialize register %s without a stack frame",
1190314564Sdim          m_register_info.name);
1191314564Sdim      return;
1192314564Sdim    }
1193254721Semaste
1194314564Sdim    lldb::RegisterContextSP reg_context_sp = frame_sp->GetRegisterContext();
1195254721Semaste
1196314564Sdim    if (!reg_context_sp->ReadRegister(&m_register_info, reg_value)) {
1197314564Sdim      err.SetErrorStringWithFormat("couldn't read the value of register %s",
1198314564Sdim                                   m_register_info.name);
1199314564Sdim      return;
1200314564Sdim    }
1201309124Sdim
1202314564Sdim    DataExtractor register_data;
1203309124Sdim
1204314564Sdim    if (!reg_value.GetData(register_data)) {
1205314564Sdim      err.SetErrorStringWithFormat("couldn't get the data for register %s",
1206314564Sdim                                   m_register_info.name);
1207314564Sdim      return;
1208314564Sdim    }
1209309124Sdim
1210314564Sdim    if (register_data.GetByteSize() != m_register_info.byte_size) {
1211314564Sdim      err.SetErrorStringWithFormat(
1212314564Sdim          "data for register %s had size %llu but we expected %llu",
1213314564Sdim          m_register_info.name, (unsigned long long)register_data.GetByteSize(),
1214314564Sdim          (unsigned long long)m_register_info.byte_size);
1215314564Sdim      return;
1216314564Sdim    }
1217309124Sdim
1218314564Sdim    m_register_contents.reset(new DataBufferHeap(register_data.GetDataStart(),
1219314564Sdim                                                 register_data.GetByteSize()));
1220309124Sdim
1221321369Sdim    Status write_error;
1222309124Sdim
1223314564Sdim    map.WriteMemory(load_addr, register_data.GetDataStart(),
1224314564Sdim                    register_data.GetByteSize(), write_error);
1225309124Sdim
1226314564Sdim    if (!write_error.Success()) {
1227314564Sdim      err.SetErrorStringWithFormat(
1228314564Sdim          "couldn't write the contents of register %s: %s",
1229314564Sdim          m_register_info.name, write_error.AsCString());
1230314564Sdim      return;
1231254721Semaste    }
1232314564Sdim  }
1233309124Sdim
1234314564Sdim  void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1235314564Sdim                     lldb::addr_t process_address, lldb::addr_t frame_top,
1236321369Sdim                     lldb::addr_t frame_bottom, Status &err) override {
1237314564Sdim    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
1238309124Sdim
1239314564Sdim    const lldb::addr_t load_addr = process_address + m_offset;
1240254721Semaste
1241314564Sdim    if (log) {
1242314564Sdim      log->Printf("EntityRegister::Dematerialize [address = 0x%" PRIx64
1243314564Sdim                  ", m_register_info = %s]",
1244314564Sdim                  (uint64_t)load_addr, m_register_info.name);
1245314564Sdim    }
1246309124Sdim
1247321369Sdim    Status extract_error;
1248309124Sdim
1249314564Sdim    DataExtractor register_data;
1250309124Sdim
1251314564Sdim    if (!frame_sp.get()) {
1252314564Sdim      err.SetErrorStringWithFormat(
1253314564Sdim          "couldn't dematerialize register %s without a stack frame",
1254314564Sdim          m_register_info.name);
1255314564Sdim      return;
1256314564Sdim    }
1257309124Sdim
1258314564Sdim    lldb::RegisterContextSP reg_context_sp = frame_sp->GetRegisterContext();
1259309124Sdim
1260314564Sdim    map.GetMemoryData(register_data, load_addr, m_register_info.byte_size,
1261314564Sdim                      extract_error);
1262309124Sdim
1263314564Sdim    if (!extract_error.Success()) {
1264314564Sdim      err.SetErrorStringWithFormat("couldn't get the data for register %s: %s",
1265314564Sdim                                   m_register_info.name,
1266314564Sdim                                   extract_error.AsCString());
1267314564Sdim      return;
1268314564Sdim    }
1269309124Sdim
1270314564Sdim    if (!memcmp(register_data.GetDataStart(), m_register_contents->GetBytes(),
1271314564Sdim                register_data.GetByteSize())) {
1272314564Sdim      // No write required, and in particular we avoid errors if the register
1273314564Sdim      // wasn't writable
1274309124Sdim
1275314564Sdim      m_register_contents.reset();
1276314564Sdim      return;
1277314564Sdim    }
1278309124Sdim
1279314564Sdim    m_register_contents.reset();
1280309124Sdim
1281314564Sdim    RegisterValue register_value(
1282314564Sdim        const_cast<uint8_t *>(register_data.GetDataStart()),
1283314564Sdim        register_data.GetByteSize(), register_data.GetByteOrder());
1284309124Sdim
1285314564Sdim    if (!reg_context_sp->WriteRegister(&m_register_info, register_value)) {
1286314564Sdim      err.SetErrorStringWithFormat("couldn't write the value of register %s",
1287314564Sdim                                   m_register_info.name);
1288314564Sdim      return;
1289254721Semaste    }
1290314564Sdim  }
1291309124Sdim
1292314564Sdim  void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
1293314564Sdim                 Log *log) override {
1294314564Sdim    StreamString dump_stream;
1295309124Sdim
1296321369Sdim    Status err;
1297309124Sdim
1298314564Sdim    const lldb::addr_t load_addr = process_address + m_offset;
1299254721Semaste
1300314564Sdim    dump_stream.Printf("0x%" PRIx64 ": EntityRegister (%s)\n", load_addr,
1301314564Sdim                       m_register_info.name);
1302309124Sdim
1303314564Sdim    {
1304314564Sdim      dump_stream.Printf("Value:\n");
1305309124Sdim
1306314564Sdim      DataBufferHeap data(m_size, 0);
1307309124Sdim
1308314564Sdim      map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
1309309124Sdim
1310314564Sdim      if (!err.Success()) {
1311314564Sdim        dump_stream.Printf("  <could not be read>\n");
1312314564Sdim      } else {
1313321369Sdim        DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
1314321369Sdim                     load_addr);
1315309124Sdim
1316314564Sdim        dump_stream.PutChar('\n');
1317314564Sdim      }
1318314564Sdim    }
1319309124Sdim
1320314564Sdim    log->PutString(dump_stream.GetString());
1321314564Sdim  }
1322309124Sdim
1323314564Sdim  void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {}
1324309124Sdim
1325254721Semasteprivate:
1326314564Sdim  RegisterInfo m_register_info;
1327314564Sdim  lldb::DataBufferSP m_register_contents;
1328254721Semaste};
1329254721Semaste
1330314564Sdimuint32_t Materializer::AddRegister(const RegisterInfo &register_info,
1331321369Sdim                                   Status &err) {
1332314564Sdim  EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
1333314564Sdim  iter->reset(new EntityRegister(register_info));
1334314564Sdim  uint32_t ret = AddStructMember(**iter);
1335314564Sdim  (*iter)->SetOffset(ret);
1336314564Sdim  return ret;
1337254721Semaste}
1338254721Semaste
1339314564SdimMaterializer::Materializer()
1340314564Sdim    : m_dematerializer_wp(), m_current_offset(0), m_struct_alignment(8) {}
1341254721Semaste
1342314564SdimMaterializer::~Materializer() {
1343314564Sdim  DematerializerSP dematerializer_sp = m_dematerializer_wp.lock();
1344309124Sdim
1345314564Sdim  if (dematerializer_sp)
1346314564Sdim    dematerializer_sp->Wipe();
1347254721Semaste}
1348254721Semaste
1349254721SemasteMaterializer::DematerializerSP
1350314564SdimMaterializer::Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1351321369Sdim                          lldb::addr_t process_address, Status &error) {
1352314564Sdim  ExecutionContextScope *exe_scope = frame_sp.get();
1353276479Sdim
1354314564Sdim  if (!exe_scope)
1355314564Sdim    exe_scope = map.GetBestExecutionContextScope();
1356276479Sdim
1357314564Sdim  DematerializerSP dematerializer_sp = m_dematerializer_wp.lock();
1358276479Sdim
1359314564Sdim  if (dematerializer_sp) {
1360314564Sdim    error.SetErrorToGenericError();
1361314564Sdim    error.SetErrorString("Couldn't materialize: already materialized");
1362314564Sdim  }
1363276479Sdim
1364314564Sdim  DematerializerSP ret(
1365314564Sdim      new Dematerializer(*this, frame_sp, map, process_address));
1366276479Sdim
1367314564Sdim  if (!exe_scope) {
1368314564Sdim    error.SetErrorToGenericError();
1369314564Sdim    error.SetErrorString("Couldn't materialize: target doesn't exist");
1370314564Sdim  }
1371276479Sdim
1372314564Sdim  for (EntityUP &entity_up : m_entities) {
1373314564Sdim    entity_up->Materialize(frame_sp, map, process_address, error);
1374276479Sdim
1375314564Sdim    if (!error.Success())
1376314564Sdim      return DematerializerSP();
1377314564Sdim  }
1378276479Sdim
1379314564Sdim  if (Log *log =
1380314564Sdim          lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)) {
1381314564Sdim    log->Printf(
1382314564Sdim        "Materializer::Materialize (frame_sp = %p, process_address = 0x%" PRIx64
1383314564Sdim        ") materialized:",
1384314564Sdim        static_cast<void *>(frame_sp.get()), process_address);
1385314564Sdim    for (EntityUP &entity_up : m_entities)
1386314564Sdim      entity_up->DumpToLog(map, process_address, log);
1387314564Sdim  }
1388276479Sdim
1389314564Sdim  m_dematerializer_wp = ret;
1390276479Sdim
1391314564Sdim  return ret;
1392254721Semaste}
1393254721Semaste
1394321369Sdimvoid Materializer::Dematerializer::Dematerialize(Status &error,
1395314564Sdim                                                 lldb::addr_t frame_bottom,
1396314564Sdim                                                 lldb::addr_t frame_top) {
1397314564Sdim  lldb::StackFrameSP frame_sp;
1398254721Semaste
1399314564Sdim  lldb::ThreadSP thread_sp = m_thread_wp.lock();
1400314564Sdim  if (thread_sp)
1401314564Sdim    frame_sp = thread_sp->GetFrameWithStackID(m_stack_id);
1402276479Sdim
1403314564Sdim  ExecutionContextScope *exe_scope = m_map->GetBestExecutionContextScope();
1404276479Sdim
1405314564Sdim  if (!IsValid()) {
1406314564Sdim    error.SetErrorToGenericError();
1407314564Sdim    error.SetErrorString("Couldn't dematerialize: invalid dematerializer");
1408314564Sdim  }
1409276479Sdim
1410314564Sdim  if (!exe_scope) {
1411314564Sdim    error.SetErrorToGenericError();
1412314564Sdim    error.SetErrorString("Couldn't dematerialize: target is gone");
1413314564Sdim  } else {
1414314564Sdim    if (Log *log =
1415314564Sdim            lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)) {
1416314564Sdim      log->Printf("Materializer::Dematerialize (frame_sp = %p, process_address "
1417314564Sdim                  "= 0x%" PRIx64 ") about to dematerialize:",
1418314564Sdim                  static_cast<void *>(frame_sp.get()), m_process_address);
1419314564Sdim      for (EntityUP &entity_up : m_materializer->m_entities)
1420314564Sdim        entity_up->DumpToLog(*m_map, m_process_address, log);
1421254721Semaste    }
1422276479Sdim
1423314564Sdim    for (EntityUP &entity_up : m_materializer->m_entities) {
1424314564Sdim      entity_up->Dematerialize(frame_sp, *m_map, m_process_address, frame_top,
1425314564Sdim                               frame_bottom, error);
1426276479Sdim
1427314564Sdim      if (!error.Success())
1428314564Sdim        break;
1429254721Semaste    }
1430314564Sdim  }
1431276479Sdim
1432314564Sdim  Wipe();
1433254721Semaste}
1434254721Semaste
1435314564Sdimvoid Materializer::Dematerializer::Wipe() {
1436314564Sdim  if (!IsValid())
1437314564Sdim    return;
1438309124Sdim
1439314564Sdim  for (EntityUP &entity_up : m_materializer->m_entities) {
1440314564Sdim    entity_up->Wipe(*m_map, m_process_address);
1441314564Sdim  }
1442254721Semaste
1443314564Sdim  m_materializer = nullptr;
1444314564Sdim  m_map = nullptr;
1445314564Sdim  m_process_address = LLDB_INVALID_ADDRESS;
1446254721Semaste}
1447296417Sdim
1448314564SdimMaterializer::PersistentVariableDelegate::~PersistentVariableDelegate() =
1449314564Sdim    default;
1450