1254721Semaste//===-- Materializer.cpp ----------------------------------------*- C++ -*-===//
2254721Semaste//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6254721Semaste//
7254721Semaste//===----------------------------------------------------------------------===//
8254721Semaste
9314564Sdim#include "lldb/Expression/Materializer.h"
10321369Sdim#include "lldb/Core/DumpDataExtractor.h"
11254721Semaste#include "lldb/Core/ValueObjectConstResult.h"
12254721Semaste#include "lldb/Core/ValueObjectVariable.h"
13296417Sdim#include "lldb/Expression/ExpressionVariable.h"
14254721Semaste#include "lldb/Symbol/Symbol.h"
15254721Semaste#include "lldb/Symbol/Type.h"
16254721Semaste#include "lldb/Symbol/Variable.h"
17254721Semaste#include "lldb/Target/ExecutionContext.h"
18254721Semaste#include "lldb/Target/RegisterContext.h"
19254721Semaste#include "lldb/Target/StackFrame.h"
20254721Semaste#include "lldb/Target/Target.h"
21254721Semaste#include "lldb/Target/Thread.h"
22321369Sdim#include "lldb/Utility/Log.h"
23344779Sdim#include "lldb/Utility/RegisterValue.h"
24254721Semaste
25353358Sdim#include <memory>
26353358Sdim
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
48314564Sdimclass EntityPersistentVariable : public Materializer::Entity {
49254721Semastepublic:
50314564Sdim  EntityPersistentVariable(lldb::ExpressionVariableSP &persistent_variable_sp,
51314564Sdim                           Materializer::PersistentVariableDelegate *delegate)
52314564Sdim      : Entity(), m_persistent_variable_sp(persistent_variable_sp),
53314564Sdim        m_delegate(delegate) {
54314564Sdim    // Hard-coding to maximum size of a pointer since persistent variables are
55314564Sdim    // materialized by reference
56314564Sdim    m_size = 8;
57314564Sdim    m_alignment = 8;
58314564Sdim  }
59309124Sdim
60321369Sdim  void MakeAllocation(IRMemoryMap &map, Status &err) {
61314564Sdim    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
62254721Semaste
63341825Sdim    // Allocate a spare memory area to store the persistent variable's
64341825Sdim    // contents.
65309124Sdim
66321369Sdim    Status allocate_error;
67314564Sdim    const bool zero_memory = false;
68309124Sdim
69314564Sdim    lldb::addr_t mem = map.Malloc(
70314564Sdim        m_persistent_variable_sp->GetByteSize(), 8,
71314564Sdim        lldb::ePermissionsReadable | lldb::ePermissionsWritable,
72314564Sdim        IRMemoryMap::eAllocationPolicyMirror, zero_memory, allocate_error);
73309124Sdim
74314564Sdim    if (!allocate_error.Success()) {
75314564Sdim      err.SetErrorStringWithFormat(
76314564Sdim          "couldn't allocate a memory area to store %s: %s",
77314564Sdim          m_persistent_variable_sp->GetName().GetCString(),
78314564Sdim          allocate_error.AsCString());
79314564Sdim      return;
80314564Sdim    }
81309124Sdim
82360784Sdim    LLDB_LOGF(log, "Allocated %s (0x%" PRIx64 ") successfully",
83360784Sdim              m_persistent_variable_sp->GetName().GetCString(), mem);
84309124Sdim
85314564Sdim    // Put the location of the spare memory into the live data of the
86314564Sdim    // ValueObject.
87309124Sdim
88314564Sdim    m_persistent_variable_sp->m_live_sp = ValueObjectConstResult::Create(
89314564Sdim        map.GetBestExecutionContextScope(),
90314564Sdim        m_persistent_variable_sp->GetCompilerType(),
91314564Sdim        m_persistent_variable_sp->GetName(), mem, eAddressTypeLoad,
92314564Sdim        map.GetAddressByteSize());
93309124Sdim
94314564Sdim    // Clear the flag if the variable will never be deallocated.
95309124Sdim
96314564Sdim    if (m_persistent_variable_sp->m_flags &
97314564Sdim        ExpressionVariable::EVKeepInTarget) {
98321369Sdim      Status leak_error;
99314564Sdim      map.Leak(mem, leak_error);
100314564Sdim      m_persistent_variable_sp->m_flags &=
101314564Sdim          ~ExpressionVariable::EVNeedsAllocation;
102314564Sdim    }
103309124Sdim
104314564Sdim    // Write the contents of the variable to the area.
105309124Sdim
106321369Sdim    Status write_error;
107309124Sdim
108314564Sdim    map.WriteMemory(mem, m_persistent_variable_sp->GetValueBytes(),
109314564Sdim                    m_persistent_variable_sp->GetByteSize(), write_error);
110309124Sdim
111314564Sdim    if (!write_error.Success()) {
112314564Sdim      err.SetErrorStringWithFormat(
113314564Sdim          "couldn't write %s to the target: %s",
114314564Sdim          m_persistent_variable_sp->GetName().AsCString(),
115314564Sdim          write_error.AsCString());
116314564Sdim      return;
117254721Semaste    }
118314564Sdim  }
119309124Sdim
120321369Sdim  void DestroyAllocation(IRMemoryMap &map, Status &err) {
121321369Sdim    Status deallocate_error;
122309124Sdim
123314564Sdim    map.Free((lldb::addr_t)m_persistent_variable_sp->m_live_sp->GetValue()
124314564Sdim                 .GetScalar()
125314564Sdim                 .ULongLong(),
126314564Sdim             deallocate_error);
127309124Sdim
128314564Sdim    m_persistent_variable_sp->m_live_sp.reset();
129309124Sdim
130314564Sdim    if (!deallocate_error.Success()) {
131314564Sdim      err.SetErrorStringWithFormat(
132314564Sdim          "couldn't deallocate memory for %s: %s",
133314564Sdim          m_persistent_variable_sp->GetName().GetCString(),
134314564Sdim          deallocate_error.AsCString());
135254721Semaste    }
136314564Sdim  }
137309124Sdim
138314564Sdim  void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
139321369Sdim                   lldb::addr_t process_address, Status &err) override {
140314564Sdim    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
141254721Semaste
142314564Sdim    const lldb::addr_t load_addr = process_address + m_offset;
143309124Sdim
144314564Sdim    if (log) {
145360784Sdim      LLDB_LOGF(log,
146360784Sdim                "EntityPersistentVariable::Materialize [address = 0x%" PRIx64
147360784Sdim                ", m_name = %s, m_flags = 0x%hx]",
148360784Sdim                (uint64_t)load_addr,
149360784Sdim                m_persistent_variable_sp->GetName().AsCString(),
150360784Sdim                m_persistent_variable_sp->m_flags);
151314564Sdim    }
152309124Sdim
153314564Sdim    if (m_persistent_variable_sp->m_flags &
154314564Sdim        ExpressionVariable::EVNeedsAllocation) {
155314564Sdim      MakeAllocation(map, err);
156314564Sdim      m_persistent_variable_sp->m_flags |=
157314564Sdim          ExpressionVariable::EVIsLLDBAllocated;
158309124Sdim
159314564Sdim      if (!err.Success())
160314564Sdim        return;
161314564Sdim    }
162309124Sdim
163314564Sdim    if ((m_persistent_variable_sp->m_flags &
164314564Sdim             ExpressionVariable::EVIsProgramReference &&
165314564Sdim         m_persistent_variable_sp->m_live_sp) ||
166314564Sdim        m_persistent_variable_sp->m_flags &
167314564Sdim            ExpressionVariable::EVIsLLDBAllocated) {
168321369Sdim      Status write_error;
169309124Sdim
170314564Sdim      map.WriteScalarToMemory(
171314564Sdim          load_addr,
172314564Sdim          m_persistent_variable_sp->m_live_sp->GetValue().GetScalar(),
173314564Sdim          map.GetAddressByteSize(), write_error);
174309124Sdim
175314564Sdim      if (!write_error.Success()) {
176314564Sdim        err.SetErrorStringWithFormat(
177314564Sdim            "couldn't write the location of %s to memory: %s",
178314564Sdim            m_persistent_variable_sp->GetName().AsCString(),
179314564Sdim            write_error.AsCString());
180314564Sdim      }
181314564Sdim    } else {
182314564Sdim      err.SetErrorStringWithFormat(
183314564Sdim          "no materialization happened for persistent variable %s",
184314564Sdim          m_persistent_variable_sp->GetName().AsCString());
185314564Sdim      return;
186254721Semaste    }
187314564Sdim  }
188309124Sdim
189314564Sdim  void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
190314564Sdim                     lldb::addr_t process_address, lldb::addr_t frame_top,
191321369Sdim                     lldb::addr_t frame_bottom, Status &err) override {
192314564Sdim    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
193309124Sdim
194314564Sdim    const lldb::addr_t load_addr = process_address + m_offset;
195254721Semaste
196314564Sdim    if (log) {
197360784Sdim      LLDB_LOGF(log,
198360784Sdim                "EntityPersistentVariable::Dematerialize [address = 0x%" PRIx64
199360784Sdim                ", m_name = %s, m_flags = 0x%hx]",
200360784Sdim                (uint64_t)process_address + m_offset,
201360784Sdim                m_persistent_variable_sp->GetName().AsCString(),
202360784Sdim                m_persistent_variable_sp->m_flags);
203314564Sdim    }
204309124Sdim
205314564Sdim    if (m_delegate) {
206314564Sdim      m_delegate->DidDematerialize(m_persistent_variable_sp);
207314564Sdim    }
208296417Sdim
209314564Sdim    if ((m_persistent_variable_sp->m_flags &
210314564Sdim         ExpressionVariable::EVIsLLDBAllocated) ||
211314564Sdim        (m_persistent_variable_sp->m_flags &
212314564Sdim         ExpressionVariable::EVIsProgramReference)) {
213314564Sdim      if (m_persistent_variable_sp->m_flags &
214314564Sdim              ExpressionVariable::EVIsProgramReference &&
215314564Sdim          !m_persistent_variable_sp->m_live_sp) {
216314564Sdim        // If the reference comes from the program, then the
217341825Sdim        // ClangExpressionVariable's live variable data hasn't been set up yet.
218341825Sdim        // Do this now.
219309124Sdim
220314564Sdim        lldb::addr_t location;
221321369Sdim        Status read_error;
222309124Sdim
223314564Sdim        map.ReadPointerFromMemory(&location, load_addr, read_error);
224309124Sdim
225314564Sdim        if (!read_error.Success()) {
226314564Sdim          err.SetErrorStringWithFormat(
227314564Sdim              "couldn't read the address of program-allocated variable %s: %s",
228314564Sdim              m_persistent_variable_sp->GetName().GetCString(),
229314564Sdim              read_error.AsCString());
230314564Sdim          return;
231314564Sdim        }
232309124Sdim
233314564Sdim        m_persistent_variable_sp->m_live_sp = ValueObjectConstResult::Create(
234314564Sdim            map.GetBestExecutionContextScope(),
235314564Sdim            m_persistent_variable_sp.get()->GetCompilerType(),
236314564Sdim            m_persistent_variable_sp->GetName(), location, eAddressTypeLoad,
237314564Sdim            m_persistent_variable_sp->GetByteSize());
238309124Sdim
239314564Sdim        if (frame_top != LLDB_INVALID_ADDRESS &&
240314564Sdim            frame_bottom != LLDB_INVALID_ADDRESS && location >= frame_bottom &&
241314564Sdim            location <= frame_top) {
242314564Sdim          // If the variable is resident in the stack frame created by the
243341825Sdim          // expression, then it cannot be relied upon to stay around.  We
244341825Sdim          // treat it as needing reallocation.
245314564Sdim          m_persistent_variable_sp->m_flags |=
246314564Sdim              ExpressionVariable::EVIsLLDBAllocated;
247314564Sdim          m_persistent_variable_sp->m_flags |=
248314564Sdim              ExpressionVariable::EVNeedsAllocation;
249314564Sdim          m_persistent_variable_sp->m_flags |=
250314564Sdim              ExpressionVariable::EVNeedsFreezeDry;
251314564Sdim          m_persistent_variable_sp->m_flags &=
252314564Sdim              ~ExpressionVariable::EVIsProgramReference;
253314564Sdim        }
254314564Sdim      }
255309124Sdim
256314564Sdim      lldb::addr_t mem = m_persistent_variable_sp->m_live_sp->GetValue()
257314564Sdim                             .GetScalar()
258314564Sdim                             .ULongLong();
259309124Sdim
260314564Sdim      if (!m_persistent_variable_sp->m_live_sp) {
261314564Sdim        err.SetErrorStringWithFormat(
262314564Sdim            "couldn't find the memory area used to store %s",
263314564Sdim            m_persistent_variable_sp->GetName().GetCString());
264314564Sdim        return;
265314564Sdim      }
266309124Sdim
267314564Sdim      if (m_persistent_variable_sp->m_live_sp->GetValue()
268314564Sdim              .GetValueAddressType() != eAddressTypeLoad) {
269314564Sdim        err.SetErrorStringWithFormat(
270314564Sdim            "the address of the memory area for %s is in an incorrect format",
271314564Sdim            m_persistent_variable_sp->GetName().GetCString());
272314564Sdim        return;
273314564Sdim      }
274309124Sdim
275314564Sdim      if (m_persistent_variable_sp->m_flags &
276314564Sdim              ExpressionVariable::EVNeedsFreezeDry ||
277314564Sdim          m_persistent_variable_sp->m_flags &
278314564Sdim              ExpressionVariable::EVKeepInTarget) {
279360784Sdim        LLDB_LOGF(log, "Dematerializing %s from 0x%" PRIx64 " (size = %llu)",
280360784Sdim                  m_persistent_variable_sp->GetName().GetCString(),
281360784Sdim                  (uint64_t)mem,
282360784Sdim                  (unsigned long long)m_persistent_variable_sp->GetByteSize());
283309124Sdim
284314564Sdim        // Read the contents of the spare memory area
285309124Sdim
286314564Sdim        m_persistent_variable_sp->ValueUpdated();
287309124Sdim
288321369Sdim        Status read_error;
289309124Sdim
290314564Sdim        map.ReadMemory(m_persistent_variable_sp->GetValueBytes(), mem,
291314564Sdim                       m_persistent_variable_sp->GetByteSize(), read_error);
292309124Sdim
293314564Sdim        if (!read_error.Success()) {
294314564Sdim          err.SetErrorStringWithFormat(
295314564Sdim              "couldn't read the contents of %s from memory: %s",
296314564Sdim              m_persistent_variable_sp->GetName().GetCString(),
297314564Sdim              read_error.AsCString());
298314564Sdim          return;
299254721Semaste        }
300309124Sdim
301314564Sdim        m_persistent_variable_sp->m_flags &=
302314564Sdim            ~ExpressionVariable::EVNeedsFreezeDry;
303314564Sdim      }
304314564Sdim    } else {
305314564Sdim      err.SetErrorStringWithFormat(
306314564Sdim          "no dematerialization happened for persistent variable %s",
307314564Sdim          m_persistent_variable_sp->GetName().AsCString());
308314564Sdim      return;
309314564Sdim    }
310309124Sdim
311314564Sdim    lldb::ProcessSP process_sp =
312314564Sdim        map.GetBestExecutionContextScope()->CalculateProcess();
313314564Sdim    if (!process_sp || !process_sp->CanJIT()) {
314314564Sdim      // Allocations are not persistent so persistent variables cannot stay
315314564Sdim      // materialized.
316254721Semaste
317314564Sdim      m_persistent_variable_sp->m_flags |=
318314564Sdim          ExpressionVariable::EVNeedsAllocation;
319314564Sdim
320314564Sdim      DestroyAllocation(map, err);
321314564Sdim      if (!err.Success())
322314564Sdim        return;
323314564Sdim    } else if (m_persistent_variable_sp->m_flags &
324314564Sdim                   ExpressionVariable::EVNeedsAllocation &&
325314564Sdim               !(m_persistent_variable_sp->m_flags &
326314564Sdim                 ExpressionVariable::EVKeepInTarget)) {
327314564Sdim      DestroyAllocation(map, err);
328314564Sdim      if (!err.Success())
329314564Sdim        return;
330254721Semaste    }
331314564Sdim  }
332309124Sdim
333314564Sdim  void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
334314564Sdim                 Log *log) override {
335314564Sdim    StreamString dump_stream;
336309124Sdim
337321369Sdim    Status err;
338309124Sdim
339314564Sdim    const lldb::addr_t load_addr = process_address + m_offset;
340254721Semaste
341314564Sdim    dump_stream.Printf("0x%" PRIx64 ": EntityPersistentVariable (%s)\n",
342314564Sdim                       load_addr,
343314564Sdim                       m_persistent_variable_sp->GetName().AsCString());
344309124Sdim
345314564Sdim    {
346314564Sdim      dump_stream.Printf("Pointer:\n");
347309124Sdim
348314564Sdim      DataBufferHeap data(m_size, 0);
349309124Sdim
350314564Sdim      map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
351309124Sdim
352314564Sdim      if (!err.Success()) {
353314564Sdim        dump_stream.Printf("  <could not be read>\n");
354314564Sdim      } else {
355321369Sdim        DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
356321369Sdim                     load_addr);
357309124Sdim
358314564Sdim        dump_stream.PutChar('\n');
359314564Sdim      }
360314564Sdim    }
361309124Sdim
362314564Sdim    {
363314564Sdim      dump_stream.Printf("Target:\n");
364309124Sdim
365314564Sdim      lldb::addr_t target_address;
366309124Sdim
367314564Sdim      map.ReadPointerFromMemory(&target_address, load_addr, err);
368309124Sdim
369314564Sdim      if (!err.Success()) {
370314564Sdim        dump_stream.Printf("  <could not be read>\n");
371314564Sdim      } else {
372314564Sdim        DataBufferHeap data(m_persistent_variable_sp->GetByteSize(), 0);
373309124Sdim
374314564Sdim        map.ReadMemory(data.GetBytes(), target_address,
375314564Sdim                       m_persistent_variable_sp->GetByteSize(), err);
376309124Sdim
377314564Sdim        if (!err.Success()) {
378314564Sdim          dump_stream.Printf("  <could not be read>\n");
379314564Sdim        } else {
380321369Sdim          DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
381321369Sdim                       target_address);
382309124Sdim
383314564Sdim          dump_stream.PutChar('\n');
384254721Semaste        }
385314564Sdim      }
386254721Semaste    }
387309124Sdim
388314564Sdim    log->PutString(dump_stream.GetString());
389314564Sdim  }
390296417Sdim
391314564Sdim  void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {}
392314564Sdim
393254721Semasteprivate:
394314564Sdim  lldb::ExpressionVariableSP m_persistent_variable_sp;
395314564Sdim  Materializer::PersistentVariableDelegate *m_delegate;
396254721Semaste};
397254721Semaste
398314564Sdimuint32_t Materializer::AddPersistentVariable(
399314564Sdim    lldb::ExpressionVariableSP &persistent_variable_sp,
400321369Sdim    PersistentVariableDelegate *delegate, Status &err) {
401314564Sdim  EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
402314564Sdim  iter->reset(new EntityPersistentVariable(persistent_variable_sp, delegate));
403314564Sdim  uint32_t ret = AddStructMember(**iter);
404314564Sdim  (*iter)->SetOffset(ret);
405314564Sdim  return ret;
406254721Semaste}
407254721Semaste
408314564Sdimclass EntityVariable : public Materializer::Entity {
409254721Semastepublic:
410314564Sdim  EntityVariable(lldb::VariableSP &variable_sp)
411314564Sdim      : Entity(), m_variable_sp(variable_sp), m_is_reference(false),
412254721Semaste        m_temporary_allocation(LLDB_INVALID_ADDRESS),
413314564Sdim        m_temporary_allocation_size(0) {
414314564Sdim    // Hard-coding to maximum size of a pointer since all variables are
415314564Sdim    // materialized by reference
416314564Sdim    m_size = 8;
417314564Sdim    m_alignment = 8;
418314564Sdim    m_is_reference =
419314564Sdim        m_variable_sp->GetType()->GetForwardCompilerType().IsReferenceType();
420314564Sdim  }
421314564Sdim
422314564Sdim  void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
423321369Sdim                   lldb::addr_t process_address, Status &err) override {
424314564Sdim    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
425314564Sdim
426314564Sdim    const lldb::addr_t load_addr = process_address + m_offset;
427314564Sdim    if (log) {
428360784Sdim      LLDB_LOGF(log,
429360784Sdim                "EntityVariable::Materialize [address = 0x%" PRIx64
430360784Sdim                ", m_variable_sp = %s]",
431360784Sdim                (uint64_t)load_addr, m_variable_sp->GetName().AsCString());
432254721Semaste    }
433309124Sdim
434314564Sdim    ExecutionContextScope *scope = frame_sp.get();
435309124Sdim
436314564Sdim    if (!scope)
437314564Sdim      scope = map.GetBestExecutionContextScope();
438309124Sdim
439314564Sdim    lldb::ValueObjectSP valobj_sp =
440314564Sdim        ValueObjectVariable::Create(scope, m_variable_sp);
441309124Sdim
442314564Sdim    if (!valobj_sp) {
443314564Sdim      err.SetErrorStringWithFormat(
444314564Sdim          "couldn't get a value object for variable %s",
445314564Sdim          m_variable_sp->GetName().AsCString());
446314564Sdim      return;
447314564Sdim    }
448309124Sdim
449321369Sdim    Status valobj_error = valobj_sp->GetError();
450309124Sdim
451314564Sdim    if (valobj_error.Fail()) {
452314564Sdim      err.SetErrorStringWithFormat("couldn't get the value of variable %s: %s",
453314564Sdim                                   m_variable_sp->GetName().AsCString(),
454314564Sdim                                   valobj_error.AsCString());
455314564Sdim      return;
456314564Sdim    }
457309124Sdim
458314564Sdim    if (m_is_reference) {
459314564Sdim      DataExtractor valobj_extractor;
460321369Sdim      Status extract_error;
461314564Sdim      valobj_sp->GetData(valobj_extractor, extract_error);
462309124Sdim
463314564Sdim      if (!extract_error.Success()) {
464314564Sdim        err.SetErrorStringWithFormat(
465314564Sdim            "couldn't read contents of reference variable %s: %s",
466314564Sdim            m_variable_sp->GetName().AsCString(), extract_error.AsCString());
467314564Sdim        return;
468314564Sdim      }
469309124Sdim
470314564Sdim      lldb::offset_t offset = 0;
471314564Sdim      lldb::addr_t reference_addr = valobj_extractor.GetAddress(&offset);
472309124Sdim
473321369Sdim      Status write_error;
474314564Sdim      map.WritePointerToMemory(load_addr, reference_addr, write_error);
475309124Sdim
476314564Sdim      if (!write_error.Success()) {
477314564Sdim        err.SetErrorStringWithFormat("couldn't write the contents of reference "
478314564Sdim                                     "variable %s to memory: %s",
479314564Sdim                                     m_variable_sp->GetName().AsCString(),
480314564Sdim                                     write_error.AsCString());
481314564Sdim        return;
482314564Sdim      }
483314564Sdim    } else {
484314564Sdim      AddressType address_type = eAddressTypeInvalid;
485314564Sdim      const bool scalar_is_load_address = false;
486314564Sdim      lldb::addr_t addr_of_valobj =
487314564Sdim          valobj_sp->GetAddressOf(scalar_is_load_address, &address_type);
488314564Sdim      if (addr_of_valobj != LLDB_INVALID_ADDRESS) {
489321369Sdim        Status write_error;
490314564Sdim        map.WritePointerToMemory(load_addr, addr_of_valobj, write_error);
491309124Sdim
492314564Sdim        if (!write_error.Success()) {
493314564Sdim          err.SetErrorStringWithFormat(
494314564Sdim              "couldn't write the address of variable %s to memory: %s",
495314564Sdim              m_variable_sp->GetName().AsCString(), write_error.AsCString());
496314564Sdim          return;
497314564Sdim        }
498314564Sdim      } else {
499314564Sdim        DataExtractor data;
500321369Sdim        Status extract_error;
501314564Sdim        valobj_sp->GetData(data, extract_error);
502314564Sdim        if (!extract_error.Success()) {
503314564Sdim          err.SetErrorStringWithFormat("couldn't get the value of %s: %s",
504314564Sdim                                       m_variable_sp->GetName().AsCString(),
505314564Sdim                                       extract_error.AsCString());
506314564Sdim          return;
507314564Sdim        }
508309124Sdim
509314564Sdim        if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
510314564Sdim          err.SetErrorStringWithFormat(
511314564Sdim              "trying to create a temporary region for %s but one exists",
512314564Sdim              m_variable_sp->GetName().AsCString());
513314564Sdim          return;
514254721Semaste        }
515309124Sdim
516314564Sdim        if (data.GetByteSize() < m_variable_sp->GetType()->GetByteSize()) {
517314564Sdim          if (data.GetByteSize() == 0 &&
518344779Sdim              !m_variable_sp->LocationExpression().IsValid()) {
519314564Sdim            err.SetErrorStringWithFormat("the variable '%s' has no location, "
520314564Sdim                                         "it may have been optimized out",
521314564Sdim                                         m_variable_sp->GetName().AsCString());
522314564Sdim          } else {
523314564Sdim            err.SetErrorStringWithFormat(
524314564Sdim                "size of variable %s (%" PRIu64
525314564Sdim                ") is larger than the ValueObject's size (%" PRIu64 ")",
526314564Sdim                m_variable_sp->GetName().AsCString(),
527353358Sdim                m_variable_sp->GetType()->GetByteSize().getValueOr(0),
528353358Sdim                data.GetByteSize());
529314564Sdim          }
530314564Sdim          return;
531314564Sdim        }
532309124Sdim
533360784Sdim        llvm::Optional<size_t> opt_bit_align =
534360784Sdim            m_variable_sp->GetType()->GetLayoutCompilerType().GetTypeBitAlign(scope);
535360784Sdim        if (!opt_bit_align) {
536360784Sdim          err.SetErrorStringWithFormat("can't get the type alignment for %s",
537360784Sdim                                       m_variable_sp->GetName().AsCString());
538360784Sdim          return;
539360784Sdim        }
540309124Sdim
541360784Sdim        size_t byte_align = (*opt_bit_align + 7) / 8;
542309124Sdim
543321369Sdim        Status alloc_error;
544314564Sdim        const bool zero_memory = false;
545309124Sdim
546314564Sdim        m_temporary_allocation = map.Malloc(
547314564Sdim            data.GetByteSize(), byte_align,
548314564Sdim            lldb::ePermissionsReadable | lldb::ePermissionsWritable,
549314564Sdim            IRMemoryMap::eAllocationPolicyMirror, zero_memory, alloc_error);
550309124Sdim
551314564Sdim        m_temporary_allocation_size = data.GetByteSize();
552296417Sdim
553353358Sdim        m_original_data = std::make_shared<DataBufferHeap>(data.GetDataStart(),
554353358Sdim                                                           data.GetByteSize());
555309124Sdim
556314564Sdim        if (!alloc_error.Success()) {
557314564Sdim          err.SetErrorStringWithFormat(
558314564Sdim              "couldn't allocate a temporary region for %s: %s",
559314564Sdim              m_variable_sp->GetName().AsCString(), alloc_error.AsCString());
560314564Sdim          return;
561314564Sdim        }
562309124Sdim
563321369Sdim        Status write_error;
564309124Sdim
565314564Sdim        map.WriteMemory(m_temporary_allocation, data.GetDataStart(),
566314564Sdim                        data.GetByteSize(), write_error);
567309124Sdim
568314564Sdim        if (!write_error.Success()) {
569314564Sdim          err.SetErrorStringWithFormat(
570314564Sdim              "couldn't write to the temporary region for %s: %s",
571314564Sdim              m_variable_sp->GetName().AsCString(), write_error.AsCString());
572314564Sdim          return;
573314564Sdim        }
574309124Sdim
575321369Sdim        Status pointer_write_error;
576309124Sdim
577314564Sdim        map.WritePointerToMemory(load_addr, m_temporary_allocation,
578314564Sdim                                 pointer_write_error);
579309124Sdim
580314564Sdim        if (!pointer_write_error.Success()) {
581314564Sdim          err.SetErrorStringWithFormat(
582314564Sdim              "couldn't write the address of the temporary region for %s: %s",
583314564Sdim              m_variable_sp->GetName().AsCString(),
584314564Sdim              pointer_write_error.AsCString());
585254721Semaste        }
586314564Sdim      }
587254721Semaste    }
588314564Sdim  }
589309124Sdim
590314564Sdim  void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
591314564Sdim                     lldb::addr_t process_address, lldb::addr_t frame_top,
592321369Sdim                     lldb::addr_t frame_bottom, Status &err) override {
593314564Sdim    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
594254721Semaste
595314564Sdim    const lldb::addr_t load_addr = process_address + m_offset;
596314564Sdim    if (log) {
597360784Sdim      LLDB_LOGF(log,
598360784Sdim                "EntityVariable::Dematerialize [address = 0x%" PRIx64
599360784Sdim                ", m_variable_sp = %s]",
600360784Sdim                (uint64_t)load_addr, m_variable_sp->GetName().AsCString());
601314564Sdim    }
602309124Sdim
603314564Sdim    if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
604314564Sdim      ExecutionContextScope *scope = frame_sp.get();
605309124Sdim
606314564Sdim      if (!scope)
607314564Sdim        scope = map.GetBestExecutionContextScope();
608309124Sdim
609314564Sdim      lldb::ValueObjectSP valobj_sp =
610314564Sdim          ValueObjectVariable::Create(scope, m_variable_sp);
611309124Sdim
612314564Sdim      if (!valobj_sp) {
613314564Sdim        err.SetErrorStringWithFormat(
614314564Sdim            "couldn't get a value object for variable %s",
615314564Sdim            m_variable_sp->GetName().AsCString());
616314564Sdim        return;
617314564Sdim      }
618309124Sdim
619314564Sdim      lldb_private::DataExtractor data;
620309124Sdim
621321369Sdim      Status extract_error;
622309124Sdim
623314564Sdim      map.GetMemoryData(data, m_temporary_allocation, valobj_sp->GetByteSize(),
624314564Sdim                        extract_error);
625309124Sdim
626314564Sdim      if (!extract_error.Success()) {
627314564Sdim        err.SetErrorStringWithFormat("couldn't get the data for variable %s",
628314564Sdim                                     m_variable_sp->GetName().AsCString());
629314564Sdim        return;
630314564Sdim      }
631309124Sdim
632314564Sdim      bool actually_write = true;
633309124Sdim
634314564Sdim      if (m_original_data) {
635314564Sdim        if ((data.GetByteSize() == m_original_data->GetByteSize()) &&
636314564Sdim            !memcmp(m_original_data->GetBytes(), data.GetDataStart(),
637314564Sdim                    data.GetByteSize())) {
638314564Sdim          actually_write = false;
639314564Sdim        }
640314564Sdim      }
641309124Sdim
642321369Sdim      Status set_error;
643309124Sdim
644314564Sdim      if (actually_write) {
645314564Sdim        valobj_sp->SetData(data, set_error);
646309124Sdim
647314564Sdim        if (!set_error.Success()) {
648314564Sdim          err.SetErrorStringWithFormat(
649314564Sdim              "couldn't write the new contents of %s back into the variable",
650314564Sdim              m_variable_sp->GetName().AsCString());
651314564Sdim          return;
652314564Sdim        }
653314564Sdim      }
654309124Sdim
655321369Sdim      Status free_error;
656309124Sdim
657314564Sdim      map.Free(m_temporary_allocation, free_error);
658309124Sdim
659314564Sdim      if (!free_error.Success()) {
660314564Sdim        err.SetErrorStringWithFormat(
661314564Sdim            "couldn't free the temporary region for %s: %s",
662314564Sdim            m_variable_sp->GetName().AsCString(), free_error.AsCString());
663314564Sdim        return;
664314564Sdim      }
665309124Sdim
666314564Sdim      m_original_data.reset();
667314564Sdim      m_temporary_allocation = LLDB_INVALID_ADDRESS;
668314564Sdim      m_temporary_allocation_size = 0;
669254721Semaste    }
670314564Sdim  }
671309124Sdim
672314564Sdim  void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
673314564Sdim                 Log *log) override {
674314564Sdim    StreamString dump_stream;
675254721Semaste
676314564Sdim    const lldb::addr_t load_addr = process_address + m_offset;
677314564Sdim    dump_stream.Printf("0x%" PRIx64 ": EntityVariable\n", load_addr);
678309124Sdim
679321369Sdim    Status err;
680309124Sdim
681314564Sdim    lldb::addr_t ptr = LLDB_INVALID_ADDRESS;
682309124Sdim
683314564Sdim    {
684314564Sdim      dump_stream.Printf("Pointer:\n");
685309124Sdim
686314564Sdim      DataBufferHeap data(m_size, 0);
687309124Sdim
688314564Sdim      map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
689309124Sdim
690314564Sdim      if (!err.Success()) {
691314564Sdim        dump_stream.Printf("  <could not be read>\n");
692314564Sdim      } else {
693314564Sdim        DataExtractor extractor(data.GetBytes(), data.GetByteSize(),
694314564Sdim                                map.GetByteOrder(), map.GetAddressByteSize());
695309124Sdim
696321369Sdim        DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
697321369Sdim                     load_addr);
698309124Sdim
699314564Sdim        lldb::offset_t offset;
700309124Sdim
701314564Sdim        ptr = extractor.GetPointer(&offset);
702309124Sdim
703314564Sdim        dump_stream.PutChar('\n');
704314564Sdim      }
705314564Sdim    }
706309124Sdim
707314564Sdim    if (m_temporary_allocation == LLDB_INVALID_ADDRESS) {
708314564Sdim      dump_stream.Printf("Points to process memory:\n");
709314564Sdim    } else {
710314564Sdim      dump_stream.Printf("Temporary allocation:\n");
711314564Sdim    }
712309124Sdim
713314564Sdim    if (ptr == LLDB_INVALID_ADDRESS) {
714314564Sdim      dump_stream.Printf("  <could not be be found>\n");
715314564Sdim    } else {
716314564Sdim      DataBufferHeap data(m_temporary_allocation_size, 0);
717309124Sdim
718314564Sdim      map.ReadMemory(data.GetBytes(), m_temporary_allocation,
719314564Sdim                     m_temporary_allocation_size, err);
720309124Sdim
721314564Sdim      if (!err.Success()) {
722314564Sdim        dump_stream.Printf("  <could not be read>\n");
723314564Sdim      } else {
724321369Sdim        DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
725321369Sdim                     load_addr);
726309124Sdim
727314564Sdim        dump_stream.PutChar('\n');
728314564Sdim      }
729254721Semaste    }
730309124Sdim
731314564Sdim    log->PutString(dump_stream.GetString());
732314564Sdim  }
733309124Sdim
734314564Sdim  void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {
735314564Sdim    if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
736321369Sdim      Status free_error;
737309124Sdim
738314564Sdim      map.Free(m_temporary_allocation, free_error);
739254721Semaste
740314564Sdim      m_temporary_allocation = LLDB_INVALID_ADDRESS;
741314564Sdim      m_temporary_allocation_size = 0;
742254721Semaste    }
743314564Sdim  }
744296417Sdim
745254721Semasteprivate:
746314564Sdim  lldb::VariableSP m_variable_sp;
747314564Sdim  bool m_is_reference;
748314564Sdim  lldb::addr_t m_temporary_allocation;
749314564Sdim  size_t m_temporary_allocation_size;
750314564Sdim  lldb::DataBufferSP m_original_data;
751254721Semaste};
752254721Semaste
753321369Sdimuint32_t Materializer::AddVariable(lldb::VariableSP &variable_sp, Status &err) {
754314564Sdim  EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
755314564Sdim  iter->reset(new EntityVariable(variable_sp));
756314564Sdim  uint32_t ret = AddStructMember(**iter);
757314564Sdim  (*iter)->SetOffset(ret);
758314564Sdim  return ret;
759254721Semaste}
760254721Semaste
761314564Sdimclass EntityResultVariable : public Materializer::Entity {
762254721Semastepublic:
763314564Sdim  EntityResultVariable(const CompilerType &type, bool is_program_reference,
764314564Sdim                       bool keep_in_memory,
765314564Sdim                       Materializer::PersistentVariableDelegate *delegate)
766314564Sdim      : Entity(), m_type(type), m_is_program_reference(is_program_reference),
767254721Semaste        m_keep_in_memory(keep_in_memory),
768254721Semaste        m_temporary_allocation(LLDB_INVALID_ADDRESS),
769314564Sdim        m_temporary_allocation_size(0), m_delegate(delegate) {
770314564Sdim    // Hard-coding to maximum size of a pointer since all results are
771314564Sdim    // materialized by reference
772314564Sdim    m_size = 8;
773314564Sdim    m_alignment = 8;
774314564Sdim  }
775309124Sdim
776314564Sdim  void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
777321369Sdim                   lldb::addr_t process_address, Status &err) override {
778314564Sdim    if (!m_is_program_reference) {
779314564Sdim      if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
780314564Sdim        err.SetErrorString("Trying to create a temporary region for the result "
781314564Sdim                           "but one exists");
782314564Sdim        return;
783314564Sdim      }
784309124Sdim
785314564Sdim      const lldb::addr_t load_addr = process_address + m_offset;
786254721Semaste
787314564Sdim      ExecutionContextScope *exe_scope = map.GetBestExecutionContextScope();
788309124Sdim
789344779Sdim      llvm::Optional<uint64_t> byte_size = m_type.GetByteSize(exe_scope);
790344779Sdim      if (!byte_size) {
791344779Sdim        err.SetErrorString("can't get size of type");
792344779Sdim        return;
793344779Sdim      }
794309124Sdim
795360784Sdim      llvm::Optional<size_t> opt_bit_align = m_type.GetTypeBitAlign(exe_scope);
796360784Sdim      if (!opt_bit_align) {
797360784Sdim        err.SetErrorStringWithFormat("can't get the type alignment");
798360784Sdim        return;
799360784Sdim      }
800296417Sdim
801360784Sdim      size_t byte_align = (*opt_bit_align + 7) / 8;
802360784Sdim
803321369Sdim      Status alloc_error;
804314564Sdim      const bool zero_memory = true;
805309124Sdim
806314564Sdim      m_temporary_allocation = map.Malloc(
807344779Sdim          *byte_size, byte_align,
808314564Sdim          lldb::ePermissionsReadable | lldb::ePermissionsWritable,
809314564Sdim          IRMemoryMap::eAllocationPolicyMirror, zero_memory, alloc_error);
810344779Sdim      m_temporary_allocation_size = *byte_size;
811309124Sdim
812314564Sdim      if (!alloc_error.Success()) {
813314564Sdim        err.SetErrorStringWithFormat(
814314564Sdim            "couldn't allocate a temporary region for the result: %s",
815314564Sdim            alloc_error.AsCString());
816314564Sdim        return;
817314564Sdim      }
818309124Sdim
819321369Sdim      Status pointer_write_error;
820309124Sdim
821314564Sdim      map.WritePointerToMemory(load_addr, m_temporary_allocation,
822314564Sdim                               pointer_write_error);
823314564Sdim
824314564Sdim      if (!pointer_write_error.Success()) {
825314564Sdim        err.SetErrorStringWithFormat("couldn't write the address of the "
826314564Sdim                                     "temporary region for the result: %s",
827314564Sdim                                     pointer_write_error.AsCString());
828314564Sdim      }
829254721Semaste    }
830314564Sdim  }
831309124Sdim
832314564Sdim  void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
833314564Sdim                     lldb::addr_t process_address, lldb::addr_t frame_top,
834321369Sdim                     lldb::addr_t frame_bottom, Status &err) override {
835314564Sdim    err.Clear();
836309124Sdim
837314564Sdim    ExecutionContextScope *exe_scope = map.GetBestExecutionContextScope();
838309124Sdim
839314564Sdim    if (!exe_scope) {
840314564Sdim      err.SetErrorString("Couldn't dematerialize a result variable: invalid "
841314564Sdim                         "execution context scope");
842314564Sdim      return;
843314564Sdim    }
844309124Sdim
845314564Sdim    lldb::addr_t address;
846321369Sdim    Status read_error;
847314564Sdim    const lldb::addr_t load_addr = process_address + m_offset;
848309124Sdim
849314564Sdim    map.ReadPointerFromMemory(&address, load_addr, read_error);
850309124Sdim
851314564Sdim    if (!read_error.Success()) {
852314564Sdim      err.SetErrorString("Couldn't dematerialize a result variable: couldn't "
853314564Sdim                         "read its address");
854314564Sdim      return;
855314564Sdim    }
856309124Sdim
857314564Sdim    lldb::TargetSP target_sp = exe_scope->CalculateTarget();
858309124Sdim
859314564Sdim    if (!target_sp) {
860314564Sdim      err.SetErrorString("Couldn't dematerialize a result variable: no target");
861314564Sdim      return;
862314564Sdim    }
863309124Sdim
864360784Sdim    auto type_system_or_err =
865360784Sdim        target_sp->GetScratchTypeSystemForLanguage(m_type.GetMinimumLanguage());
866309124Sdim
867360784Sdim    if (auto error = type_system_or_err.takeError()) {
868314564Sdim      err.SetErrorStringWithFormat("Couldn't dematerialize a result variable: "
869314564Sdim                                   "couldn't get the corresponding type "
870314564Sdim                                   "system: %s",
871360784Sdim                                   llvm::toString(std::move(error)).c_str());
872314564Sdim      return;
873314564Sdim    }
874314564Sdim    PersistentExpressionState *persistent_state =
875360784Sdim        type_system_or_err->GetPersistentExpressionState();
876309124Sdim
877314564Sdim    if (!persistent_state) {
878314564Sdim      err.SetErrorString("Couldn't dematerialize a result variable: "
879314564Sdim                         "corresponding type system doesn't handle persistent "
880314564Sdim                         "variables");
881314564Sdim      return;
882314564Sdim    }
883309124Sdim
884341825Sdim    ConstString name =
885341825Sdim        m_delegate
886341825Sdim            ? m_delegate->GetName()
887341825Sdim            : persistent_state->GetNextPersistentVariableName(
888341825Sdim                  *target_sp, persistent_state->GetPersistentVariablePrefix());
889309124Sdim
890314564Sdim    lldb::ExpressionVariableSP ret = persistent_state->CreatePersistentVariable(
891314564Sdim        exe_scope, name, m_type, map.GetByteOrder(), map.GetAddressByteSize());
892309124Sdim
893314564Sdim    if (!ret) {
894314564Sdim      err.SetErrorStringWithFormat("couldn't dematerialize a result variable: "
895314564Sdim                                   "failed to make persistent variable %s",
896314564Sdim                                   name.AsCString());
897314564Sdim      return;
898314564Sdim    }
899309124Sdim
900314564Sdim    lldb::ProcessSP process_sp =
901314564Sdim        map.GetBestExecutionContextScope()->CalculateProcess();
902309124Sdim
903314564Sdim    if (m_delegate) {
904314564Sdim      m_delegate->DidDematerialize(ret);
905314564Sdim    }
906309124Sdim
907314564Sdim    bool can_persist =
908314564Sdim        (m_is_program_reference && process_sp && process_sp->CanJIT() &&
909314564Sdim         !(address >= frame_bottom && address < frame_top));
910254721Semaste
911314564Sdim    if (can_persist && m_keep_in_memory) {
912314564Sdim      ret->m_live_sp = ValueObjectConstResult::Create(exe_scope, m_type, name,
913314564Sdim                                                      address, eAddressTypeLoad,
914314564Sdim                                                      map.GetAddressByteSize());
915314564Sdim    }
916309124Sdim
917314564Sdim    ret->ValueUpdated();
918309124Sdim
919314564Sdim    const size_t pvar_byte_size = ret->GetByteSize();
920314564Sdim    uint8_t *pvar_data = ret->GetValueBytes();
921309124Sdim
922314564Sdim    map.ReadMemory(pvar_data, address, pvar_byte_size, read_error);
923309124Sdim
924314564Sdim    if (!read_error.Success()) {
925314564Sdim      err.SetErrorString(
926314564Sdim          "Couldn't dematerialize a result variable: couldn't read its memory");
927314564Sdim      return;
928314564Sdim    }
929309124Sdim
930314564Sdim    if (!can_persist || !m_keep_in_memory) {
931314564Sdim      ret->m_flags |= ExpressionVariable::EVNeedsAllocation;
932309124Sdim
933314564Sdim      if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
934321369Sdim        Status free_error;
935314564Sdim        map.Free(m_temporary_allocation, free_error);
936314564Sdim      }
937314564Sdim    } else {
938314564Sdim      ret->m_flags |= ExpressionVariable::EVIsLLDBAllocated;
939254721Semaste    }
940309124Sdim
941314564Sdim    m_temporary_allocation = LLDB_INVALID_ADDRESS;
942314564Sdim    m_temporary_allocation_size = 0;
943314564Sdim  }
944309124Sdim
945314564Sdim  void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
946314564Sdim                 Log *log) override {
947314564Sdim    StreamString dump_stream;
948254721Semaste
949314564Sdim    const lldb::addr_t load_addr = process_address + m_offset;
950309124Sdim
951314564Sdim    dump_stream.Printf("0x%" PRIx64 ": EntityResultVariable\n", load_addr);
952309124Sdim
953321369Sdim    Status err;
954309124Sdim
955314564Sdim    lldb::addr_t ptr = LLDB_INVALID_ADDRESS;
956309124Sdim
957314564Sdim    {
958314564Sdim      dump_stream.Printf("Pointer:\n");
959309124Sdim
960314564Sdim      DataBufferHeap data(m_size, 0);
961309124Sdim
962314564Sdim      map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
963309124Sdim
964314564Sdim      if (!err.Success()) {
965314564Sdim        dump_stream.Printf("  <could not be read>\n");
966314564Sdim      } else {
967314564Sdim        DataExtractor extractor(data.GetBytes(), data.GetByteSize(),
968314564Sdim                                map.GetByteOrder(), map.GetAddressByteSize());
969309124Sdim
970321369Sdim        DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
971321369Sdim                     load_addr);
972309124Sdim
973314564Sdim        lldb::offset_t offset;
974309124Sdim
975314564Sdim        ptr = extractor.GetPointer(&offset);
976309124Sdim
977314564Sdim        dump_stream.PutChar('\n');
978314564Sdim      }
979314564Sdim    }
980309124Sdim
981314564Sdim    if (m_temporary_allocation == LLDB_INVALID_ADDRESS) {
982314564Sdim      dump_stream.Printf("Points to process memory:\n");
983314564Sdim    } else {
984314564Sdim      dump_stream.Printf("Temporary allocation:\n");
985314564Sdim    }
986309124Sdim
987314564Sdim    if (ptr == LLDB_INVALID_ADDRESS) {
988314564Sdim      dump_stream.Printf("  <could not be be found>\n");
989314564Sdim    } else {
990314564Sdim      DataBufferHeap data(m_temporary_allocation_size, 0);
991309124Sdim
992314564Sdim      map.ReadMemory(data.GetBytes(), m_temporary_allocation,
993314564Sdim                     m_temporary_allocation_size, err);
994309124Sdim
995314564Sdim      if (!err.Success()) {
996314564Sdim        dump_stream.Printf("  <could not be read>\n");
997314564Sdim      } else {
998321369Sdim        DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
999321369Sdim                     load_addr);
1000309124Sdim
1001314564Sdim        dump_stream.PutChar('\n');
1002314564Sdim      }
1003254721Semaste    }
1004309124Sdim
1005314564Sdim    log->PutString(dump_stream.GetString());
1006314564Sdim  }
1007309124Sdim
1008314564Sdim  void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {
1009314564Sdim    if (!m_keep_in_memory && m_temporary_allocation != LLDB_INVALID_ADDRESS) {
1010321369Sdim      Status free_error;
1011309124Sdim
1012314564Sdim      map.Free(m_temporary_allocation, free_error);
1013254721Semaste    }
1014296417Sdim
1015314564Sdim    m_temporary_allocation = LLDB_INVALID_ADDRESS;
1016314564Sdim    m_temporary_allocation_size = 0;
1017314564Sdim  }
1018314564Sdim
1019254721Semasteprivate:
1020314564Sdim  CompilerType m_type;
1021314564Sdim  bool m_is_program_reference;
1022314564Sdim  bool m_keep_in_memory;
1023309124Sdim
1024314564Sdim  lldb::addr_t m_temporary_allocation;
1025314564Sdim  size_t m_temporary_allocation_size;
1026314564Sdim  Materializer::PersistentVariableDelegate *m_delegate;
1027254721Semaste};
1028254721Semaste
1029314564Sdimuint32_t Materializer::AddResultVariable(const CompilerType &type,
1030314564Sdim                                         bool is_program_reference,
1031314564Sdim                                         bool keep_in_memory,
1032314564Sdim                                         PersistentVariableDelegate *delegate,
1033321369Sdim                                         Status &err) {
1034314564Sdim  EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
1035314564Sdim  iter->reset(new EntityResultVariable(type, is_program_reference,
1036314564Sdim                                       keep_in_memory, delegate));
1037314564Sdim  uint32_t ret = AddStructMember(**iter);
1038314564Sdim  (*iter)->SetOffset(ret);
1039314564Sdim  return ret;
1040254721Semaste}
1041254721Semaste
1042314564Sdimclass EntitySymbol : public Materializer::Entity {
1043254721Semastepublic:
1044314564Sdim  EntitySymbol(const Symbol &symbol) : Entity(), m_symbol(symbol) {
1045314564Sdim    // Hard-coding to maximum size of a symbol
1046314564Sdim    m_size = 8;
1047314564Sdim    m_alignment = 8;
1048314564Sdim  }
1049309124Sdim
1050314564Sdim  void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1051321369Sdim                   lldb::addr_t process_address, Status &err) override {
1052314564Sdim    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
1053254721Semaste
1054314564Sdim    const lldb::addr_t load_addr = process_address + m_offset;
1055254721Semaste
1056314564Sdim    if (log) {
1057360784Sdim      LLDB_LOGF(log,
1058360784Sdim                "EntitySymbol::Materialize [address = 0x%" PRIx64
1059360784Sdim                ", m_symbol = %s]",
1060360784Sdim                (uint64_t)load_addr, m_symbol.GetName().AsCString());
1061314564Sdim    }
1062309124Sdim
1063314564Sdim    const Address sym_address = m_symbol.GetAddress();
1064254721Semaste
1065314564Sdim    ExecutionContextScope *exe_scope = map.GetBestExecutionContextScope();
1066309124Sdim
1067314564Sdim    lldb::TargetSP target_sp;
1068309124Sdim
1069314564Sdim    if (exe_scope)
1070314564Sdim      target_sp = map.GetBestExecutionContextScope()->CalculateTarget();
1071309124Sdim
1072314564Sdim    if (!target_sp) {
1073314564Sdim      err.SetErrorStringWithFormat(
1074314564Sdim          "couldn't resolve symbol %s because there is no target",
1075314564Sdim          m_symbol.GetName().AsCString());
1076314564Sdim      return;
1077314564Sdim    }
1078309124Sdim
1079314564Sdim    lldb::addr_t resolved_address = sym_address.GetLoadAddress(target_sp.get());
1080309124Sdim
1081314564Sdim    if (resolved_address == LLDB_INVALID_ADDRESS)
1082314564Sdim      resolved_address = sym_address.GetFileAddress();
1083309124Sdim
1084321369Sdim    Status pointer_write_error;
1085309124Sdim
1086314564Sdim    map.WritePointerToMemory(load_addr, resolved_address, pointer_write_error);
1087309124Sdim
1088314564Sdim    if (!pointer_write_error.Success()) {
1089314564Sdim      err.SetErrorStringWithFormat(
1090314564Sdim          "couldn't write the address of symbol %s: %s",
1091314564Sdim          m_symbol.GetName().AsCString(), pointer_write_error.AsCString());
1092314564Sdim      return;
1093254721Semaste    }
1094314564Sdim  }
1095309124Sdim
1096314564Sdim  void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1097314564Sdim                     lldb::addr_t process_address, lldb::addr_t frame_top,
1098321369Sdim                     lldb::addr_t frame_bottom, Status &err) override {
1099314564Sdim    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
1100254721Semaste
1101314564Sdim    const lldb::addr_t load_addr = process_address + m_offset;
1102254721Semaste
1103314564Sdim    if (log) {
1104360784Sdim      LLDB_LOGF(log,
1105360784Sdim                "EntitySymbol::Dematerialize [address = 0x%" PRIx64
1106360784Sdim                ", m_symbol = %s]",
1107360784Sdim                (uint64_t)load_addr, m_symbol.GetName().AsCString());
1108254721Semaste    }
1109309124Sdim
1110314564Sdim    // no work needs to be done
1111314564Sdim  }
1112309124Sdim
1113314564Sdim  void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
1114314564Sdim                 Log *log) override {
1115314564Sdim    StreamString dump_stream;
1116309124Sdim
1117321369Sdim    Status err;
1118254721Semaste
1119314564Sdim    const lldb::addr_t load_addr = process_address + m_offset;
1120309124Sdim
1121314564Sdim    dump_stream.Printf("0x%" PRIx64 ": EntitySymbol (%s)\n", load_addr,
1122314564Sdim                       m_symbol.GetName().AsCString());
1123309124Sdim
1124314564Sdim    {
1125314564Sdim      dump_stream.Printf("Pointer:\n");
1126309124Sdim
1127314564Sdim      DataBufferHeap data(m_size, 0);
1128309124Sdim
1129314564Sdim      map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
1130309124Sdim
1131314564Sdim      if (!err.Success()) {
1132314564Sdim        dump_stream.Printf("  <could not be read>\n");
1133314564Sdim      } else {
1134321369Sdim        DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
1135321369Sdim                     load_addr);
1136309124Sdim
1137314564Sdim        dump_stream.PutChar('\n');
1138314564Sdim      }
1139254721Semaste    }
1140309124Sdim
1141314564Sdim    log->PutString(dump_stream.GetString());
1142314564Sdim  }
1143296417Sdim
1144314564Sdim  void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {}
1145314564Sdim
1146254721Semasteprivate:
1147314564Sdim  Symbol m_symbol;
1148254721Semaste};
1149254721Semaste
1150321369Sdimuint32_t Materializer::AddSymbol(const Symbol &symbol_sp, Status &err) {
1151314564Sdim  EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
1152314564Sdim  iter->reset(new EntitySymbol(symbol_sp));
1153314564Sdim  uint32_t ret = AddStructMember(**iter);
1154314564Sdim  (*iter)->SetOffset(ret);
1155314564Sdim  return ret;
1156254721Semaste}
1157254721Semaste
1158314564Sdimclass EntityRegister : public Materializer::Entity {
1159254721Semastepublic:
1160314564Sdim  EntityRegister(const RegisterInfo &register_info)
1161314564Sdim      : Entity(), m_register_info(register_info) {
1162314564Sdim    // Hard-coding alignment conservatively
1163314564Sdim    m_size = m_register_info.byte_size;
1164314564Sdim    m_alignment = m_register_info.byte_size;
1165314564Sdim  }
1166314564Sdim
1167314564Sdim  void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1168321369Sdim                   lldb::addr_t process_address, Status &err) override {
1169314564Sdim    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
1170314564Sdim
1171314564Sdim    const lldb::addr_t load_addr = process_address + m_offset;
1172314564Sdim
1173314564Sdim    if (log) {
1174360784Sdim      LLDB_LOGF(log,
1175360784Sdim                "EntityRegister::Materialize [address = 0x%" PRIx64
1176360784Sdim                ", m_register_info = %s]",
1177360784Sdim                (uint64_t)load_addr, m_register_info.name);
1178254721Semaste    }
1179309124Sdim
1180314564Sdim    RegisterValue reg_value;
1181309124Sdim
1182314564Sdim    if (!frame_sp.get()) {
1183314564Sdim      err.SetErrorStringWithFormat(
1184314564Sdim          "couldn't materialize register %s without a stack frame",
1185314564Sdim          m_register_info.name);
1186314564Sdim      return;
1187314564Sdim    }
1188254721Semaste
1189314564Sdim    lldb::RegisterContextSP reg_context_sp = frame_sp->GetRegisterContext();
1190254721Semaste
1191314564Sdim    if (!reg_context_sp->ReadRegister(&m_register_info, reg_value)) {
1192314564Sdim      err.SetErrorStringWithFormat("couldn't read the value of register %s",
1193314564Sdim                                   m_register_info.name);
1194314564Sdim      return;
1195314564Sdim    }
1196309124Sdim
1197314564Sdim    DataExtractor register_data;
1198309124Sdim
1199314564Sdim    if (!reg_value.GetData(register_data)) {
1200314564Sdim      err.SetErrorStringWithFormat("couldn't get the data for register %s",
1201314564Sdim                                   m_register_info.name);
1202314564Sdim      return;
1203314564Sdim    }
1204309124Sdim
1205314564Sdim    if (register_data.GetByteSize() != m_register_info.byte_size) {
1206314564Sdim      err.SetErrorStringWithFormat(
1207314564Sdim          "data for register %s had size %llu but we expected %llu",
1208314564Sdim          m_register_info.name, (unsigned long long)register_data.GetByteSize(),
1209314564Sdim          (unsigned long long)m_register_info.byte_size);
1210314564Sdim      return;
1211314564Sdim    }
1212309124Sdim
1213353358Sdim    m_register_contents = std::make_shared<DataBufferHeap>(
1214353358Sdim        register_data.GetDataStart(), register_data.GetByteSize());
1215309124Sdim
1216321369Sdim    Status write_error;
1217309124Sdim
1218314564Sdim    map.WriteMemory(load_addr, register_data.GetDataStart(),
1219314564Sdim                    register_data.GetByteSize(), write_error);
1220309124Sdim
1221314564Sdim    if (!write_error.Success()) {
1222314564Sdim      err.SetErrorStringWithFormat(
1223314564Sdim          "couldn't write the contents of register %s: %s",
1224314564Sdim          m_register_info.name, write_error.AsCString());
1225314564Sdim      return;
1226254721Semaste    }
1227314564Sdim  }
1228309124Sdim
1229314564Sdim  void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1230314564Sdim                     lldb::addr_t process_address, lldb::addr_t frame_top,
1231321369Sdim                     lldb::addr_t frame_bottom, Status &err) override {
1232314564Sdim    Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
1233309124Sdim
1234314564Sdim    const lldb::addr_t load_addr = process_address + m_offset;
1235254721Semaste
1236314564Sdim    if (log) {
1237360784Sdim      LLDB_LOGF(log,
1238360784Sdim                "EntityRegister::Dematerialize [address = 0x%" PRIx64
1239360784Sdim                ", m_register_info = %s]",
1240360784Sdim                (uint64_t)load_addr, m_register_info.name);
1241314564Sdim    }
1242309124Sdim
1243321369Sdim    Status extract_error;
1244309124Sdim
1245314564Sdim    DataExtractor register_data;
1246309124Sdim
1247314564Sdim    if (!frame_sp.get()) {
1248314564Sdim      err.SetErrorStringWithFormat(
1249314564Sdim          "couldn't dematerialize register %s without a stack frame",
1250314564Sdim          m_register_info.name);
1251314564Sdim      return;
1252314564Sdim    }
1253309124Sdim
1254314564Sdim    lldb::RegisterContextSP reg_context_sp = frame_sp->GetRegisterContext();
1255309124Sdim
1256314564Sdim    map.GetMemoryData(register_data, load_addr, m_register_info.byte_size,
1257314564Sdim                      extract_error);
1258309124Sdim
1259314564Sdim    if (!extract_error.Success()) {
1260314564Sdim      err.SetErrorStringWithFormat("couldn't get the data for register %s: %s",
1261314564Sdim                                   m_register_info.name,
1262314564Sdim                                   extract_error.AsCString());
1263314564Sdim      return;
1264314564Sdim    }
1265309124Sdim
1266314564Sdim    if (!memcmp(register_data.GetDataStart(), m_register_contents->GetBytes(),
1267314564Sdim                register_data.GetByteSize())) {
1268314564Sdim      // No write required, and in particular we avoid errors if the register
1269314564Sdim      // wasn't writable
1270309124Sdim
1271314564Sdim      m_register_contents.reset();
1272314564Sdim      return;
1273314564Sdim    }
1274309124Sdim
1275314564Sdim    m_register_contents.reset();
1276309124Sdim
1277314564Sdim    RegisterValue register_value(
1278314564Sdim        const_cast<uint8_t *>(register_data.GetDataStart()),
1279314564Sdim        register_data.GetByteSize(), register_data.GetByteOrder());
1280309124Sdim
1281314564Sdim    if (!reg_context_sp->WriteRegister(&m_register_info, register_value)) {
1282314564Sdim      err.SetErrorStringWithFormat("couldn't write the value of register %s",
1283314564Sdim                                   m_register_info.name);
1284314564Sdim      return;
1285254721Semaste    }
1286314564Sdim  }
1287309124Sdim
1288314564Sdim  void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
1289314564Sdim                 Log *log) override {
1290314564Sdim    StreamString dump_stream;
1291309124Sdim
1292321369Sdim    Status err;
1293309124Sdim
1294314564Sdim    const lldb::addr_t load_addr = process_address + m_offset;
1295254721Semaste
1296314564Sdim    dump_stream.Printf("0x%" PRIx64 ": EntityRegister (%s)\n", load_addr,
1297314564Sdim                       m_register_info.name);
1298309124Sdim
1299314564Sdim    {
1300314564Sdim      dump_stream.Printf("Value:\n");
1301309124Sdim
1302314564Sdim      DataBufferHeap data(m_size, 0);
1303309124Sdim
1304314564Sdim      map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
1305309124Sdim
1306314564Sdim      if (!err.Success()) {
1307314564Sdim        dump_stream.Printf("  <could not be read>\n");
1308314564Sdim      } else {
1309321369Sdim        DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
1310321369Sdim                     load_addr);
1311309124Sdim
1312314564Sdim        dump_stream.PutChar('\n');
1313314564Sdim      }
1314314564Sdim    }
1315309124Sdim
1316314564Sdim    log->PutString(dump_stream.GetString());
1317314564Sdim  }
1318309124Sdim
1319314564Sdim  void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {}
1320309124Sdim
1321254721Semasteprivate:
1322314564Sdim  RegisterInfo m_register_info;
1323314564Sdim  lldb::DataBufferSP m_register_contents;
1324254721Semaste};
1325254721Semaste
1326314564Sdimuint32_t Materializer::AddRegister(const RegisterInfo &register_info,
1327321369Sdim                                   Status &err) {
1328314564Sdim  EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
1329314564Sdim  iter->reset(new EntityRegister(register_info));
1330314564Sdim  uint32_t ret = AddStructMember(**iter);
1331314564Sdim  (*iter)->SetOffset(ret);
1332314564Sdim  return ret;
1333254721Semaste}
1334254721Semaste
1335314564SdimMaterializer::Materializer()
1336314564Sdim    : m_dematerializer_wp(), m_current_offset(0), m_struct_alignment(8) {}
1337254721Semaste
1338314564SdimMaterializer::~Materializer() {
1339314564Sdim  DematerializerSP dematerializer_sp = m_dematerializer_wp.lock();
1340309124Sdim
1341314564Sdim  if (dematerializer_sp)
1342314564Sdim    dematerializer_sp->Wipe();
1343254721Semaste}
1344254721Semaste
1345254721SemasteMaterializer::DematerializerSP
1346314564SdimMaterializer::Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1347321369Sdim                          lldb::addr_t process_address, Status &error) {
1348314564Sdim  ExecutionContextScope *exe_scope = frame_sp.get();
1349276479Sdim
1350314564Sdim  if (!exe_scope)
1351314564Sdim    exe_scope = map.GetBestExecutionContextScope();
1352276479Sdim
1353314564Sdim  DematerializerSP dematerializer_sp = m_dematerializer_wp.lock();
1354276479Sdim
1355314564Sdim  if (dematerializer_sp) {
1356314564Sdim    error.SetErrorToGenericError();
1357314564Sdim    error.SetErrorString("Couldn't materialize: already materialized");
1358314564Sdim  }
1359276479Sdim
1360314564Sdim  DematerializerSP ret(
1361314564Sdim      new Dematerializer(*this, frame_sp, map, process_address));
1362276479Sdim
1363314564Sdim  if (!exe_scope) {
1364314564Sdim    error.SetErrorToGenericError();
1365314564Sdim    error.SetErrorString("Couldn't materialize: target doesn't exist");
1366314564Sdim  }
1367276479Sdim
1368314564Sdim  for (EntityUP &entity_up : m_entities) {
1369314564Sdim    entity_up->Materialize(frame_sp, map, process_address, error);
1370276479Sdim
1371314564Sdim    if (!error.Success())
1372314564Sdim      return DematerializerSP();
1373314564Sdim  }
1374276479Sdim
1375314564Sdim  if (Log *log =
1376314564Sdim          lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)) {
1377360784Sdim    LLDB_LOGF(
1378360784Sdim        log,
1379314564Sdim        "Materializer::Materialize (frame_sp = %p, process_address = 0x%" PRIx64
1380314564Sdim        ") materialized:",
1381314564Sdim        static_cast<void *>(frame_sp.get()), process_address);
1382314564Sdim    for (EntityUP &entity_up : m_entities)
1383314564Sdim      entity_up->DumpToLog(map, process_address, log);
1384314564Sdim  }
1385276479Sdim
1386314564Sdim  m_dematerializer_wp = ret;
1387276479Sdim
1388314564Sdim  return ret;
1389254721Semaste}
1390254721Semaste
1391321369Sdimvoid Materializer::Dematerializer::Dematerialize(Status &error,
1392314564Sdim                                                 lldb::addr_t frame_bottom,
1393314564Sdim                                                 lldb::addr_t frame_top) {
1394314564Sdim  lldb::StackFrameSP frame_sp;
1395254721Semaste
1396314564Sdim  lldb::ThreadSP thread_sp = m_thread_wp.lock();
1397314564Sdim  if (thread_sp)
1398314564Sdim    frame_sp = thread_sp->GetFrameWithStackID(m_stack_id);
1399276479Sdim
1400314564Sdim  ExecutionContextScope *exe_scope = m_map->GetBestExecutionContextScope();
1401276479Sdim
1402314564Sdim  if (!IsValid()) {
1403314564Sdim    error.SetErrorToGenericError();
1404314564Sdim    error.SetErrorString("Couldn't dematerialize: invalid dematerializer");
1405314564Sdim  }
1406276479Sdim
1407314564Sdim  if (!exe_scope) {
1408314564Sdim    error.SetErrorToGenericError();
1409314564Sdim    error.SetErrorString("Couldn't dematerialize: target is gone");
1410314564Sdim  } else {
1411314564Sdim    if (Log *log =
1412314564Sdim            lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)) {
1413360784Sdim      LLDB_LOGF(log,
1414360784Sdim                "Materializer::Dematerialize (frame_sp = %p, process_address "
1415360784Sdim                "= 0x%" PRIx64 ") about to dematerialize:",
1416360784Sdim                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