Materializer.cpp revision 321369
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
10296417Sdim// C Includes
11296417Sdim// C++ Includes
12296417Sdim// Other libraries and framework includes
13296417Sdim// Project includes
14314564Sdim#include "lldb/Expression/Materializer.h"
15321369Sdim#include "lldb/Core/DumpDataExtractor.h"
16254721Semaste#include "lldb/Core/RegisterValue.h"
17254721Semaste#include "lldb/Core/ValueObjectConstResult.h"
18254721Semaste#include "lldb/Core/ValueObjectVariable.h"
19296417Sdim#include "lldb/Expression/ExpressionVariable.h"
20254721Semaste#include "lldb/Symbol/ClangASTContext.h"
21254721Semaste#include "lldb/Symbol/Symbol.h"
22254721Semaste#include "lldb/Symbol/Type.h"
23254721Semaste#include "lldb/Symbol/Variable.h"
24254721Semaste#include "lldb/Target/ExecutionContext.h"
25254721Semaste#include "lldb/Target/RegisterContext.h"
26254721Semaste#include "lldb/Target/StackFrame.h"
27254721Semaste#include "lldb/Target/Target.h"
28254721Semaste#include "lldb/Target/Thread.h"
29321369Sdim#include "lldb/Utility/Log.h"
30254721Semaste
31254721Semasteusing namespace lldb_private;
32254721Semaste
33314564Sdimuint32_t Materializer::AddStructMember(Entity &entity) {
34314564Sdim  uint32_t size = entity.GetSize();
35314564Sdim  uint32_t alignment = entity.GetAlignment();
36309124Sdim
37314564Sdim  uint32_t ret;
38309124Sdim
39314564Sdim  if (m_current_offset == 0)
40314564Sdim    m_struct_alignment = alignment;
41309124Sdim
42314564Sdim  if (m_current_offset % alignment)
43314564Sdim    m_current_offset += (alignment - (m_current_offset % alignment));
44309124Sdim
45314564Sdim  ret = m_current_offset;
46309124Sdim
47314564Sdim  m_current_offset += size;
48309124Sdim
49314564Sdim  return ret;
50254721Semaste}
51254721Semaste
52314564Sdimvoid Materializer::Entity::SetSizeAndAlignmentFromType(CompilerType &type) {
53314564Sdim  m_size = type.GetByteSize(nullptr);
54309124Sdim
55314564Sdim  uint32_t bit_alignment = type.GetTypeBitAlign();
56309124Sdim
57314564Sdim  if (bit_alignment % 8) {
58314564Sdim    bit_alignment += 8;
59314564Sdim    bit_alignment &= ~((uint32_t)0x111u);
60314564Sdim  }
61309124Sdim
62314564Sdim  m_alignment = bit_alignment / 8;
63254721Semaste}
64254721Semaste
65314564Sdimclass EntityPersistentVariable : public Materializer::Entity {
66254721Semastepublic:
67314564Sdim  EntityPersistentVariable(lldb::ExpressionVariableSP &persistent_variable_sp,
68314564Sdim                           Materializer::PersistentVariableDelegate *delegate)
69314564Sdim      : Entity(), m_persistent_variable_sp(persistent_variable_sp),
70314564Sdim        m_delegate(delegate) {
71314564Sdim    // Hard-coding to maximum size of a pointer since persistent variables are
72314564Sdim    // materialized by reference
73314564Sdim    m_size = 8;
74314564Sdim    m_alignment = 8;
75314564Sdim  }
76309124Sdim
77321369Sdim  void MakeAllocation(IRMemoryMap &map, Status &err) {
78314564Sdim    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
79254721Semaste
80314564Sdim    // Allocate a spare memory area to store the persistent variable's contents.
81309124Sdim
82321369Sdim    Status allocate_error;
83314564Sdim    const bool zero_memory = false;
84309124Sdim
85314564Sdim    lldb::addr_t mem = map.Malloc(
86314564Sdim        m_persistent_variable_sp->GetByteSize(), 8,
87314564Sdim        lldb::ePermissionsReadable | lldb::ePermissionsWritable,
88314564Sdim        IRMemoryMap::eAllocationPolicyMirror, zero_memory, allocate_error);
89309124Sdim
90314564Sdim    if (!allocate_error.Success()) {
91314564Sdim      err.SetErrorStringWithFormat(
92314564Sdim          "couldn't allocate a memory area to store %s: %s",
93314564Sdim          m_persistent_variable_sp->GetName().GetCString(),
94314564Sdim          allocate_error.AsCString());
95314564Sdim      return;
96314564Sdim    }
97309124Sdim
98314564Sdim    if (log)
99314564Sdim      log->Printf("Allocated %s (0x%" PRIx64 ") successfully",
100314564Sdim                  m_persistent_variable_sp->GetName().GetCString(), mem);
101309124Sdim
102314564Sdim    // Put the location of the spare memory into the live data of the
103314564Sdim    // ValueObject.
104309124Sdim
105314564Sdim    m_persistent_variable_sp->m_live_sp = ValueObjectConstResult::Create(
106314564Sdim        map.GetBestExecutionContextScope(),
107314564Sdim        m_persistent_variable_sp->GetCompilerType(),
108314564Sdim        m_persistent_variable_sp->GetName(), mem, eAddressTypeLoad,
109314564Sdim        map.GetAddressByteSize());
110309124Sdim
111314564Sdim    // Clear the flag if the variable will never be deallocated.
112309124Sdim
113314564Sdim    if (m_persistent_variable_sp->m_flags &
114314564Sdim        ExpressionVariable::EVKeepInTarget) {
115321369Sdim      Status leak_error;
116314564Sdim      map.Leak(mem, leak_error);
117314564Sdim      m_persistent_variable_sp->m_flags &=
118314564Sdim          ~ExpressionVariable::EVNeedsAllocation;
119314564Sdim    }
120309124Sdim
121314564Sdim    // Write the contents of the variable to the area.
122309124Sdim
123321369Sdim    Status write_error;
124309124Sdim
125314564Sdim    map.WriteMemory(mem, m_persistent_variable_sp->GetValueBytes(),
126314564Sdim                    m_persistent_variable_sp->GetByteSize(), write_error);
127309124Sdim
128314564Sdim    if (!write_error.Success()) {
129314564Sdim      err.SetErrorStringWithFormat(
130314564Sdim          "couldn't write %s to the target: %s",
131314564Sdim          m_persistent_variable_sp->GetName().AsCString(),
132314564Sdim          write_error.AsCString());
133314564Sdim      return;
134254721Semaste    }
135314564Sdim  }
136309124Sdim
137321369Sdim  void DestroyAllocation(IRMemoryMap &map, Status &err) {
138321369Sdim    Status deallocate_error;
139309124Sdim
140314564Sdim    map.Free((lldb::addr_t)m_persistent_variable_sp->m_live_sp->GetValue()
141314564Sdim                 .GetScalar()
142314564Sdim                 .ULongLong(),
143314564Sdim             deallocate_error);
144309124Sdim
145314564Sdim    m_persistent_variable_sp->m_live_sp.reset();
146309124Sdim
147314564Sdim    if (!deallocate_error.Success()) {
148314564Sdim      err.SetErrorStringWithFormat(
149314564Sdim          "couldn't deallocate memory for %s: %s",
150314564Sdim          m_persistent_variable_sp->GetName().GetCString(),
151314564Sdim          deallocate_error.AsCString());
152254721Semaste    }
153314564Sdim  }
154309124Sdim
155314564Sdim  void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
156321369Sdim                   lldb::addr_t process_address, Status &err) override {
157314564Sdim    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
158254721Semaste
159314564Sdim    const lldb::addr_t load_addr = process_address + m_offset;
160309124Sdim
161314564Sdim    if (log) {
162314564Sdim      log->Printf("EntityPersistentVariable::Materialize [address = 0x%" PRIx64
163314564Sdim                  ", m_name = %s, m_flags = 0x%hx]",
164314564Sdim                  (uint64_t)load_addr,
165314564Sdim                  m_persistent_variable_sp->GetName().AsCString(),
166314564Sdim                  m_persistent_variable_sp->m_flags);
167314564Sdim    }
168309124Sdim
169314564Sdim    if (m_persistent_variable_sp->m_flags &
170314564Sdim        ExpressionVariable::EVNeedsAllocation) {
171314564Sdim      MakeAllocation(map, err);
172314564Sdim      m_persistent_variable_sp->m_flags |=
173314564Sdim          ExpressionVariable::EVIsLLDBAllocated;
174309124Sdim
175314564Sdim      if (!err.Success())
176314564Sdim        return;
177314564Sdim    }
178309124Sdim
179314564Sdim    if ((m_persistent_variable_sp->m_flags &
180314564Sdim             ExpressionVariable::EVIsProgramReference &&
181314564Sdim         m_persistent_variable_sp->m_live_sp) ||
182314564Sdim        m_persistent_variable_sp->m_flags &
183314564Sdim            ExpressionVariable::EVIsLLDBAllocated) {
184321369Sdim      Status write_error;
185309124Sdim
186314564Sdim      map.WriteScalarToMemory(
187314564Sdim          load_addr,
188314564Sdim          m_persistent_variable_sp->m_live_sp->GetValue().GetScalar(),
189314564Sdim          map.GetAddressByteSize(), write_error);
190309124Sdim
191314564Sdim      if (!write_error.Success()) {
192314564Sdim        err.SetErrorStringWithFormat(
193314564Sdim            "couldn't write the location of %s to memory: %s",
194314564Sdim            m_persistent_variable_sp->GetName().AsCString(),
195314564Sdim            write_error.AsCString());
196314564Sdim      }
197314564Sdim    } else {
198314564Sdim      err.SetErrorStringWithFormat(
199314564Sdim          "no materialization happened for persistent variable %s",
200314564Sdim          m_persistent_variable_sp->GetName().AsCString());
201314564Sdim      return;
202254721Semaste    }
203314564Sdim  }
204309124Sdim
205314564Sdim  void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
206314564Sdim                     lldb::addr_t process_address, lldb::addr_t frame_top,
207321369Sdim                     lldb::addr_t frame_bottom, Status &err) override {
208314564Sdim    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
209309124Sdim
210314564Sdim    const lldb::addr_t load_addr = process_address + m_offset;
211254721Semaste
212314564Sdim    if (log) {
213314564Sdim      log->Printf(
214314564Sdim          "EntityPersistentVariable::Dematerialize [address = 0x%" PRIx64
215314564Sdim          ", m_name = %s, m_flags = 0x%hx]",
216314564Sdim          (uint64_t)process_address + m_offset,
217314564Sdim          m_persistent_variable_sp->GetName().AsCString(),
218314564Sdim          m_persistent_variable_sp->m_flags);
219314564Sdim    }
220309124Sdim
221314564Sdim    if (m_delegate) {
222314564Sdim      m_delegate->DidDematerialize(m_persistent_variable_sp);
223314564Sdim    }
224296417Sdim
225314564Sdim    if ((m_persistent_variable_sp->m_flags &
226314564Sdim         ExpressionVariable::EVIsLLDBAllocated) ||
227314564Sdim        (m_persistent_variable_sp->m_flags &
228314564Sdim         ExpressionVariable::EVIsProgramReference)) {
229314564Sdim      if (m_persistent_variable_sp->m_flags &
230314564Sdim              ExpressionVariable::EVIsProgramReference &&
231314564Sdim          !m_persistent_variable_sp->m_live_sp) {
232314564Sdim        // If the reference comes from the program, then the
233314564Sdim        // ClangExpressionVariable's
234314564Sdim        // live variable data hasn't been set up yet.  Do this now.
235309124Sdim
236314564Sdim        lldb::addr_t location;
237321369Sdim        Status read_error;
238309124Sdim
239314564Sdim        map.ReadPointerFromMemory(&location, load_addr, read_error);
240309124Sdim
241314564Sdim        if (!read_error.Success()) {
242314564Sdim          err.SetErrorStringWithFormat(
243314564Sdim              "couldn't read the address of program-allocated variable %s: %s",
244314564Sdim              m_persistent_variable_sp->GetName().GetCString(),
245314564Sdim              read_error.AsCString());
246314564Sdim          return;
247314564Sdim        }
248309124Sdim
249314564Sdim        m_persistent_variable_sp->m_live_sp = ValueObjectConstResult::Create(
250314564Sdim            map.GetBestExecutionContextScope(),
251314564Sdim            m_persistent_variable_sp.get()->GetCompilerType(),
252314564Sdim            m_persistent_variable_sp->GetName(), location, eAddressTypeLoad,
253314564Sdim            m_persistent_variable_sp->GetByteSize());
254309124Sdim
255314564Sdim        if (frame_top != LLDB_INVALID_ADDRESS &&
256314564Sdim            frame_bottom != LLDB_INVALID_ADDRESS && location >= frame_bottom &&
257314564Sdim            location <= frame_top) {
258314564Sdim          // If the variable is resident in the stack frame created by the
259314564Sdim          // expression,
260314564Sdim          // then it cannot be relied upon to stay around.  We treat it as
261314564Sdim          // needing
262314564Sdim          // reallocation.
263314564Sdim          m_persistent_variable_sp->m_flags |=
264314564Sdim              ExpressionVariable::EVIsLLDBAllocated;
265314564Sdim          m_persistent_variable_sp->m_flags |=
266314564Sdim              ExpressionVariable::EVNeedsAllocation;
267314564Sdim          m_persistent_variable_sp->m_flags |=
268314564Sdim              ExpressionVariable::EVNeedsFreezeDry;
269314564Sdim          m_persistent_variable_sp->m_flags &=
270314564Sdim              ~ExpressionVariable::EVIsProgramReference;
271314564Sdim        }
272314564Sdim      }
273309124Sdim
274314564Sdim      lldb::addr_t mem = m_persistent_variable_sp->m_live_sp->GetValue()
275314564Sdim                             .GetScalar()
276314564Sdim                             .ULongLong();
277309124Sdim
278314564Sdim      if (!m_persistent_variable_sp->m_live_sp) {
279314564Sdim        err.SetErrorStringWithFormat(
280314564Sdim            "couldn't find the memory area used to store %s",
281314564Sdim            m_persistent_variable_sp->GetName().GetCString());
282314564Sdim        return;
283314564Sdim      }
284309124Sdim
285314564Sdim      if (m_persistent_variable_sp->m_live_sp->GetValue()
286314564Sdim              .GetValueAddressType() != eAddressTypeLoad) {
287314564Sdim        err.SetErrorStringWithFormat(
288314564Sdim            "the address of the memory area for %s is in an incorrect format",
289314564Sdim            m_persistent_variable_sp->GetName().GetCString());
290314564Sdim        return;
291314564Sdim      }
292309124Sdim
293314564Sdim      if (m_persistent_variable_sp->m_flags &
294314564Sdim              ExpressionVariable::EVNeedsFreezeDry ||
295314564Sdim          m_persistent_variable_sp->m_flags &
296314564Sdim              ExpressionVariable::EVKeepInTarget) {
297314564Sdim        if (log)
298314564Sdim          log->Printf(
299314564Sdim              "Dematerializing %s from 0x%" PRIx64 " (size = %llu)",
300314564Sdim              m_persistent_variable_sp->GetName().GetCString(), (uint64_t)mem,
301314564Sdim              (unsigned long long)m_persistent_variable_sp->GetByteSize());
302309124Sdim
303314564Sdim        // Read the contents of the spare memory area
304309124Sdim
305314564Sdim        m_persistent_variable_sp->ValueUpdated();
306309124Sdim
307321369Sdim        Status read_error;
308309124Sdim
309314564Sdim        map.ReadMemory(m_persistent_variable_sp->GetValueBytes(), mem,
310314564Sdim                       m_persistent_variable_sp->GetByteSize(), read_error);
311309124Sdim
312314564Sdim        if (!read_error.Success()) {
313314564Sdim          err.SetErrorStringWithFormat(
314314564Sdim              "couldn't read the contents of %s from memory: %s",
315314564Sdim              m_persistent_variable_sp->GetName().GetCString(),
316314564Sdim              read_error.AsCString());
317314564Sdim          return;
318254721Semaste        }
319309124Sdim
320314564Sdim        m_persistent_variable_sp->m_flags &=
321314564Sdim            ~ExpressionVariable::EVNeedsFreezeDry;
322314564Sdim      }
323314564Sdim    } else {
324314564Sdim      err.SetErrorStringWithFormat(
325314564Sdim          "no dematerialization happened for persistent variable %s",
326314564Sdim          m_persistent_variable_sp->GetName().AsCString());
327314564Sdim      return;
328314564Sdim    }
329309124Sdim
330314564Sdim    lldb::ProcessSP process_sp =
331314564Sdim        map.GetBestExecutionContextScope()->CalculateProcess();
332314564Sdim    if (!process_sp || !process_sp->CanJIT()) {
333314564Sdim      // Allocations are not persistent so persistent variables cannot stay
334314564Sdim      // materialized.
335254721Semaste
336314564Sdim      m_persistent_variable_sp->m_flags |=
337314564Sdim          ExpressionVariable::EVNeedsAllocation;
338314564Sdim
339314564Sdim      DestroyAllocation(map, err);
340314564Sdim      if (!err.Success())
341314564Sdim        return;
342314564Sdim    } else if (m_persistent_variable_sp->m_flags &
343314564Sdim                   ExpressionVariable::EVNeedsAllocation &&
344314564Sdim               !(m_persistent_variable_sp->m_flags &
345314564Sdim                 ExpressionVariable::EVKeepInTarget)) {
346314564Sdim      DestroyAllocation(map, err);
347314564Sdim      if (!err.Success())
348314564Sdim        return;
349254721Semaste    }
350314564Sdim  }
351309124Sdim
352314564Sdim  void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
353314564Sdim                 Log *log) override {
354314564Sdim    StreamString dump_stream;
355309124Sdim
356321369Sdim    Status err;
357309124Sdim
358314564Sdim    const lldb::addr_t load_addr = process_address + m_offset;
359254721Semaste
360314564Sdim    dump_stream.Printf("0x%" PRIx64 ": EntityPersistentVariable (%s)\n",
361314564Sdim                       load_addr,
362314564Sdim                       m_persistent_variable_sp->GetName().AsCString());
363309124Sdim
364314564Sdim    {
365314564Sdim      dump_stream.Printf("Pointer:\n");
366309124Sdim
367314564Sdim      DataBufferHeap data(m_size, 0);
368309124Sdim
369314564Sdim      map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
370309124Sdim
371314564Sdim      if (!err.Success()) {
372314564Sdim        dump_stream.Printf("  <could not be read>\n");
373314564Sdim      } else {
374321369Sdim        DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
375321369Sdim                     load_addr);
376309124Sdim
377314564Sdim        dump_stream.PutChar('\n');
378314564Sdim      }
379314564Sdim    }
380309124Sdim
381314564Sdim    {
382314564Sdim      dump_stream.Printf("Target:\n");
383309124Sdim
384314564Sdim      lldb::addr_t target_address;
385309124Sdim
386314564Sdim      map.ReadPointerFromMemory(&target_address, load_addr, err);
387309124Sdim
388314564Sdim      if (!err.Success()) {
389314564Sdim        dump_stream.Printf("  <could not be read>\n");
390314564Sdim      } else {
391314564Sdim        DataBufferHeap data(m_persistent_variable_sp->GetByteSize(), 0);
392309124Sdim
393314564Sdim        map.ReadMemory(data.GetBytes(), target_address,
394314564Sdim                       m_persistent_variable_sp->GetByteSize(), err);
395309124Sdim
396314564Sdim        if (!err.Success()) {
397314564Sdim          dump_stream.Printf("  <could not be read>\n");
398314564Sdim        } else {
399321369Sdim          DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
400321369Sdim                       target_address);
401309124Sdim
402314564Sdim          dump_stream.PutChar('\n');
403254721Semaste        }
404314564Sdim      }
405254721Semaste    }
406309124Sdim
407314564Sdim    log->PutString(dump_stream.GetString());
408314564Sdim  }
409296417Sdim
410314564Sdim  void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {}
411314564Sdim
412254721Semasteprivate:
413314564Sdim  lldb::ExpressionVariableSP m_persistent_variable_sp;
414314564Sdim  Materializer::PersistentVariableDelegate *m_delegate;
415254721Semaste};
416254721Semaste
417314564Sdimuint32_t Materializer::AddPersistentVariable(
418314564Sdim    lldb::ExpressionVariableSP &persistent_variable_sp,
419321369Sdim    PersistentVariableDelegate *delegate, Status &err) {
420314564Sdim  EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
421314564Sdim  iter->reset(new EntityPersistentVariable(persistent_variable_sp, delegate));
422314564Sdim  uint32_t ret = AddStructMember(**iter);
423314564Sdim  (*iter)->SetOffset(ret);
424314564Sdim  return ret;
425254721Semaste}
426254721Semaste
427314564Sdimclass EntityVariable : public Materializer::Entity {
428254721Semastepublic:
429314564Sdim  EntityVariable(lldb::VariableSP &variable_sp)
430314564Sdim      : Entity(), m_variable_sp(variable_sp), m_is_reference(false),
431254721Semaste        m_temporary_allocation(LLDB_INVALID_ADDRESS),
432314564Sdim        m_temporary_allocation_size(0) {
433314564Sdim    // Hard-coding to maximum size of a pointer since all variables are
434314564Sdim    // materialized by reference
435314564Sdim    m_size = 8;
436314564Sdim    m_alignment = 8;
437314564Sdim    m_is_reference =
438314564Sdim        m_variable_sp->GetType()->GetForwardCompilerType().IsReferenceType();
439314564Sdim  }
440314564Sdim
441314564Sdim  void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
442321369Sdim                   lldb::addr_t process_address, Status &err) override {
443314564Sdim    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
444314564Sdim
445314564Sdim    const lldb::addr_t load_addr = process_address + m_offset;
446314564Sdim    if (log) {
447314564Sdim      log->Printf("EntityVariable::Materialize [address = 0x%" PRIx64
448314564Sdim                  ", m_variable_sp = %s]",
449314564Sdim                  (uint64_t)load_addr, m_variable_sp->GetName().AsCString());
450254721Semaste    }
451309124Sdim
452314564Sdim    ExecutionContextScope *scope = frame_sp.get();
453309124Sdim
454314564Sdim    if (!scope)
455314564Sdim      scope = map.GetBestExecutionContextScope();
456309124Sdim
457314564Sdim    lldb::ValueObjectSP valobj_sp =
458314564Sdim        ValueObjectVariable::Create(scope, m_variable_sp);
459309124Sdim
460314564Sdim    if (!valobj_sp) {
461314564Sdim      err.SetErrorStringWithFormat(
462314564Sdim          "couldn't get a value object for variable %s",
463314564Sdim          m_variable_sp->GetName().AsCString());
464314564Sdim      return;
465314564Sdim    }
466309124Sdim
467321369Sdim    Status valobj_error = valobj_sp->GetError();
468309124Sdim
469314564Sdim    if (valobj_error.Fail()) {
470314564Sdim      err.SetErrorStringWithFormat("couldn't get the value of variable %s: %s",
471314564Sdim                                   m_variable_sp->GetName().AsCString(),
472314564Sdim                                   valobj_error.AsCString());
473314564Sdim      return;
474314564Sdim    }
475309124Sdim
476314564Sdim    if (m_is_reference) {
477314564Sdim      DataExtractor valobj_extractor;
478321369Sdim      Status extract_error;
479314564Sdim      valobj_sp->GetData(valobj_extractor, extract_error);
480309124Sdim
481314564Sdim      if (!extract_error.Success()) {
482314564Sdim        err.SetErrorStringWithFormat(
483314564Sdim            "couldn't read contents of reference variable %s: %s",
484314564Sdim            m_variable_sp->GetName().AsCString(), extract_error.AsCString());
485314564Sdim        return;
486314564Sdim      }
487309124Sdim
488314564Sdim      lldb::offset_t offset = 0;
489314564Sdim      lldb::addr_t reference_addr = valobj_extractor.GetAddress(&offset);
490309124Sdim
491321369Sdim      Status write_error;
492314564Sdim      map.WritePointerToMemory(load_addr, reference_addr, write_error);
493309124Sdim
494314564Sdim      if (!write_error.Success()) {
495314564Sdim        err.SetErrorStringWithFormat("couldn't write the contents of reference "
496314564Sdim                                     "variable %s to memory: %s",
497314564Sdim                                     m_variable_sp->GetName().AsCString(),
498314564Sdim                                     write_error.AsCString());
499314564Sdim        return;
500314564Sdim      }
501314564Sdim    } else {
502314564Sdim      AddressType address_type = eAddressTypeInvalid;
503314564Sdim      const bool scalar_is_load_address = false;
504314564Sdim      lldb::addr_t addr_of_valobj =
505314564Sdim          valobj_sp->GetAddressOf(scalar_is_load_address, &address_type);
506314564Sdim      if (addr_of_valobj != LLDB_INVALID_ADDRESS) {
507321369Sdim        Status write_error;
508314564Sdim        map.WritePointerToMemory(load_addr, addr_of_valobj, write_error);
509309124Sdim
510314564Sdim        if (!write_error.Success()) {
511314564Sdim          err.SetErrorStringWithFormat(
512314564Sdim              "couldn't write the address of variable %s to memory: %s",
513314564Sdim              m_variable_sp->GetName().AsCString(), write_error.AsCString());
514314564Sdim          return;
515314564Sdim        }
516314564Sdim      } else {
517314564Sdim        DataExtractor data;
518321369Sdim        Status extract_error;
519314564Sdim        valobj_sp->GetData(data, extract_error);
520314564Sdim        if (!extract_error.Success()) {
521314564Sdim          err.SetErrorStringWithFormat("couldn't get the value of %s: %s",
522314564Sdim                                       m_variable_sp->GetName().AsCString(),
523314564Sdim                                       extract_error.AsCString());
524314564Sdim          return;
525314564Sdim        }
526309124Sdim
527314564Sdim        if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
528314564Sdim          err.SetErrorStringWithFormat(
529314564Sdim              "trying to create a temporary region for %s but one exists",
530314564Sdim              m_variable_sp->GetName().AsCString());
531314564Sdim          return;
532254721Semaste        }
533309124Sdim
534314564Sdim        if (data.GetByteSize() < m_variable_sp->GetType()->GetByteSize()) {
535314564Sdim          if (data.GetByteSize() == 0 &&
536314564Sdim              m_variable_sp->LocationExpression().IsValid() == false) {
537314564Sdim            err.SetErrorStringWithFormat("the variable '%s' has no location, "
538314564Sdim                                         "it may have been optimized out",
539314564Sdim                                         m_variable_sp->GetName().AsCString());
540314564Sdim          } else {
541314564Sdim            err.SetErrorStringWithFormat(
542314564Sdim                "size of variable %s (%" PRIu64
543314564Sdim                ") is larger than the ValueObject's size (%" PRIu64 ")",
544314564Sdim                m_variable_sp->GetName().AsCString(),
545314564Sdim                m_variable_sp->GetType()->GetByteSize(), data.GetByteSize());
546314564Sdim          }
547314564Sdim          return;
548314564Sdim        }
549309124Sdim
550314564Sdim        size_t bit_align =
551314564Sdim            m_variable_sp->GetType()->GetLayoutCompilerType().GetTypeBitAlign();
552314564Sdim        size_t byte_align = (bit_align + 7) / 8;
553309124Sdim
554314564Sdim        if (!byte_align)
555314564Sdim          byte_align = 1;
556309124Sdim
557321369Sdim        Status alloc_error;
558314564Sdim        const bool zero_memory = false;
559309124Sdim
560314564Sdim        m_temporary_allocation = map.Malloc(
561314564Sdim            data.GetByteSize(), byte_align,
562314564Sdim            lldb::ePermissionsReadable | lldb::ePermissionsWritable,
563314564Sdim            IRMemoryMap::eAllocationPolicyMirror, zero_memory, alloc_error);
564309124Sdim
565314564Sdim        m_temporary_allocation_size = data.GetByteSize();
566296417Sdim
567314564Sdim        m_original_data.reset(
568314564Sdim            new DataBufferHeap(data.GetDataStart(), data.GetByteSize()));
569309124Sdim
570314564Sdim        if (!alloc_error.Success()) {
571314564Sdim          err.SetErrorStringWithFormat(
572314564Sdim              "couldn't allocate a temporary region for %s: %s",
573314564Sdim              m_variable_sp->GetName().AsCString(), alloc_error.AsCString());
574314564Sdim          return;
575314564Sdim        }
576309124Sdim
577321369Sdim        Status write_error;
578309124Sdim
579314564Sdim        map.WriteMemory(m_temporary_allocation, data.GetDataStart(),
580314564Sdim                        data.GetByteSize(), write_error);
581309124Sdim
582314564Sdim        if (!write_error.Success()) {
583314564Sdim          err.SetErrorStringWithFormat(
584314564Sdim              "couldn't write to the temporary region for %s: %s",
585314564Sdim              m_variable_sp->GetName().AsCString(), write_error.AsCString());
586314564Sdim          return;
587314564Sdim        }
588309124Sdim
589321369Sdim        Status pointer_write_error;
590309124Sdim
591314564Sdim        map.WritePointerToMemory(load_addr, m_temporary_allocation,
592314564Sdim                                 pointer_write_error);
593309124Sdim
594314564Sdim        if (!pointer_write_error.Success()) {
595314564Sdim          err.SetErrorStringWithFormat(
596314564Sdim              "couldn't write the address of the temporary region for %s: %s",
597314564Sdim              m_variable_sp->GetName().AsCString(),
598314564Sdim              pointer_write_error.AsCString());
599254721Semaste        }
600314564Sdim      }
601254721Semaste    }
602314564Sdim  }
603309124Sdim
604314564Sdim  void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
605314564Sdim                     lldb::addr_t process_address, lldb::addr_t frame_top,
606321369Sdim                     lldb::addr_t frame_bottom, Status &err) override {
607314564Sdim    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
608254721Semaste
609314564Sdim    const lldb::addr_t load_addr = process_address + m_offset;
610314564Sdim    if (log) {
611314564Sdim      log->Printf("EntityVariable::Dematerialize [address = 0x%" PRIx64
612314564Sdim                  ", m_variable_sp = %s]",
613314564Sdim                  (uint64_t)load_addr, m_variable_sp->GetName().AsCString());
614314564Sdim    }
615309124Sdim
616314564Sdim    if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
617314564Sdim      ExecutionContextScope *scope = frame_sp.get();
618309124Sdim
619314564Sdim      if (!scope)
620314564Sdim        scope = map.GetBestExecutionContextScope();
621309124Sdim
622314564Sdim      lldb::ValueObjectSP valobj_sp =
623314564Sdim          ValueObjectVariable::Create(scope, m_variable_sp);
624309124Sdim
625314564Sdim      if (!valobj_sp) {
626314564Sdim        err.SetErrorStringWithFormat(
627314564Sdim            "couldn't get a value object for variable %s",
628314564Sdim            m_variable_sp->GetName().AsCString());
629314564Sdim        return;
630314564Sdim      }
631309124Sdim
632314564Sdim      lldb_private::DataExtractor data;
633309124Sdim
634321369Sdim      Status extract_error;
635309124Sdim
636314564Sdim      map.GetMemoryData(data, m_temporary_allocation, valobj_sp->GetByteSize(),
637314564Sdim                        extract_error);
638309124Sdim
639314564Sdim      if (!extract_error.Success()) {
640314564Sdim        err.SetErrorStringWithFormat("couldn't get the data for variable %s",
641314564Sdim                                     m_variable_sp->GetName().AsCString());
642314564Sdim        return;
643314564Sdim      }
644309124Sdim
645314564Sdim      bool actually_write = true;
646309124Sdim
647314564Sdim      if (m_original_data) {
648314564Sdim        if ((data.GetByteSize() == m_original_data->GetByteSize()) &&
649314564Sdim            !memcmp(m_original_data->GetBytes(), data.GetDataStart(),
650314564Sdim                    data.GetByteSize())) {
651314564Sdim          actually_write = false;
652314564Sdim        }
653314564Sdim      }
654309124Sdim
655321369Sdim      Status set_error;
656309124Sdim
657314564Sdim      if (actually_write) {
658314564Sdim        valobj_sp->SetData(data, set_error);
659309124Sdim
660314564Sdim        if (!set_error.Success()) {
661314564Sdim          err.SetErrorStringWithFormat(
662314564Sdim              "couldn't write the new contents of %s back into the variable",
663314564Sdim              m_variable_sp->GetName().AsCString());
664314564Sdim          return;
665314564Sdim        }
666314564Sdim      }
667309124Sdim
668321369Sdim      Status free_error;
669309124Sdim
670314564Sdim      map.Free(m_temporary_allocation, free_error);
671309124Sdim
672314564Sdim      if (!free_error.Success()) {
673314564Sdim        err.SetErrorStringWithFormat(
674314564Sdim            "couldn't free the temporary region for %s: %s",
675314564Sdim            m_variable_sp->GetName().AsCString(), free_error.AsCString());
676314564Sdim        return;
677314564Sdim      }
678309124Sdim
679314564Sdim      m_original_data.reset();
680314564Sdim      m_temporary_allocation = LLDB_INVALID_ADDRESS;
681314564Sdim      m_temporary_allocation_size = 0;
682254721Semaste    }
683314564Sdim  }
684309124Sdim
685314564Sdim  void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
686314564Sdim                 Log *log) override {
687314564Sdim    StreamString dump_stream;
688254721Semaste
689314564Sdim    const lldb::addr_t load_addr = process_address + m_offset;
690314564Sdim    dump_stream.Printf("0x%" PRIx64 ": EntityVariable\n", load_addr);
691309124Sdim
692321369Sdim    Status err;
693309124Sdim
694314564Sdim    lldb::addr_t ptr = LLDB_INVALID_ADDRESS;
695309124Sdim
696314564Sdim    {
697314564Sdim      dump_stream.Printf("Pointer:\n");
698309124Sdim
699314564Sdim      DataBufferHeap data(m_size, 0);
700309124Sdim
701314564Sdim      map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
702309124Sdim
703314564Sdim      if (!err.Success()) {
704314564Sdim        dump_stream.Printf("  <could not be read>\n");
705314564Sdim      } else {
706314564Sdim        DataExtractor extractor(data.GetBytes(), data.GetByteSize(),
707314564Sdim                                map.GetByteOrder(), map.GetAddressByteSize());
708309124Sdim
709321369Sdim        DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
710321369Sdim                     load_addr);
711309124Sdim
712314564Sdim        lldb::offset_t offset;
713309124Sdim
714314564Sdim        ptr = extractor.GetPointer(&offset);
715309124Sdim
716314564Sdim        dump_stream.PutChar('\n');
717314564Sdim      }
718314564Sdim    }
719309124Sdim
720314564Sdim    if (m_temporary_allocation == LLDB_INVALID_ADDRESS) {
721314564Sdim      dump_stream.Printf("Points to process memory:\n");
722314564Sdim    } else {
723314564Sdim      dump_stream.Printf("Temporary allocation:\n");
724314564Sdim    }
725309124Sdim
726314564Sdim    if (ptr == LLDB_INVALID_ADDRESS) {
727314564Sdim      dump_stream.Printf("  <could not be be found>\n");
728314564Sdim    } else {
729314564Sdim      DataBufferHeap data(m_temporary_allocation_size, 0);
730309124Sdim
731314564Sdim      map.ReadMemory(data.GetBytes(), m_temporary_allocation,
732314564Sdim                     m_temporary_allocation_size, err);
733309124Sdim
734314564Sdim      if (!err.Success()) {
735314564Sdim        dump_stream.Printf("  <could not be read>\n");
736314564Sdim      } else {
737321369Sdim        DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
738321369Sdim                     load_addr);
739309124Sdim
740314564Sdim        dump_stream.PutChar('\n');
741314564Sdim      }
742254721Semaste    }
743309124Sdim
744314564Sdim    log->PutString(dump_stream.GetString());
745314564Sdim  }
746309124Sdim
747314564Sdim  void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {
748314564Sdim    if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
749321369Sdim      Status free_error;
750309124Sdim
751314564Sdim      map.Free(m_temporary_allocation, free_error);
752254721Semaste
753314564Sdim      m_temporary_allocation = LLDB_INVALID_ADDRESS;
754314564Sdim      m_temporary_allocation_size = 0;
755254721Semaste    }
756314564Sdim  }
757296417Sdim
758254721Semasteprivate:
759314564Sdim  lldb::VariableSP m_variable_sp;
760314564Sdim  bool m_is_reference;
761314564Sdim  lldb::addr_t m_temporary_allocation;
762314564Sdim  size_t m_temporary_allocation_size;
763314564Sdim  lldb::DataBufferSP m_original_data;
764254721Semaste};
765254721Semaste
766321369Sdimuint32_t Materializer::AddVariable(lldb::VariableSP &variable_sp, Status &err) {
767314564Sdim  EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
768314564Sdim  iter->reset(new EntityVariable(variable_sp));
769314564Sdim  uint32_t ret = AddStructMember(**iter);
770314564Sdim  (*iter)->SetOffset(ret);
771314564Sdim  return ret;
772254721Semaste}
773254721Semaste
774314564Sdimclass EntityResultVariable : public Materializer::Entity {
775254721Semastepublic:
776314564Sdim  EntityResultVariable(const CompilerType &type, bool is_program_reference,
777314564Sdim                       bool keep_in_memory,
778314564Sdim                       Materializer::PersistentVariableDelegate *delegate)
779314564Sdim      : Entity(), m_type(type), m_is_program_reference(is_program_reference),
780254721Semaste        m_keep_in_memory(keep_in_memory),
781254721Semaste        m_temporary_allocation(LLDB_INVALID_ADDRESS),
782314564Sdim        m_temporary_allocation_size(0), m_delegate(delegate) {
783314564Sdim    // Hard-coding to maximum size of a pointer since all results are
784314564Sdim    // materialized by reference
785314564Sdim    m_size = 8;
786314564Sdim    m_alignment = 8;
787314564Sdim  }
788309124Sdim
789314564Sdim  void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
790321369Sdim                   lldb::addr_t process_address, Status &err) override {
791314564Sdim    if (!m_is_program_reference) {
792314564Sdim      if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
793314564Sdim        err.SetErrorString("Trying to create a temporary region for the result "
794314564Sdim                           "but one exists");
795314564Sdim        return;
796314564Sdim      }
797309124Sdim
798314564Sdim      const lldb::addr_t load_addr = process_address + m_offset;
799254721Semaste
800314564Sdim      ExecutionContextScope *exe_scope = map.GetBestExecutionContextScope();
801309124Sdim
802314564Sdim      size_t byte_size = m_type.GetByteSize(exe_scope);
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(
813314564Sdim          byte_size, byte_align,
814314564Sdim          lldb::ePermissionsReadable | lldb::ePermissionsWritable,
815314564Sdim          IRMemoryMap::eAllocationPolicyMirror, zero_memory, alloc_error);
816314564Sdim      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
892314564Sdim    ConstString name = m_delegate
893314564Sdim                           ? m_delegate->GetName()
894314564Sdim                           : persistent_state->GetNextPersistentVariableName();
895309124Sdim
896314564Sdim    lldb::ExpressionVariableSP ret = persistent_state->CreatePersistentVariable(
897314564Sdim        exe_scope, name, m_type, map.GetByteOrder(), map.GetAddressByteSize());
898309124Sdim
899314564Sdim    if (!ret) {
900314564Sdim      err.SetErrorStringWithFormat("couldn't dematerialize a result variable: "
901314564Sdim                                   "failed to make persistent variable %s",
902314564Sdim                                   name.AsCString());
903314564Sdim      return;
904314564Sdim    }
905309124Sdim
906314564Sdim    lldb::ProcessSP process_sp =
907314564Sdim        map.GetBestExecutionContextScope()->CalculateProcess();
908309124Sdim
909314564Sdim    if (m_delegate) {
910314564Sdim      m_delegate->DidDematerialize(ret);
911314564Sdim    }
912309124Sdim
913314564Sdim    bool can_persist =
914314564Sdim        (m_is_program_reference && process_sp && process_sp->CanJIT() &&
915314564Sdim         !(address >= frame_bottom && address < frame_top));
916254721Semaste
917314564Sdim    if (can_persist && m_keep_in_memory) {
918314564Sdim      ret->m_live_sp = ValueObjectConstResult::Create(exe_scope, m_type, name,
919314564Sdim                                                      address, eAddressTypeLoad,
920314564Sdim                                                      map.GetAddressByteSize());
921314564Sdim    }
922309124Sdim
923314564Sdim    ret->ValueUpdated();
924309124Sdim
925314564Sdim    const size_t pvar_byte_size = ret->GetByteSize();
926314564Sdim    uint8_t *pvar_data = ret->GetValueBytes();
927309124Sdim
928314564Sdim    map.ReadMemory(pvar_data, address, pvar_byte_size, read_error);
929309124Sdim
930314564Sdim    if (!read_error.Success()) {
931314564Sdim      err.SetErrorString(
932314564Sdim          "Couldn't dematerialize a result variable: couldn't read its memory");
933314564Sdim      return;
934314564Sdim    }
935309124Sdim
936314564Sdim    if (!can_persist || !m_keep_in_memory) {
937314564Sdim      ret->m_flags |= ExpressionVariable::EVNeedsAllocation;
938309124Sdim
939314564Sdim      if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
940321369Sdim        Status free_error;
941314564Sdim        map.Free(m_temporary_allocation, free_error);
942314564Sdim      }
943314564Sdim    } else {
944314564Sdim      ret->m_flags |= ExpressionVariable::EVIsLLDBAllocated;
945254721Semaste    }
946309124Sdim
947314564Sdim    m_temporary_allocation = LLDB_INVALID_ADDRESS;
948314564Sdim    m_temporary_allocation_size = 0;
949314564Sdim  }
950309124Sdim
951314564Sdim  void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
952314564Sdim                 Log *log) override {
953314564Sdim    StreamString dump_stream;
954254721Semaste
955314564Sdim    const lldb::addr_t load_addr = process_address + m_offset;
956309124Sdim
957314564Sdim    dump_stream.Printf("0x%" PRIx64 ": EntityResultVariable\n", load_addr);
958309124Sdim
959321369Sdim    Status err;
960309124Sdim
961314564Sdim    lldb::addr_t ptr = LLDB_INVALID_ADDRESS;
962309124Sdim
963314564Sdim    {
964314564Sdim      dump_stream.Printf("Pointer:\n");
965309124Sdim
966314564Sdim      DataBufferHeap data(m_size, 0);
967309124Sdim
968314564Sdim      map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
969309124Sdim
970314564Sdim      if (!err.Success()) {
971314564Sdim        dump_stream.Printf("  <could not be read>\n");
972314564Sdim      } else {
973314564Sdim        DataExtractor extractor(data.GetBytes(), data.GetByteSize(),
974314564Sdim                                map.GetByteOrder(), map.GetAddressByteSize());
975309124Sdim
976321369Sdim        DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
977321369Sdim                     load_addr);
978309124Sdim
979314564Sdim        lldb::offset_t offset;
980309124Sdim
981314564Sdim        ptr = extractor.GetPointer(&offset);
982309124Sdim
983314564Sdim        dump_stream.PutChar('\n');
984314564Sdim      }
985314564Sdim    }
986309124Sdim
987314564Sdim    if (m_temporary_allocation == LLDB_INVALID_ADDRESS) {
988314564Sdim      dump_stream.Printf("Points to process memory:\n");
989314564Sdim    } else {
990314564Sdim      dump_stream.Printf("Temporary allocation:\n");
991314564Sdim    }
992309124Sdim
993314564Sdim    if (ptr == LLDB_INVALID_ADDRESS) {
994314564Sdim      dump_stream.Printf("  <could not be be found>\n");
995314564Sdim    } else {
996314564Sdim      DataBufferHeap data(m_temporary_allocation_size, 0);
997309124Sdim
998314564Sdim      map.ReadMemory(data.GetBytes(), m_temporary_allocation,
999314564Sdim                     m_temporary_allocation_size, err);
1000309124Sdim
1001314564Sdim      if (!err.Success()) {
1002314564Sdim        dump_stream.Printf("  <could not be read>\n");
1003314564Sdim      } else {
1004321369Sdim        DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
1005321369Sdim                     load_addr);
1006309124Sdim
1007314564Sdim        dump_stream.PutChar('\n');
1008314564Sdim      }
1009254721Semaste    }
1010309124Sdim
1011314564Sdim    log->PutString(dump_stream.GetString());
1012314564Sdim  }
1013309124Sdim
1014314564Sdim  void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {
1015314564Sdim    if (!m_keep_in_memory && m_temporary_allocation != LLDB_INVALID_ADDRESS) {
1016321369Sdim      Status free_error;
1017309124Sdim
1018314564Sdim      map.Free(m_temporary_allocation, free_error);
1019254721Semaste    }
1020296417Sdim
1021314564Sdim    m_temporary_allocation = LLDB_INVALID_ADDRESS;
1022314564Sdim    m_temporary_allocation_size = 0;
1023314564Sdim  }
1024314564Sdim
1025254721Semasteprivate:
1026314564Sdim  CompilerType m_type;
1027314564Sdim  bool m_is_program_reference;
1028314564Sdim  bool m_keep_in_memory;
1029309124Sdim
1030314564Sdim  lldb::addr_t m_temporary_allocation;
1031314564Sdim  size_t m_temporary_allocation_size;
1032314564Sdim  Materializer::PersistentVariableDelegate *m_delegate;
1033254721Semaste};
1034254721Semaste
1035314564Sdimuint32_t Materializer::AddResultVariable(const CompilerType &type,
1036314564Sdim                                         bool is_program_reference,
1037314564Sdim                                         bool keep_in_memory,
1038314564Sdim                                         PersistentVariableDelegate *delegate,
1039321369Sdim                                         Status &err) {
1040314564Sdim  EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
1041314564Sdim  iter->reset(new EntityResultVariable(type, is_program_reference,
1042314564Sdim                                       keep_in_memory, delegate));
1043314564Sdim  uint32_t ret = AddStructMember(**iter);
1044314564Sdim  (*iter)->SetOffset(ret);
1045314564Sdim  return ret;
1046254721Semaste}
1047254721Semaste
1048314564Sdimclass EntitySymbol : public Materializer::Entity {
1049254721Semastepublic:
1050314564Sdim  EntitySymbol(const Symbol &symbol) : Entity(), m_symbol(symbol) {
1051314564Sdim    // Hard-coding to maximum size of a symbol
1052314564Sdim    m_size = 8;
1053314564Sdim    m_alignment = 8;
1054314564Sdim  }
1055309124Sdim
1056314564Sdim  void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1057321369Sdim                   lldb::addr_t process_address, Status &err) override {
1058314564Sdim    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
1059254721Semaste
1060314564Sdim    const lldb::addr_t load_addr = process_address + m_offset;
1061254721Semaste
1062314564Sdim    if (log) {
1063314564Sdim      log->Printf("EntitySymbol::Materialize [address = 0x%" PRIx64
1064314564Sdim                  ", m_symbol = %s]",
1065314564Sdim                  (uint64_t)load_addr, m_symbol.GetName().AsCString());
1066314564Sdim    }
1067309124Sdim
1068314564Sdim    const Address sym_address = m_symbol.GetAddress();
1069254721Semaste
1070314564Sdim    ExecutionContextScope *exe_scope = map.GetBestExecutionContextScope();
1071309124Sdim
1072314564Sdim    lldb::TargetSP target_sp;
1073309124Sdim
1074314564Sdim    if (exe_scope)
1075314564Sdim      target_sp = map.GetBestExecutionContextScope()->CalculateTarget();
1076309124Sdim
1077314564Sdim    if (!target_sp) {
1078314564Sdim      err.SetErrorStringWithFormat(
1079314564Sdim          "couldn't resolve symbol %s because there is no target",
1080314564Sdim          m_symbol.GetName().AsCString());
1081314564Sdim      return;
1082314564Sdim    }
1083309124Sdim
1084314564Sdim    lldb::addr_t resolved_address = sym_address.GetLoadAddress(target_sp.get());
1085309124Sdim
1086314564Sdim    if (resolved_address == LLDB_INVALID_ADDRESS)
1087314564Sdim      resolved_address = sym_address.GetFileAddress();
1088309124Sdim
1089321369Sdim    Status pointer_write_error;
1090309124Sdim
1091314564Sdim    map.WritePointerToMemory(load_addr, resolved_address, pointer_write_error);
1092309124Sdim
1093314564Sdim    if (!pointer_write_error.Success()) {
1094314564Sdim      err.SetErrorStringWithFormat(
1095314564Sdim          "couldn't write the address of symbol %s: %s",
1096314564Sdim          m_symbol.GetName().AsCString(), pointer_write_error.AsCString());
1097314564Sdim      return;
1098254721Semaste    }
1099314564Sdim  }
1100309124Sdim
1101314564Sdim  void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1102314564Sdim                     lldb::addr_t process_address, lldb::addr_t frame_top,
1103321369Sdim                     lldb::addr_t frame_bottom, Status &err) override {
1104314564Sdim    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
1105254721Semaste
1106314564Sdim    const lldb::addr_t load_addr = process_address + m_offset;
1107254721Semaste
1108314564Sdim    if (log) {
1109314564Sdim      log->Printf("EntitySymbol::Dematerialize [address = 0x%" PRIx64
1110314564Sdim                  ", m_symbol = %s]",
1111314564Sdim                  (uint64_t)load_addr, m_symbol.GetName().AsCString());
1112254721Semaste    }
1113309124Sdim
1114314564Sdim    // no work needs to be done
1115314564Sdim  }
1116309124Sdim
1117314564Sdim  void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
1118314564Sdim                 Log *log) override {
1119314564Sdim    StreamString dump_stream;
1120309124Sdim
1121321369Sdim    Status err;
1122254721Semaste
1123314564Sdim    const lldb::addr_t load_addr = process_address + m_offset;
1124309124Sdim
1125314564Sdim    dump_stream.Printf("0x%" PRIx64 ": EntitySymbol (%s)\n", load_addr,
1126314564Sdim                       m_symbol.GetName().AsCString());
1127309124Sdim
1128314564Sdim    {
1129314564Sdim      dump_stream.Printf("Pointer:\n");
1130309124Sdim
1131314564Sdim      DataBufferHeap data(m_size, 0);
1132309124Sdim
1133314564Sdim      map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
1134309124Sdim
1135314564Sdim      if (!err.Success()) {
1136314564Sdim        dump_stream.Printf("  <could not be read>\n");
1137314564Sdim      } else {
1138321369Sdim        DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
1139321369Sdim                     load_addr);
1140309124Sdim
1141314564Sdim        dump_stream.PutChar('\n');
1142314564Sdim      }
1143254721Semaste    }
1144309124Sdim
1145314564Sdim    log->PutString(dump_stream.GetString());
1146314564Sdim  }
1147296417Sdim
1148314564Sdim  void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {}
1149314564Sdim
1150254721Semasteprivate:
1151314564Sdim  Symbol m_symbol;
1152254721Semaste};
1153254721Semaste
1154321369Sdimuint32_t Materializer::AddSymbol(const Symbol &symbol_sp, Status &err) {
1155314564Sdim  EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
1156314564Sdim  iter->reset(new EntitySymbol(symbol_sp));
1157314564Sdim  uint32_t ret = AddStructMember(**iter);
1158314564Sdim  (*iter)->SetOffset(ret);
1159314564Sdim  return ret;
1160254721Semaste}
1161254721Semaste
1162314564Sdimclass EntityRegister : public Materializer::Entity {
1163254721Semastepublic:
1164314564Sdim  EntityRegister(const RegisterInfo &register_info)
1165314564Sdim      : Entity(), m_register_info(register_info) {
1166314564Sdim    // Hard-coding alignment conservatively
1167314564Sdim    m_size = m_register_info.byte_size;
1168314564Sdim    m_alignment = m_register_info.byte_size;
1169314564Sdim  }
1170314564Sdim
1171314564Sdim  void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1172321369Sdim                   lldb::addr_t process_address, Status &err) override {
1173314564Sdim    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
1174314564Sdim
1175314564Sdim    const lldb::addr_t load_addr = process_address + m_offset;
1176314564Sdim
1177314564Sdim    if (log) {
1178314564Sdim      log->Printf("EntityRegister::Materialize [address = 0x%" PRIx64
1179314564Sdim                  ", m_register_info = %s]",
1180314564Sdim                  (uint64_t)load_addr, m_register_info.name);
1181254721Semaste    }
1182309124Sdim
1183314564Sdim    RegisterValue reg_value;
1184309124Sdim
1185314564Sdim    if (!frame_sp.get()) {
1186314564Sdim      err.SetErrorStringWithFormat(
1187314564Sdim          "couldn't materialize register %s without a stack frame",
1188314564Sdim          m_register_info.name);
1189314564Sdim      return;
1190314564Sdim    }
1191254721Semaste
1192314564Sdim    lldb::RegisterContextSP reg_context_sp = frame_sp->GetRegisterContext();
1193254721Semaste
1194314564Sdim    if (!reg_context_sp->ReadRegister(&m_register_info, reg_value)) {
1195314564Sdim      err.SetErrorStringWithFormat("couldn't read the value of register %s",
1196314564Sdim                                   m_register_info.name);
1197314564Sdim      return;
1198314564Sdim    }
1199309124Sdim
1200314564Sdim    DataExtractor register_data;
1201309124Sdim
1202314564Sdim    if (!reg_value.GetData(register_data)) {
1203314564Sdim      err.SetErrorStringWithFormat("couldn't get the data for register %s",
1204314564Sdim                                   m_register_info.name);
1205314564Sdim      return;
1206314564Sdim    }
1207309124Sdim
1208314564Sdim    if (register_data.GetByteSize() != m_register_info.byte_size) {
1209314564Sdim      err.SetErrorStringWithFormat(
1210314564Sdim          "data for register %s had size %llu but we expected %llu",
1211314564Sdim          m_register_info.name, (unsigned long long)register_data.GetByteSize(),
1212314564Sdim          (unsigned long long)m_register_info.byte_size);
1213314564Sdim      return;
1214314564Sdim    }
1215309124Sdim
1216314564Sdim    m_register_contents.reset(new DataBufferHeap(register_data.GetDataStart(),
1217314564Sdim                                                 register_data.GetByteSize()));
1218309124Sdim
1219321369Sdim    Status write_error;
1220309124Sdim
1221314564Sdim    map.WriteMemory(load_addr, register_data.GetDataStart(),
1222314564Sdim                    register_data.GetByteSize(), write_error);
1223309124Sdim
1224314564Sdim    if (!write_error.Success()) {
1225314564Sdim      err.SetErrorStringWithFormat(
1226314564Sdim          "couldn't write the contents of register %s: %s",
1227314564Sdim          m_register_info.name, write_error.AsCString());
1228314564Sdim      return;
1229254721Semaste    }
1230314564Sdim  }
1231309124Sdim
1232314564Sdim  void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1233314564Sdim                     lldb::addr_t process_address, lldb::addr_t frame_top,
1234321369Sdim                     lldb::addr_t frame_bottom, Status &err) override {
1235314564Sdim    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
1236309124Sdim
1237314564Sdim    const lldb::addr_t load_addr = process_address + m_offset;
1238254721Semaste
1239314564Sdim    if (log) {
1240314564Sdim      log->Printf("EntityRegister::Dematerialize [address = 0x%" PRIx64
1241314564Sdim                  ", m_register_info = %s]",
1242314564Sdim                  (uint64_t)load_addr, m_register_info.name);
1243314564Sdim    }
1244309124Sdim
1245321369Sdim    Status extract_error;
1246309124Sdim
1247314564Sdim    DataExtractor register_data;
1248309124Sdim
1249314564Sdim    if (!frame_sp.get()) {
1250314564Sdim      err.SetErrorStringWithFormat(
1251314564Sdim          "couldn't dematerialize register %s without a stack frame",
1252314564Sdim          m_register_info.name);
1253314564Sdim      return;
1254314564Sdim    }
1255309124Sdim
1256314564Sdim    lldb::RegisterContextSP reg_context_sp = frame_sp->GetRegisterContext();
1257309124Sdim
1258314564Sdim    map.GetMemoryData(register_data, load_addr, m_register_info.byte_size,
1259314564Sdim                      extract_error);
1260309124Sdim
1261314564Sdim    if (!extract_error.Success()) {
1262314564Sdim      err.SetErrorStringWithFormat("couldn't get the data for register %s: %s",
1263314564Sdim                                   m_register_info.name,
1264314564Sdim                                   extract_error.AsCString());
1265314564Sdim      return;
1266314564Sdim    }
1267309124Sdim
1268314564Sdim    if (!memcmp(register_data.GetDataStart(), m_register_contents->GetBytes(),
1269314564Sdim                register_data.GetByteSize())) {
1270314564Sdim      // No write required, and in particular we avoid errors if the register
1271314564Sdim      // wasn't writable
1272309124Sdim
1273314564Sdim      m_register_contents.reset();
1274314564Sdim      return;
1275314564Sdim    }
1276309124Sdim
1277314564Sdim    m_register_contents.reset();
1278309124Sdim
1279314564Sdim    RegisterValue register_value(
1280314564Sdim        const_cast<uint8_t *>(register_data.GetDataStart()),
1281314564Sdim        register_data.GetByteSize(), register_data.GetByteOrder());
1282309124Sdim
1283314564Sdim    if (!reg_context_sp->WriteRegister(&m_register_info, register_value)) {
1284314564Sdim      err.SetErrorStringWithFormat("couldn't write the value of register %s",
1285314564Sdim                                   m_register_info.name);
1286314564Sdim      return;
1287254721Semaste    }
1288314564Sdim  }
1289309124Sdim
1290314564Sdim  void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
1291314564Sdim                 Log *log) override {
1292314564Sdim    StreamString dump_stream;
1293309124Sdim
1294321369Sdim    Status err;
1295309124Sdim
1296314564Sdim    const lldb::addr_t load_addr = process_address + m_offset;
1297254721Semaste
1298314564Sdim    dump_stream.Printf("0x%" PRIx64 ": EntityRegister (%s)\n", load_addr,
1299314564Sdim                       m_register_info.name);
1300309124Sdim
1301314564Sdim    {
1302314564Sdim      dump_stream.Printf("Value:\n");
1303309124Sdim
1304314564Sdim      DataBufferHeap data(m_size, 0);
1305309124Sdim
1306314564Sdim      map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
1307309124Sdim
1308314564Sdim      if (!err.Success()) {
1309314564Sdim        dump_stream.Printf("  <could not be read>\n");
1310314564Sdim      } else {
1311321369Sdim        DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
1312321369Sdim                     load_addr);
1313309124Sdim
1314314564Sdim        dump_stream.PutChar('\n');
1315314564Sdim      }
1316314564Sdim    }
1317309124Sdim
1318314564Sdim    log->PutString(dump_stream.GetString());
1319314564Sdim  }
1320309124Sdim
1321314564Sdim  void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {}
1322309124Sdim
1323254721Semasteprivate:
1324314564Sdim  RegisterInfo m_register_info;
1325314564Sdim  lldb::DataBufferSP m_register_contents;
1326254721Semaste};
1327254721Semaste
1328314564Sdimuint32_t Materializer::AddRegister(const RegisterInfo &register_info,
1329321369Sdim                                   Status &err) {
1330314564Sdim  EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
1331314564Sdim  iter->reset(new EntityRegister(register_info));
1332314564Sdim  uint32_t ret = AddStructMember(**iter);
1333314564Sdim  (*iter)->SetOffset(ret);
1334314564Sdim  return ret;
1335254721Semaste}
1336254721Semaste
1337314564SdimMaterializer::Materializer()
1338314564Sdim    : m_dematerializer_wp(), m_current_offset(0), m_struct_alignment(8) {}
1339254721Semaste
1340314564SdimMaterializer::~Materializer() {
1341314564Sdim  DematerializerSP dematerializer_sp = m_dematerializer_wp.lock();
1342309124Sdim
1343314564Sdim  if (dematerializer_sp)
1344314564Sdim    dematerializer_sp->Wipe();
1345254721Semaste}
1346254721Semaste
1347254721SemasteMaterializer::DematerializerSP
1348314564SdimMaterializer::Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1349321369Sdim                          lldb::addr_t process_address, Status &error) {
1350314564Sdim  ExecutionContextScope *exe_scope = frame_sp.get();
1351276479Sdim
1352314564Sdim  if (!exe_scope)
1353314564Sdim    exe_scope = map.GetBestExecutionContextScope();
1354276479Sdim
1355314564Sdim  DematerializerSP dematerializer_sp = m_dematerializer_wp.lock();
1356276479Sdim
1357314564Sdim  if (dematerializer_sp) {
1358314564Sdim    error.SetErrorToGenericError();
1359314564Sdim    error.SetErrorString("Couldn't materialize: already materialized");
1360314564Sdim  }
1361276479Sdim
1362314564Sdim  DematerializerSP ret(
1363314564Sdim      new Dematerializer(*this, frame_sp, map, process_address));
1364276479Sdim
1365314564Sdim  if (!exe_scope) {
1366314564Sdim    error.SetErrorToGenericError();
1367314564Sdim    error.SetErrorString("Couldn't materialize: target doesn't exist");
1368314564Sdim  }
1369276479Sdim
1370314564Sdim  for (EntityUP &entity_up : m_entities) {
1371314564Sdim    entity_up->Materialize(frame_sp, map, process_address, error);
1372276479Sdim
1373314564Sdim    if (!error.Success())
1374314564Sdim      return DematerializerSP();
1375314564Sdim  }
1376276479Sdim
1377314564Sdim  if (Log *log =
1378314564Sdim          lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)) {
1379314564Sdim    log->Printf(
1380314564Sdim        "Materializer::Materialize (frame_sp = %p, process_address = 0x%" PRIx64
1381314564Sdim        ") materialized:",
1382314564Sdim        static_cast<void *>(frame_sp.get()), process_address);
1383314564Sdim    for (EntityUP &entity_up : m_entities)
1384314564Sdim      entity_up->DumpToLog(map, process_address, log);
1385314564Sdim  }
1386276479Sdim
1387314564Sdim  m_dematerializer_wp = ret;
1388276479Sdim
1389314564Sdim  return ret;
1390254721Semaste}
1391254721Semaste
1392321369Sdimvoid Materializer::Dematerializer::Dematerialize(Status &error,
1393314564Sdim                                                 lldb::addr_t frame_bottom,
1394314564Sdim                                                 lldb::addr_t frame_top) {
1395314564Sdim  lldb::StackFrameSP frame_sp;
1396254721Semaste
1397314564Sdim  lldb::ThreadSP thread_sp = m_thread_wp.lock();
1398314564Sdim  if (thread_sp)
1399314564Sdim    frame_sp = thread_sp->GetFrameWithStackID(m_stack_id);
1400276479Sdim
1401314564Sdim  ExecutionContextScope *exe_scope = m_map->GetBestExecutionContextScope();
1402276479Sdim
1403314564Sdim  if (!IsValid()) {
1404314564Sdim    error.SetErrorToGenericError();
1405314564Sdim    error.SetErrorString("Couldn't dematerialize: invalid dematerializer");
1406314564Sdim  }
1407276479Sdim
1408314564Sdim  if (!exe_scope) {
1409314564Sdim    error.SetErrorToGenericError();
1410314564Sdim    error.SetErrorString("Couldn't dematerialize: target is gone");
1411314564Sdim  } else {
1412314564Sdim    if (Log *log =
1413314564Sdim            lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)) {
1414314564Sdim      log->Printf("Materializer::Dematerialize (frame_sp = %p, process_address "
1415314564Sdim                  "= 0x%" PRIx64 ") about to dematerialize:",
1416314564Sdim                  static_cast<void *>(frame_sp.get()), m_process_address);
1417314564Sdim      for (EntityUP &entity_up : m_materializer->m_entities)
1418314564Sdim        entity_up->DumpToLog(*m_map, m_process_address, log);
1419254721Semaste    }
1420276479Sdim
1421314564Sdim    for (EntityUP &entity_up : m_materializer->m_entities) {
1422314564Sdim      entity_up->Dematerialize(frame_sp, *m_map, m_process_address, frame_top,
1423314564Sdim                               frame_bottom, error);
1424276479Sdim
1425314564Sdim      if (!error.Success())
1426314564Sdim        break;
1427254721Semaste    }
1428314564Sdim  }
1429276479Sdim
1430314564Sdim  Wipe();
1431254721Semaste}
1432254721Semaste
1433314564Sdimvoid Materializer::Dematerializer::Wipe() {
1434314564Sdim  if (!IsValid())
1435314564Sdim    return;
1436309124Sdim
1437314564Sdim  for (EntityUP &entity_up : m_materializer->m_entities) {
1438314564Sdim    entity_up->Wipe(*m_map, m_process_address);
1439314564Sdim  }
1440254721Semaste
1441314564Sdim  m_materializer = nullptr;
1442314564Sdim  m_map = nullptr;
1443314564Sdim  m_process_address = LLDB_INVALID_ADDRESS;
1444254721Semaste}
1445296417Sdim
1446314564SdimMaterializer::PersistentVariableDelegate::~PersistentVariableDelegate() =
1447314564Sdim    default;
1448