180814287SRaphael Isemann //===-- Materializer.cpp --------------------------------------------------===//
296d2730aSSean Callanan //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
696d2730aSSean Callanan //
796d2730aSSean Callanan //===----------------------------------------------------------------------===//
896d2730aSSean Callanan 
9b9c1b51eSKate Stone #include "lldb/Expression/Materializer.h"
1029cb868aSZachary Turner #include "lldb/Core/DumpDataExtractor.h"
1135005f76SSean Callanan #include "lldb/Core/ValueObjectConstResult.h"
12f8043fa5SSean Callanan #include "lldb/Core/ValueObjectVariable.h"
138f1f9a1bSSean Callanan #include "lldb/Expression/ExpressionVariable.h"
1496d2730aSSean Callanan #include "lldb/Symbol/Symbol.h"
1596d2730aSSean Callanan #include "lldb/Symbol/Type.h"
1696d2730aSSean Callanan #include "lldb/Symbol/Variable.h"
1796d2730aSSean Callanan #include "lldb/Target/ExecutionContext.h"
18b5717e00SSean Callanan #include "lldb/Target/RegisterContext.h"
19b57e4a1bSJason Molenda #include "lldb/Target/StackFrame.h"
201582ee68SSean Callanan #include "lldb/Target/Target.h"
21a4e8105bSSean Callanan #include "lldb/Target/Thread.h"
22c34698a8SPavel Labath #include "lldb/Utility/LLDBLog.h"
236f9e6901SZachary Turner #include "lldb/Utility/Log.h"
24d821c997SPavel Labath #include "lldb/Utility/RegisterValue.h"
25*317c8bf8SMichael Buch #include "lldb/lldb-forward.h"
2696d2730aSSean Callanan 
27796ac80bSJonas Devlieghere #include <memory>
28796ac80bSJonas Devlieghere 
2996d2730aSSean Callanan using namespace lldb_private;
3096d2730aSSean Callanan 
31fcf4e252SMichael Buch // FIXME: these should be retrieved from the target
32fcf4e252SMichael Buch //        instead of being hard-coded. Currently we
33fcf4e252SMichael Buch //        assume that persistent vars are materialized
34fcf4e252SMichael Buch //        as references, and thus pick the size of a
35fcf4e252SMichael Buch //        64-bit pointer.
36fcf4e252SMichael Buch static constexpr uint32_t g_default_var_alignment = 8;
37fcf4e252SMichael Buch static constexpr uint32_t g_default_var_byte_size = 8;
38fcf4e252SMichael Buch 
AddStructMember(Entity & entity)39b9c1b51eSKate Stone uint32_t Materializer::AddStructMember(Entity &entity) {
4096d2730aSSean Callanan   uint32_t size = entity.GetSize();
4196d2730aSSean Callanan   uint32_t alignment = entity.GetAlignment();
4296d2730aSSean Callanan 
4396d2730aSSean Callanan   uint32_t ret;
4496d2730aSSean Callanan 
453dd6a423SSean Callanan   if (m_current_offset == 0)
4696d2730aSSean Callanan     m_struct_alignment = alignment;
4796d2730aSSean Callanan 
4896d2730aSSean Callanan   if (m_current_offset % alignment)
4996d2730aSSean Callanan     m_current_offset += (alignment - (m_current_offset % alignment));
5096d2730aSSean Callanan 
5196d2730aSSean Callanan   ret = m_current_offset;
5296d2730aSSean Callanan 
5396d2730aSSean Callanan   m_current_offset += size;
5496d2730aSSean Callanan 
5596d2730aSSean Callanan   return ret;
5696d2730aSSean Callanan }
5796d2730aSSean Callanan 
58b9c1b51eSKate Stone class EntityPersistentVariable : public Materializer::Entity {
5996d2730aSSean Callanan public:
EntityPersistentVariable(lldb::ExpressionVariableSP & persistent_variable_sp,Materializer::PersistentVariableDelegate * delegate)609fda9d21SSean Callanan   EntityPersistentVariable(lldb::ExpressionVariableSP &persistent_variable_sp,
61b9c1b51eSKate Stone                            Materializer::PersistentVariableDelegate *delegate)
62b9c1b51eSKate Stone       : Entity(), m_persistent_variable_sp(persistent_variable_sp),
63b9c1b51eSKate Stone         m_delegate(delegate) {
64b9c1b51eSKate Stone     // Hard-coding to maximum size of a pointer since persistent variables are
65b9c1b51eSKate Stone     // materialized by reference
66fcf4e252SMichael Buch     m_size = g_default_var_byte_size;
67fcf4e252SMichael Buch     m_alignment = g_default_var_alignment;
6896d2730aSSean Callanan   }
6996d2730aSSean Callanan 
MakeAllocation(IRMemoryMap & map,Status & err)7097206d57SZachary Turner   void MakeAllocation(IRMemoryMap &map, Status &err) {
71a007a6d8SPavel Labath     Log *log = GetLog(LLDBLog::Expressions);
7235005f76SSean Callanan 
7305097246SAdrian Prantl     // Allocate a spare memory area to store the persistent variable's
7405097246SAdrian Prantl     // contents.
7535005f76SSean Callanan 
7697206d57SZachary Turner     Status allocate_error;
772c381414SJim Ingham     const bool zero_memory = false;
7835005f76SSean Callanan 
79b9c1b51eSKate Stone     lldb::addr_t mem = map.Malloc(
80aa88161bSKazu Hirata         m_persistent_variable_sp->GetByteSize().value_or(0), 8,
8135005f76SSean Callanan         lldb::ePermissionsReadable | lldb::ePermissionsWritable,
82b9c1b51eSKate Stone         IRMemoryMap::eAllocationPolicyMirror, zero_memory, allocate_error);
8335005f76SSean Callanan 
84b9c1b51eSKate Stone     if (!allocate_error.Success()) {
85b9c1b51eSKate Stone       err.SetErrorStringWithFormat(
86b9c1b51eSKate Stone           "couldn't allocate a memory area to store %s: %s",
87b9c1b51eSKate Stone           m_persistent_variable_sp->GetName().GetCString(),
88b9c1b51eSKate Stone           allocate_error.AsCString());
8935005f76SSean Callanan       return;
9096d2730aSSean Callanan     }
9196d2730aSSean Callanan 
9263e5fb76SJonas Devlieghere     LLDB_LOGF(log, "Allocated %s (0x%" PRIx64 ") successfully",
93b9c1b51eSKate Stone               m_persistent_variable_sp->GetName().GetCString(), mem);
9435005f76SSean Callanan 
95b9c1b51eSKate Stone     // Put the location of the spare memory into the live data of the
96b9c1b51eSKate Stone     // ValueObject.
9735005f76SSean Callanan 
98b9c1b51eSKate Stone     m_persistent_variable_sp->m_live_sp = ValueObjectConstResult::Create(
99b9c1b51eSKate Stone         map.GetBestExecutionContextScope(),
100c608d206SSean Callanan         m_persistent_variable_sp->GetCompilerType(),
101b9c1b51eSKate Stone         m_persistent_variable_sp->GetName(), mem, eAddressTypeLoad,
102edd508b3SSean Callanan         map.GetAddressByteSize());
10335005f76SSean Callanan 
10435005f76SSean Callanan     // Clear the flag if the variable will never be deallocated.
10535005f76SSean Callanan 
106b9c1b51eSKate Stone     if (m_persistent_variable_sp->m_flags &
107b9c1b51eSKate Stone         ExpressionVariable::EVKeepInTarget) {
10897206d57SZachary Turner       Status leak_error;
109fbf5c682SSean Callanan       map.Leak(mem, leak_error);
110b9c1b51eSKate Stone       m_persistent_variable_sp->m_flags &=
111b9c1b51eSKate Stone           ~ExpressionVariable::EVNeedsAllocation;
112fbf5c682SSean Callanan     }
11335005f76SSean Callanan 
11435005f76SSean Callanan     // Write the contents of the variable to the area.
11535005f76SSean Callanan 
11697206d57SZachary Turner     Status write_error;
11735005f76SSean Callanan 
118b9c1b51eSKate Stone     map.WriteMemory(mem, m_persistent_variable_sp->GetValueBytes(),
119aa88161bSKazu Hirata                     m_persistent_variable_sp->GetByteSize().value_or(0),
120113f56fbSAdrian Prantl                     write_error);
12135005f76SSean Callanan 
122b9c1b51eSKate Stone     if (!write_error.Success()) {
123b9c1b51eSKate Stone       err.SetErrorStringWithFormat(
124b9c1b51eSKate Stone           "couldn't write %s to the target: %s",
125b9c1b51eSKate Stone           m_persistent_variable_sp->GetName().AsCString(),
12635005f76SSean Callanan           write_error.AsCString());
12735005f76SSean Callanan       return;
12835005f76SSean Callanan     }
12935005f76SSean Callanan   }
13035005f76SSean Callanan 
DestroyAllocation(IRMemoryMap & map,Status & err)13197206d57SZachary Turner   void DestroyAllocation(IRMemoryMap &map, Status &err) {
13297206d57SZachary Turner     Status deallocate_error;
13335005f76SSean Callanan 
134b9c1b51eSKate Stone     map.Free((lldb::addr_t)m_persistent_variable_sp->m_live_sp->GetValue()
135b9c1b51eSKate Stone                  .GetScalar()
136b9c1b51eSKate Stone                  .ULongLong(),
137b9c1b51eSKate Stone              deallocate_error);
13835005f76SSean Callanan 
1392afbf444SSean Callanan     m_persistent_variable_sp->m_live_sp.reset();
1402afbf444SSean Callanan 
141b9c1b51eSKate Stone     if (!deallocate_error.Success()) {
142b9c1b51eSKate Stone       err.SetErrorStringWithFormat(
143b9c1b51eSKate Stone           "couldn't deallocate memory for %s: %s",
144b9c1b51eSKate Stone           m_persistent_variable_sp->GetName().GetCString(),
145b9c1b51eSKate Stone           deallocate_error.AsCString());
14635005f76SSean Callanan     }
14735005f76SSean Callanan   }
14835005f76SSean Callanan 
Materialize(lldb::StackFrameSP & frame_sp,IRMemoryMap & map,lldb::addr_t process_address,Status & err)149b9c1b51eSKate Stone   void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
15097206d57SZachary Turner                    lldb::addr_t process_address, Status &err) override {
151a007a6d8SPavel Labath     Log *log = GetLog(LLDBLog::Expressions);
15235005f76SSean Callanan 
15357ee3067SGreg Clayton     const lldb::addr_t load_addr = process_address + m_offset;
15457ee3067SGreg Clayton 
155b9c1b51eSKate Stone     if (log) {
15663e5fb76SJonas Devlieghere       LLDB_LOGF(log,
15763e5fb76SJonas Devlieghere                 "EntityPersistentVariable::Materialize [address = 0x%" PRIx64
158b9c1b51eSKate Stone                 ", m_name = %s, m_flags = 0x%hx]",
15957ee3067SGreg Clayton                 (uint64_t)load_addr,
16035005f76SSean Callanan                 m_persistent_variable_sp->GetName().AsCString(),
16135005f76SSean Callanan                 m_persistent_variable_sp->m_flags);
16235005f76SSean Callanan     }
16335005f76SSean Callanan 
164b9c1b51eSKate Stone     if (m_persistent_variable_sp->m_flags &
165b9c1b51eSKate Stone         ExpressionVariable::EVNeedsAllocation) {
16635005f76SSean Callanan       MakeAllocation(map, err);
167b9c1b51eSKate Stone       m_persistent_variable_sp->m_flags |=
168b9c1b51eSKate Stone           ExpressionVariable::EVIsLLDBAllocated;
1692afbf444SSean Callanan 
17035005f76SSean Callanan       if (!err.Success())
17135005f76SSean Callanan         return;
17235005f76SSean Callanan     }
17335005f76SSean Callanan 
174b9c1b51eSKate Stone     if ((m_persistent_variable_sp->m_flags &
175b9c1b51eSKate Stone              ExpressionVariable::EVIsProgramReference &&
176b9c1b51eSKate Stone          m_persistent_variable_sp->m_live_sp) ||
177b9c1b51eSKate Stone         m_persistent_variable_sp->m_flags &
178b9c1b51eSKate Stone             ExpressionVariable::EVIsLLDBAllocated) {
17997206d57SZachary Turner       Status write_error;
18035005f76SSean Callanan 
181b9c1b51eSKate Stone       map.WriteScalarToMemory(
182b9c1b51eSKate Stone           load_addr,
18335005f76SSean Callanan           m_persistent_variable_sp->m_live_sp->GetValue().GetScalar(),
184b9c1b51eSKate Stone           map.GetAddressByteSize(), write_error);
18535005f76SSean Callanan 
186b9c1b51eSKate Stone       if (!write_error.Success()) {
187b9c1b51eSKate Stone         err.SetErrorStringWithFormat(
188b9c1b51eSKate Stone             "couldn't write the location of %s to memory: %s",
189b9c1b51eSKate Stone             m_persistent_variable_sp->GetName().AsCString(),
190b9c1b51eSKate Stone             write_error.AsCString());
19135005f76SSean Callanan       }
192b9c1b51eSKate Stone     } else {
193b9c1b51eSKate Stone       err.SetErrorStringWithFormat(
194b9c1b51eSKate Stone           "no materialization happened for persistent variable %s",
195b9c1b51eSKate Stone           m_persistent_variable_sp->GetName().AsCString());
19635005f76SSean Callanan       return;
19735005f76SSean Callanan     }
19835005f76SSean Callanan   }
19935005f76SSean Callanan 
Dematerialize(lldb::StackFrameSP & frame_sp,IRMemoryMap & map,lldb::addr_t process_address,lldb::addr_t frame_top,lldb::addr_t frame_bottom,Status & err)200b9c1b51eSKate Stone   void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
201b9c1b51eSKate Stone                      lldb::addr_t process_address, lldb::addr_t frame_top,
20297206d57SZachary Turner                      lldb::addr_t frame_bottom, Status &err) override {
203a007a6d8SPavel Labath     Log *log = GetLog(LLDBLog::Expressions);
20435005f76SSean Callanan 
20557ee3067SGreg Clayton     const lldb::addr_t load_addr = process_address + m_offset;
20657ee3067SGreg Clayton 
207b9c1b51eSKate Stone     if (log) {
20863e5fb76SJonas Devlieghere       LLDB_LOGF(log,
209b9c1b51eSKate Stone                 "EntityPersistentVariable::Dematerialize [address = 0x%" PRIx64
210b9c1b51eSKate Stone                 ", m_name = %s, m_flags = 0x%hx]",
21157ee3067SGreg Clayton                 (uint64_t)process_address + m_offset,
21235005f76SSean Callanan                 m_persistent_variable_sp->GetName().AsCString(),
21335005f76SSean Callanan                 m_persistent_variable_sp->m_flags);
21435005f76SSean Callanan     }
21535005f76SSean Callanan 
216b9c1b51eSKate Stone     if (m_delegate) {
2179fda9d21SSean Callanan       m_delegate->DidDematerialize(m_persistent_variable_sp);
2189fda9d21SSean Callanan     }
2199fda9d21SSean Callanan 
220b9c1b51eSKate Stone     if ((m_persistent_variable_sp->m_flags &
221b9c1b51eSKate Stone          ExpressionVariable::EVIsLLDBAllocated) ||
222b9c1b51eSKate Stone         (m_persistent_variable_sp->m_flags &
223b9c1b51eSKate Stone          ExpressionVariable::EVIsProgramReference)) {
224b9c1b51eSKate Stone       if (m_persistent_variable_sp->m_flags &
225b9c1b51eSKate Stone               ExpressionVariable::EVIsProgramReference &&
226b9c1b51eSKate Stone           !m_persistent_variable_sp->m_live_sp) {
227b9c1b51eSKate Stone         // If the reference comes from the program, then the
22805097246SAdrian Prantl         // ClangExpressionVariable's live variable data hasn't been set up yet.
22905097246SAdrian Prantl         // Do this now.
23035005f76SSean Callanan 
23114b1bae5SSean Callanan         lldb::addr_t location;
23297206d57SZachary Turner         Status read_error;
23335005f76SSean Callanan 
23457ee3067SGreg Clayton         map.ReadPointerFromMemory(&location, load_addr, read_error);
23535005f76SSean Callanan 
236b9c1b51eSKate Stone         if (!read_error.Success()) {
237b9c1b51eSKate Stone           err.SetErrorStringWithFormat(
238b9c1b51eSKate Stone               "couldn't read the address of program-allocated variable %s: %s",
239b9c1b51eSKate Stone               m_persistent_variable_sp->GetName().GetCString(),
240b9c1b51eSKate Stone               read_error.AsCString());
24135005f76SSean Callanan           return;
24235005f76SSean Callanan         }
24335005f76SSean Callanan 
244b9c1b51eSKate Stone         m_persistent_variable_sp->m_live_sp = ValueObjectConstResult::Create(
245b9c1b51eSKate Stone             map.GetBestExecutionContextScope(),
246e6f4a826SSean Callanan             m_persistent_variable_sp.get()->GetCompilerType(),
247b9c1b51eSKate Stone             m_persistent_variable_sp->GetName(), location, eAddressTypeLoad,
248aa88161bSKazu Hirata             m_persistent_variable_sp->GetByteSize().value_or(0));
24935005f76SSean Callanan 
25035005f76SSean Callanan         if (frame_top != LLDB_INVALID_ADDRESS &&
251b9c1b51eSKate Stone             frame_bottom != LLDB_INVALID_ADDRESS && location >= frame_bottom &&
252b9c1b51eSKate Stone             location <= frame_top) {
253b9c1b51eSKate Stone           // If the variable is resident in the stack frame created by the
25405097246SAdrian Prantl           // expression, then it cannot be relied upon to stay around.  We
25505097246SAdrian Prantl           // treat it as needing reallocation.
256b9c1b51eSKate Stone           m_persistent_variable_sp->m_flags |=
257b9c1b51eSKate Stone               ExpressionVariable::EVIsLLDBAllocated;
258b9c1b51eSKate Stone           m_persistent_variable_sp->m_flags |=
259b9c1b51eSKate Stone               ExpressionVariable::EVNeedsAllocation;
260b9c1b51eSKate Stone           m_persistent_variable_sp->m_flags |=
261b9c1b51eSKate Stone               ExpressionVariable::EVNeedsFreezeDry;
262b9c1b51eSKate Stone           m_persistent_variable_sp->m_flags &=
263b9c1b51eSKate Stone               ~ExpressionVariable::EVIsProgramReference;
26435005f76SSean Callanan         }
26535005f76SSean Callanan       }
26635005f76SSean Callanan 
267b9c1b51eSKate Stone       lldb::addr_t mem = m_persistent_variable_sp->m_live_sp->GetValue()
268b9c1b51eSKate Stone                              .GetScalar()
269b9c1b51eSKate Stone                              .ULongLong();
27035005f76SSean Callanan 
271b9c1b51eSKate Stone       if (!m_persistent_variable_sp->m_live_sp) {
272b9c1b51eSKate Stone         err.SetErrorStringWithFormat(
273b9c1b51eSKate Stone             "couldn't find the memory area used to store %s",
274b9c1b51eSKate Stone             m_persistent_variable_sp->GetName().GetCString());
27535005f76SSean Callanan         return;
27635005f76SSean Callanan       }
27735005f76SSean Callanan 
278b9c1b51eSKate Stone       if (m_persistent_variable_sp->m_live_sp->GetValue()
279b9c1b51eSKate Stone               .GetValueAddressType() != eAddressTypeLoad) {
280b9c1b51eSKate Stone         err.SetErrorStringWithFormat(
281b9c1b51eSKate Stone             "the address of the memory area for %s is in an incorrect format",
282b9c1b51eSKate Stone             m_persistent_variable_sp->GetName().GetCString());
28335005f76SSean Callanan         return;
28435005f76SSean Callanan       }
28535005f76SSean Callanan 
286b9c1b51eSKate Stone       if (m_persistent_variable_sp->m_flags &
287b9c1b51eSKate Stone               ExpressionVariable::EVNeedsFreezeDry ||
288b9c1b51eSKate Stone           m_persistent_variable_sp->m_flags &
289b9c1b51eSKate Stone               ExpressionVariable::EVKeepInTarget) {
29063e5fb76SJonas Devlieghere         LLDB_LOGF(log, "Dematerializing %s from 0x%" PRIx64 " (size = %llu)",
29163e5fb76SJonas Devlieghere                   m_persistent_variable_sp->GetName().GetCString(),
29263e5fb76SJonas Devlieghere                   (uint64_t)mem,
293113f56fbSAdrian Prantl                   (unsigned long long)m_persistent_variable_sp->GetByteSize()
294aa88161bSKazu Hirata                       .value_or(0));
29535005f76SSean Callanan 
29635005f76SSean Callanan         // Read the contents of the spare memory area
29735005f76SSean Callanan 
29835005f76SSean Callanan         m_persistent_variable_sp->ValueUpdated();
29935005f76SSean Callanan 
30097206d57SZachary Turner         Status read_error;
30135005f76SSean Callanan 
302b9c1b51eSKate Stone         map.ReadMemory(m_persistent_variable_sp->GetValueBytes(), mem,
303aa88161bSKazu Hirata                        m_persistent_variable_sp->GetByteSize().value_or(0),
304aa88161bSKazu Hirata                        read_error);
30535005f76SSean Callanan 
306b9c1b51eSKate Stone         if (!read_error.Success()) {
307b9c1b51eSKate Stone           err.SetErrorStringWithFormat(
308b9c1b51eSKate Stone               "couldn't read the contents of %s from memory: %s",
309b9c1b51eSKate Stone               m_persistent_variable_sp->GetName().GetCString(),
310b9c1b51eSKate Stone               read_error.AsCString());
31135005f76SSean Callanan           return;
31235005f76SSean Callanan         }
31335005f76SSean Callanan 
314b9c1b51eSKate Stone         m_persistent_variable_sp->m_flags &=
315b9c1b51eSKate Stone             ~ExpressionVariable::EVNeedsFreezeDry;
31635005f76SSean Callanan       }
317b9c1b51eSKate Stone     } else {
318b9c1b51eSKate Stone       err.SetErrorStringWithFormat(
319b9c1b51eSKate Stone           "no dematerialization happened for persistent variable %s",
320b9c1b51eSKate Stone           m_persistent_variable_sp->GetName().AsCString());
32135005f76SSean Callanan       return;
32235005f76SSean Callanan     }
32335005f76SSean Callanan 
324b9c1b51eSKate Stone     lldb::ProcessSP process_sp =
325b9c1b51eSKate Stone         map.GetBestExecutionContextScope()->CalculateProcess();
326b9c1b51eSKate Stone     if (!process_sp || !process_sp->CanJIT()) {
327b9c1b51eSKate Stone       // Allocations are not persistent so persistent variables cannot stay
328b9c1b51eSKate Stone       // materialized.
3292afbf444SSean Callanan 
330b9c1b51eSKate Stone       m_persistent_variable_sp->m_flags |=
331b9c1b51eSKate Stone           ExpressionVariable::EVNeedsAllocation;
3322afbf444SSean Callanan 
3332afbf444SSean Callanan       DestroyAllocation(map, err);
3342afbf444SSean Callanan       if (!err.Success())
3352afbf444SSean Callanan         return;
336b9c1b51eSKate Stone     } else if (m_persistent_variable_sp->m_flags &
337b9c1b51eSKate Stone                    ExpressionVariable::EVNeedsAllocation &&
338b9c1b51eSKate Stone                !(m_persistent_variable_sp->m_flags &
339b9c1b51eSKate Stone                  ExpressionVariable::EVKeepInTarget)) {
34035005f76SSean Callanan       DestroyAllocation(map, err);
34135005f76SSean Callanan       if (!err.Success())
34235005f76SSean Callanan         return;
34335005f76SSean Callanan     }
34496d2730aSSean Callanan   }
3452d37e5a5SSean Callanan 
DumpToLog(IRMemoryMap & map,lldb::addr_t process_address,Log * log)346b9c1b51eSKate Stone   void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
347b9c1b51eSKate Stone                  Log *log) override {
3482d37e5a5SSean Callanan     StreamString dump_stream;
3492d37e5a5SSean Callanan 
35097206d57SZachary Turner     Status err;
3512d37e5a5SSean Callanan 
35257ee3067SGreg Clayton     const lldb::addr_t load_addr = process_address + m_offset;
35357ee3067SGreg Clayton 
354b9c1b51eSKate Stone     dump_stream.Printf("0x%" PRIx64 ": EntityPersistentVariable (%s)\n",
355b9c1b51eSKate Stone                        load_addr,
356b9c1b51eSKate Stone                        m_persistent_variable_sp->GetName().AsCString());
3572d37e5a5SSean Callanan 
3582d37e5a5SSean Callanan     {
3592d37e5a5SSean Callanan       dump_stream.Printf("Pointer:\n");
3602d37e5a5SSean Callanan 
3612d37e5a5SSean Callanan       DataBufferHeap data(m_size, 0);
3622d37e5a5SSean Callanan 
36357ee3067SGreg Clayton       map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
3642d37e5a5SSean Callanan 
365b9c1b51eSKate Stone       if (!err.Success()) {
3662d37e5a5SSean Callanan         dump_stream.Printf("  <could not be read>\n");
367b9c1b51eSKate Stone       } else {
36829cb868aSZachary Turner         DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
36929cb868aSZachary Turner                      load_addr);
37014b1bae5SSean Callanan 
37114b1bae5SSean Callanan         dump_stream.PutChar('\n');
3722d37e5a5SSean Callanan       }
3732d37e5a5SSean Callanan     }
3742d37e5a5SSean Callanan 
3752d37e5a5SSean Callanan     {
3762d37e5a5SSean Callanan       dump_stream.Printf("Target:\n");
3772d37e5a5SSean Callanan 
3782d37e5a5SSean Callanan       lldb::addr_t target_address;
3792d37e5a5SSean Callanan 
38057ee3067SGreg Clayton       map.ReadPointerFromMemory(&target_address, load_addr, err);
3812d37e5a5SSean Callanan 
382b9c1b51eSKate Stone       if (!err.Success()) {
3832d37e5a5SSean Callanan         dump_stream.Printf("  <could not be read>\n");
384b9c1b51eSKate Stone       } else {
385aa88161bSKazu Hirata         DataBufferHeap data(m_persistent_variable_sp->GetByteSize().value_or(0),
386aa88161bSKazu Hirata                             0);
3872d37e5a5SSean Callanan 
388b9c1b51eSKate Stone         map.ReadMemory(data.GetBytes(), target_address,
389aa88161bSKazu Hirata                        m_persistent_variable_sp->GetByteSize().value_or(0),
390aa88161bSKazu Hirata                        err);
3912d37e5a5SSean Callanan 
392b9c1b51eSKate Stone         if (!err.Success()) {
3932d37e5a5SSean Callanan           dump_stream.Printf("  <could not be read>\n");
394b9c1b51eSKate Stone         } else {
39529cb868aSZachary Turner           DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
39629cb868aSZachary Turner                        target_address);
39714b1bae5SSean Callanan 
39814b1bae5SSean Callanan           dump_stream.PutChar('\n');
3992d37e5a5SSean Callanan         }
4002d37e5a5SSean Callanan       }
4012d37e5a5SSean Callanan     }
4022d37e5a5SSean Callanan 
403c156427dSZachary Turner     log->PutString(dump_stream.GetString());
4042d37e5a5SSean Callanan   }
4052d37e5a5SSean Callanan 
Wipe(IRMemoryMap & map,lldb::addr_t process_address)406b9c1b51eSKate Stone   void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {}
407315b6884SEugene Zelenko 
40896d2730aSSean Callanan private:
409bc8ac34eSSean Callanan   lldb::ExpressionVariableSP m_persistent_variable_sp;
4109fda9d21SSean Callanan   Materializer::PersistentVariableDelegate *m_delegate;
41196d2730aSSean Callanan };
41296d2730aSSean Callanan 
AddPersistentVariable(lldb::ExpressionVariableSP & persistent_variable_sp,PersistentVariableDelegate * delegate,Status & err)413b9c1b51eSKate Stone uint32_t Materializer::AddPersistentVariable(
414b9c1b51eSKate Stone     lldb::ExpressionVariableSP &persistent_variable_sp,
41597206d57SZachary Turner     PersistentVariableDelegate *delegate, Status &err) {
41696d2730aSSean Callanan   EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
41706412daeSJonas Devlieghere   *iter = std::make_unique<EntityPersistentVariable>(persistent_variable_sp,
41806412daeSJonas Devlieghere                                                      delegate);
41996d2730aSSean Callanan   uint32_t ret = AddStructMember(**iter);
42096d2730aSSean Callanan   (*iter)->SetOffset(ret);
42196d2730aSSean Callanan   return ret;
42296d2730aSSean Callanan }
42396d2730aSSean Callanan 
424*317c8bf8SMichael Buch /// Base class for materialization of Variables and ValueObjects.
425*317c8bf8SMichael Buch ///
426*317c8bf8SMichael Buch /// Subclasses specify how to obtain the Value which is to be
427*317c8bf8SMichael Buch /// materialized.
428*317c8bf8SMichael Buch class EntityVariableBase : public Materializer::Entity {
42996d2730aSSean Callanan public:
430*317c8bf8SMichael Buch   virtual ~EntityVariableBase() = default;
431*317c8bf8SMichael Buch 
EntityVariableBase()432*317c8bf8SMichael Buch   EntityVariableBase() {
433b9c1b51eSKate Stone     // Hard-coding to maximum size of a pointer since all variables are
434b9c1b51eSKate Stone     // materialized by reference
435fcf4e252SMichael Buch     m_size = g_default_var_byte_size;
436fcf4e252SMichael Buch     m_alignment = g_default_var_alignment;
43796d2730aSSean Callanan   }
43896d2730aSSean Callanan 
Materialize(lldb::StackFrameSP & frame_sp,IRMemoryMap & map,lldb::addr_t process_address,Status & err)439b9c1b51eSKate Stone   void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
44097206d57SZachary Turner                    lldb::addr_t process_address, Status &err) override {
441a007a6d8SPavel Labath     Log *log = GetLog(LLDBLog::Expressions);
442f8043fa5SSean Callanan 
44357ee3067SGreg Clayton     const lldb::addr_t load_addr = process_address + m_offset;
444b9c1b51eSKate Stone     if (log) {
44563e5fb76SJonas Devlieghere       LLDB_LOGF(log,
44663e5fb76SJonas Devlieghere                 "EntityVariable::Materialize [address = 0x%" PRIx64
447b9c1b51eSKate Stone                 ", m_variable_sp = %s]",
448*317c8bf8SMichael Buch                 (uint64_t)load_addr, GetName().GetCString());
449f8043fa5SSean Callanan     }
450f8043fa5SSean Callanan 
451b024d878SSean Callanan     ExecutionContextScope *scope = frame_sp.get();
452b024d878SSean Callanan 
453b024d878SSean Callanan     if (!scope)
454b024d878SSean Callanan       scope = map.GetBestExecutionContextScope();
455b024d878SSean Callanan 
456*317c8bf8SMichael Buch     lldb::ValueObjectSP valobj_sp = SetupValueObject(scope);
457f8043fa5SSean Callanan 
458b9c1b51eSKate Stone     if (!valobj_sp) {
459b9c1b51eSKate Stone       err.SetErrorStringWithFormat(
460*317c8bf8SMichael Buch           "couldn't get a value object for variable %s", GetName().AsCString());
461f8043fa5SSean Callanan       return;
462f8043fa5SSean Callanan     }
463f8043fa5SSean Callanan 
46497206d57SZachary Turner     Status valobj_error = valobj_sp->GetError();
465866e91c9SSean Callanan 
466b9c1b51eSKate Stone     if (valobj_error.Fail()) {
467b9c1b51eSKate Stone       err.SetErrorStringWithFormat("couldn't get the value of variable %s: %s",
468*317c8bf8SMichael Buch                                    GetName().AsCString(),
469b9c1b51eSKate Stone                                    valobj_error.AsCString());
470866e91c9SSean Callanan       return;
471866e91c9SSean Callanan     }
472866e91c9SSean Callanan 
473b9c1b51eSKate Stone     if (m_is_reference) {
474f8043fa5SSean Callanan       DataExtractor valobj_extractor;
47597206d57SZachary Turner       Status extract_error;
476866e91c9SSean Callanan       valobj_sp->GetData(valobj_extractor, extract_error);
477866e91c9SSean Callanan 
478b9c1b51eSKate Stone       if (!extract_error.Success()) {
479b9c1b51eSKate Stone         err.SetErrorStringWithFormat(
480b9c1b51eSKate Stone             "couldn't read contents of reference variable %s: %s",
481*317c8bf8SMichael Buch             GetName().AsCString(), extract_error.AsCString());
482866e91c9SSean Callanan         return;
483866e91c9SSean Callanan       }
484866e91c9SSean Callanan 
485f8043fa5SSean Callanan       lldb::offset_t offset = 0;
486f8043fa5SSean Callanan       lldb::addr_t reference_addr = valobj_extractor.GetAddress(&offset);
487f8043fa5SSean Callanan 
48897206d57SZachary Turner       Status write_error;
48957ee3067SGreg Clayton       map.WritePointerToMemory(load_addr, reference_addr, write_error);
490f8043fa5SSean Callanan 
491b9c1b51eSKate Stone       if (!write_error.Success()) {
492b9c1b51eSKate Stone         err.SetErrorStringWithFormat("couldn't write the contents of reference "
493b9c1b51eSKate Stone                                      "variable %s to memory: %s",
494*317c8bf8SMichael Buch                                      GetName().AsCString(),
495b9c1b51eSKate Stone                                      write_error.AsCString());
496f8043fa5SSean Callanan         return;
497f8043fa5SSean Callanan       }
498b9c1b51eSKate Stone     } else {
49965b320f7SSean Callanan       AddressType address_type = eAddressTypeInvalid;
50065b320f7SSean Callanan       const bool scalar_is_load_address = false;
501b9c1b51eSKate Stone       lldb::addr_t addr_of_valobj =
502b9c1b51eSKate Stone           valobj_sp->GetAddressOf(scalar_is_load_address, &address_type);
503b9c1b51eSKate Stone       if (addr_of_valobj != LLDB_INVALID_ADDRESS) {
50497206d57SZachary Turner         Status write_error;
50513b4ef2dSSean Callanan         map.WritePointerToMemory(load_addr, addr_of_valobj, write_error);
506f8043fa5SSean Callanan 
507b9c1b51eSKate Stone         if (!write_error.Success()) {
508b9c1b51eSKate Stone           err.SetErrorStringWithFormat(
509b9c1b51eSKate Stone               "couldn't write the address of variable %s to memory: %s",
510*317c8bf8SMichael Buch               GetName().AsCString(), write_error.AsCString());
511f8043fa5SSean Callanan           return;
512f8043fa5SSean Callanan         }
513b9c1b51eSKate Stone       } else {
514f8043fa5SSean Callanan         DataExtractor data;
51597206d57SZachary Turner         Status extract_error;
516866e91c9SSean Callanan         valobj_sp->GetData(data, extract_error);
517b9c1b51eSKate Stone         if (!extract_error.Success()) {
518b9c1b51eSKate Stone           err.SetErrorStringWithFormat("couldn't get the value of %s: %s",
519*317c8bf8SMichael Buch                                        GetName().AsCString(),
520b9c1b51eSKate Stone                                        extract_error.AsCString());
521b9c1b51eSKate Stone           return;
522b9c1b51eSKate Stone         }
523b9c1b51eSKate Stone 
524b9c1b51eSKate Stone         if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
525b9c1b51eSKate Stone           err.SetErrorStringWithFormat(
526b9c1b51eSKate Stone               "trying to create a temporary region for %s but one exists",
527*317c8bf8SMichael Buch               GetName().AsCString());
528b9c1b51eSKate Stone           return;
529b9c1b51eSKate Stone         }
530b9c1b51eSKate Stone 
531*317c8bf8SMichael Buch         if (data.GetByteSize() < GetByteSize(scope)) {
532*317c8bf8SMichael Buch           if (data.GetByteSize() == 0 && !LocationExpressionIsValid()) {
533b9c1b51eSKate Stone             err.SetErrorStringWithFormat("the variable '%s' has no location, "
534b9c1b51eSKate Stone                                          "it may have been optimized out",
535*317c8bf8SMichael Buch                                          GetName().AsCString());
536b9c1b51eSKate Stone           } else {
537b9c1b51eSKate Stone             err.SetErrorStringWithFormat(
538b9c1b51eSKate Stone                 "size of variable %s (%" PRIu64
539b9c1b51eSKate Stone                 ") is larger than the ValueObject's size (%" PRIu64 ")",
540*317c8bf8SMichael Buch                 GetName().AsCString(), GetByteSize(scope).value_or(0),
541d13777aaSAdrian Prantl                 data.GetByteSize());
5429e9f219aSGreg Clayton           }
543f8043fa5SSean Callanan           return;
544f8043fa5SSean Callanan         }
545f8043fa5SSean Callanan 
546*317c8bf8SMichael Buch         llvm::Optional<size_t> opt_bit_align = GetTypeBitAlign(scope);
54736f13e49SDavide Italiano         if (!opt_bit_align) {
54836f13e49SDavide Italiano           err.SetErrorStringWithFormat("can't get the type alignment for %s",
549*317c8bf8SMichael Buch                                        GetName().AsCString());
55036f13e49SDavide Italiano           return;
55136f13e49SDavide Italiano         }
552f8043fa5SSean Callanan 
55336f13e49SDavide Italiano         size_t byte_align = (*opt_bit_align + 7) / 8;
55422ac610cSSean Callanan 
55597206d57SZachary Turner         Status alloc_error;
5562c381414SJim Ingham         const bool zero_memory = false;
557f8043fa5SSean Callanan 
558b9c1b51eSKate Stone         m_temporary_allocation = map.Malloc(
559b9c1b51eSKate Stone             data.GetByteSize(), byte_align,
5602c381414SJim Ingham             lldb::ePermissionsReadable | lldb::ePermissionsWritable,
561b9c1b51eSKate Stone             IRMemoryMap::eAllocationPolicyMirror, zero_memory, alloc_error);
5622c381414SJim Ingham 
5632d37e5a5SSean Callanan         m_temporary_allocation_size = data.GetByteSize();
564f8043fa5SSean Callanan 
565796ac80bSJonas Devlieghere         m_original_data = std::make_shared<DataBufferHeap>(data.GetDataStart(),
566796ac80bSJonas Devlieghere                                                            data.GetByteSize());
567c4ca2c1dSSean Callanan 
568b9c1b51eSKate Stone         if (!alloc_error.Success()) {
569b9c1b51eSKate Stone           err.SetErrorStringWithFormat(
570b9c1b51eSKate Stone               "couldn't allocate a temporary region for %s: %s",
571*317c8bf8SMichael Buch               GetName().AsCString(), alloc_error.AsCString());
572f8043fa5SSean Callanan           return;
573f8043fa5SSean Callanan         }
574f8043fa5SSean Callanan 
57597206d57SZachary Turner         Status write_error;
576f8043fa5SSean Callanan 
577b9c1b51eSKate Stone         map.WriteMemory(m_temporary_allocation, data.GetDataStart(),
578b9c1b51eSKate Stone                         data.GetByteSize(), write_error);
579f8043fa5SSean Callanan 
580b9c1b51eSKate Stone         if (!write_error.Success()) {
581b9c1b51eSKate Stone           err.SetErrorStringWithFormat(
582b9c1b51eSKate Stone               "couldn't write to the temporary region for %s: %s",
583*317c8bf8SMichael Buch               GetName().AsCString(), write_error.AsCString());
584f8043fa5SSean Callanan           return;
585f8043fa5SSean Callanan         }
586f8043fa5SSean Callanan 
58797206d57SZachary Turner         Status pointer_write_error;
588f8043fa5SSean Callanan 
589b9c1b51eSKate Stone         map.WritePointerToMemory(load_addr, m_temporary_allocation,
590b9c1b51eSKate Stone                                  pointer_write_error);
591f8043fa5SSean Callanan 
592b9c1b51eSKate Stone         if (!pointer_write_error.Success()) {
593b9c1b51eSKate Stone           err.SetErrorStringWithFormat(
594b9c1b51eSKate Stone               "couldn't write the address of the temporary region for %s: %s",
595*317c8bf8SMichael Buch               GetName().AsCString(), pointer_write_error.AsCString());
596f8043fa5SSean Callanan         }
597f8043fa5SSean Callanan       }
598f8043fa5SSean Callanan     }
59996d2730aSSean Callanan   }
60096d2730aSSean Callanan 
Dematerialize(lldb::StackFrameSP & frame_sp,IRMemoryMap & map,lldb::addr_t process_address,lldb::addr_t frame_top,lldb::addr_t frame_bottom,Status & err)601b9c1b51eSKate Stone   void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
602b9c1b51eSKate Stone                      lldb::addr_t process_address, lldb::addr_t frame_top,
60397206d57SZachary Turner                      lldb::addr_t frame_bottom, Status &err) override {
604a007a6d8SPavel Labath     Log *log = GetLog(LLDBLog::Expressions);
605f8043fa5SSean Callanan 
60657ee3067SGreg Clayton     const lldb::addr_t load_addr = process_address + m_offset;
607b9c1b51eSKate Stone     if (log) {
60863e5fb76SJonas Devlieghere       LLDB_LOGF(log,
60963e5fb76SJonas Devlieghere                 "EntityVariable::Dematerialize [address = 0x%" PRIx64
610b9c1b51eSKate Stone                 ", m_variable_sp = %s]",
611*317c8bf8SMichael Buch                 (uint64_t)load_addr, GetName().AsCString());
612f8043fa5SSean Callanan     }
613f8043fa5SSean Callanan 
614b9c1b51eSKate Stone     if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
615b024d878SSean Callanan       ExecutionContextScope *scope = frame_sp.get();
616b024d878SSean Callanan 
617b024d878SSean Callanan       if (!scope)
618b024d878SSean Callanan         scope = map.GetBestExecutionContextScope();
619b024d878SSean Callanan 
620*317c8bf8SMichael Buch       lldb::ValueObjectSP valobj_sp = SetupValueObject(scope);
621f8043fa5SSean Callanan 
622b9c1b51eSKate Stone       if (!valobj_sp) {
623b9c1b51eSKate Stone         err.SetErrorStringWithFormat(
624b9c1b51eSKate Stone             "couldn't get a value object for variable %s",
625*317c8bf8SMichael Buch             GetName().AsCString());
626f8043fa5SSean Callanan         return;
627f8043fa5SSean Callanan       }
628f8043fa5SSean Callanan 
629458ae1c6SSean Callanan       lldb_private::DataExtractor data;
630458ae1c6SSean Callanan 
63197206d57SZachary Turner       Status extract_error;
632458ae1c6SSean Callanan 
633113f56fbSAdrian Prantl       map.GetMemoryData(data, m_temporary_allocation,
634aa88161bSKazu Hirata                         valobj_sp->GetByteSize().value_or(0), extract_error);
635458ae1c6SSean Callanan 
636b9c1b51eSKate Stone       if (!extract_error.Success()) {
637b9c1b51eSKate Stone         err.SetErrorStringWithFormat("couldn't get the data for variable %s",
638*317c8bf8SMichael Buch                                      GetName().AsCString());
639458ae1c6SSean Callanan         return;
640458ae1c6SSean Callanan       }
641458ae1c6SSean Callanan 
642c4ca2c1dSSean Callanan       bool actually_write = true;
643c4ca2c1dSSean Callanan 
644b9c1b51eSKate Stone       if (m_original_data) {
645c4ca2c1dSSean Callanan         if ((data.GetByteSize() == m_original_data->GetByteSize()) &&
646b9c1b51eSKate Stone             !memcmp(m_original_data->GetBytes(), data.GetDataStart(),
647b9c1b51eSKate Stone                     data.GetByteSize())) {
648c4ca2c1dSSean Callanan           actually_write = false;
649c4ca2c1dSSean Callanan         }
650c4ca2c1dSSean Callanan       }
651c4ca2c1dSSean Callanan 
65297206d57SZachary Turner       Status set_error;
653458ae1c6SSean Callanan 
654b9c1b51eSKate Stone       if (actually_write) {
655458ae1c6SSean Callanan         valobj_sp->SetData(data, set_error);
656458ae1c6SSean Callanan 
657b9c1b51eSKate Stone         if (!set_error.Success()) {
658b9c1b51eSKate Stone           err.SetErrorStringWithFormat(
659b9c1b51eSKate Stone               "couldn't write the new contents of %s back into the variable",
660*317c8bf8SMichael Buch               GetName().AsCString());
661458ae1c6SSean Callanan           return;
662458ae1c6SSean Callanan         }
663c4ca2c1dSSean Callanan       }
664f8043fa5SSean Callanan 
66597206d57SZachary Turner       Status free_error;
666f8043fa5SSean Callanan 
667f8043fa5SSean Callanan       map.Free(m_temporary_allocation, free_error);
668f8043fa5SSean Callanan 
669b9c1b51eSKate Stone       if (!free_error.Success()) {
670b9c1b51eSKate Stone         err.SetErrorStringWithFormat(
671b9c1b51eSKate Stone             "couldn't free the temporary region for %s: %s",
672*317c8bf8SMichael Buch             GetName().AsCString(), free_error.AsCString());
673f8043fa5SSean Callanan         return;
674f8043fa5SSean Callanan       }
675f8043fa5SSean Callanan 
676c4ca2c1dSSean Callanan       m_original_data.reset();
677f8043fa5SSean Callanan       m_temporary_allocation = LLDB_INVALID_ADDRESS;
6782d37e5a5SSean Callanan       m_temporary_allocation_size = 0;
679f8043fa5SSean Callanan     }
68096d2730aSSean Callanan   }
6812d37e5a5SSean Callanan 
DumpToLog(IRMemoryMap & map,lldb::addr_t process_address,Log * log)682b9c1b51eSKate Stone   void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
683b9c1b51eSKate Stone                  Log *log) override {
6842d37e5a5SSean Callanan     StreamString dump_stream;
6852d37e5a5SSean Callanan 
68657ee3067SGreg Clayton     const lldb::addr_t load_addr = process_address + m_offset;
68757ee3067SGreg Clayton     dump_stream.Printf("0x%" PRIx64 ": EntityVariable\n", load_addr);
6881582ee68SSean Callanan 
68997206d57SZachary Turner     Status err;
6902d37e5a5SSean Callanan 
6911582ee68SSean Callanan     lldb::addr_t ptr = LLDB_INVALID_ADDRESS;
6922d37e5a5SSean Callanan 
6932d37e5a5SSean Callanan     {
6942d37e5a5SSean Callanan       dump_stream.Printf("Pointer:\n");
6952d37e5a5SSean Callanan 
6962d37e5a5SSean Callanan       DataBufferHeap data(m_size, 0);
6972d37e5a5SSean Callanan 
69857ee3067SGreg Clayton       map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
6992d37e5a5SSean Callanan 
700b9c1b51eSKate Stone       if (!err.Success()) {
7012d37e5a5SSean Callanan         dump_stream.Printf("  <could not be read>\n");
702b9c1b51eSKate Stone       } else {
703b9c1b51eSKate Stone         DataExtractor extractor(data.GetBytes(), data.GetByteSize(),
704b9c1b51eSKate Stone                                 map.GetByteOrder(), map.GetAddressByteSize());
7052d37e5a5SSean Callanan 
70629cb868aSZachary Turner         DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
70729cb868aSZachary Turner                      load_addr);
70814b1bae5SSean Callanan 
709dcd0926aSPavel Labath         lldb::offset_t offset = 0;
7101582ee68SSean Callanan 
7110863f675SPavel Labath         ptr = extractor.GetAddress(&offset);
7121582ee68SSean Callanan 
71314b1bae5SSean Callanan         dump_stream.PutChar('\n');
7142d37e5a5SSean Callanan       }
7152d37e5a5SSean Callanan     }
7162d37e5a5SSean Callanan 
717b9c1b51eSKate Stone     if (m_temporary_allocation == LLDB_INVALID_ADDRESS) {
7181582ee68SSean Callanan       dump_stream.Printf("Points to process memory:\n");
719b9c1b51eSKate Stone     } else {
7202d37e5a5SSean Callanan       dump_stream.Printf("Temporary allocation:\n");
7211582ee68SSean Callanan     }
7222d37e5a5SSean Callanan 
723b9c1b51eSKate Stone     if (ptr == LLDB_INVALID_ADDRESS) {
7241582ee68SSean Callanan       dump_stream.Printf("  <could not be be found>\n");
725b9c1b51eSKate Stone     } else {
7262d37e5a5SSean Callanan       DataBufferHeap data(m_temporary_allocation_size, 0);
7272d37e5a5SSean Callanan 
728b9c1b51eSKate Stone       map.ReadMemory(data.GetBytes(), m_temporary_allocation,
729b9c1b51eSKate Stone                      m_temporary_allocation_size, err);
7302d37e5a5SSean Callanan 
731b9c1b51eSKate Stone       if (!err.Success()) {
7322d37e5a5SSean Callanan         dump_stream.Printf("  <could not be read>\n");
733b9c1b51eSKate Stone       } else {
73429cb868aSZachary Turner         DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
73529cb868aSZachary Turner                      load_addr);
73614b1bae5SSean Callanan 
73714b1bae5SSean Callanan         dump_stream.PutChar('\n');
7382d37e5a5SSean Callanan       }
7392d37e5a5SSean Callanan     }
7402d37e5a5SSean Callanan 
741c156427dSZachary Turner     log->PutString(dump_stream.GetString());
7422d37e5a5SSean Callanan   }
74314b1bae5SSean Callanan 
Wipe(IRMemoryMap & map,lldb::addr_t process_address)744b9c1b51eSKate Stone   void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {
745b9c1b51eSKate Stone     if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
74697206d57SZachary Turner       Status free_error;
74714b1bae5SSean Callanan 
74814b1bae5SSean Callanan       map.Free(m_temporary_allocation, free_error);
74914b1bae5SSean Callanan 
75014b1bae5SSean Callanan       m_temporary_allocation = LLDB_INVALID_ADDRESS;
75114b1bae5SSean Callanan       m_temporary_allocation_size = 0;
75214b1bae5SSean Callanan     }
75314b1bae5SSean Callanan   }
754315b6884SEugene Zelenko 
75596d2730aSSean Callanan private:
756*317c8bf8SMichael Buch   virtual ConstString GetName() const = 0;
757*317c8bf8SMichael Buch 
758*317c8bf8SMichael Buch   /// Creates and returns ValueObject tied to this variable
759*317c8bf8SMichael Buch   /// and prepares Entity for materialization.
760*317c8bf8SMichael Buch   ///
761*317c8bf8SMichael Buch   /// Called each time the Materializer (de)materializes a
762*317c8bf8SMichael Buch   /// variable. We re-create the ValueObject based on the
763*317c8bf8SMichael Buch   /// current ExecutionContextScope since clients such as
764*317c8bf8SMichael Buch   /// conditional breakpoints may materialize the same
765*317c8bf8SMichael Buch   /// EntityVariable multiple times with different frames.
766*317c8bf8SMichael Buch   ///
767*317c8bf8SMichael Buch   /// Each subsequent use of the EntityVariableBase interface
768*317c8bf8SMichael Buch   /// will query the newly created ValueObject until this
769*317c8bf8SMichael Buch   /// function is called again.
770*317c8bf8SMichael Buch   virtual lldb::ValueObjectSP
771*317c8bf8SMichael Buch   SetupValueObject(ExecutionContextScope *scope) = 0;
772*317c8bf8SMichael Buch 
773*317c8bf8SMichael Buch   /// Returns size in bytes of the type associated with this variable
774*317c8bf8SMichael Buch   ///
775*317c8bf8SMichael Buch   /// \returns On success, returns byte size of the type associated
776*317c8bf8SMichael Buch   ///          with this variable. Returns NoneType otherwise.
777*317c8bf8SMichael Buch   virtual llvm::Optional<uint64_t>
778*317c8bf8SMichael Buch   GetByteSize(ExecutionContextScope *scope) const = 0;
779*317c8bf8SMichael Buch 
780*317c8bf8SMichael Buch   /// Returns 'true' if the location expression associated with this variable
781*317c8bf8SMichael Buch   /// is valid.
782*317c8bf8SMichael Buch   virtual bool LocationExpressionIsValid() const = 0;
783*317c8bf8SMichael Buch 
784*317c8bf8SMichael Buch   /// Returns alignment of the type associated with this variable in bits.
785*317c8bf8SMichael Buch   ///
786*317c8bf8SMichael Buch   /// \returns On success, returns alignment in bits for the type associated
787*317c8bf8SMichael Buch   ///          with this variable. Returns NoneType otherwise.
788*317c8bf8SMichael Buch   virtual llvm::Optional<size_t>
789*317c8bf8SMichael Buch   GetTypeBitAlign(ExecutionContextScope *scope) const = 0;
790*317c8bf8SMichael Buch 
791*317c8bf8SMichael Buch protected:
79228c878aeSShafik Yaghmour   bool m_is_reference = false;
79328c878aeSShafik Yaghmour   lldb::addr_t m_temporary_allocation = LLDB_INVALID_ADDRESS;
79428c878aeSShafik Yaghmour   size_t m_temporary_allocation_size = 0;
795c4ca2c1dSSean Callanan   lldb::DataBufferSP m_original_data;
79696d2730aSSean Callanan };
79796d2730aSSean Callanan 
798*317c8bf8SMichael Buch /// Represents an Entity constructed from a VariableSP.
799*317c8bf8SMichael Buch ///
800*317c8bf8SMichael Buch /// This class is used for materialization of variables for which
801*317c8bf8SMichael Buch /// the user has a VariableSP on hand. The ValueObject is then
802*317c8bf8SMichael Buch /// derived from the associated DWARF location expression when needed
803*317c8bf8SMichael Buch /// by the Materializer.
804*317c8bf8SMichael Buch class EntityVariable : public EntityVariableBase {
805*317c8bf8SMichael Buch public:
EntityVariable(lldb::VariableSP & variable_sp)806*317c8bf8SMichael Buch   EntityVariable(lldb::VariableSP &variable_sp) : m_variable_sp(variable_sp) {
807*317c8bf8SMichael Buch     m_is_reference =
808*317c8bf8SMichael Buch         m_variable_sp->GetType()->GetForwardCompilerType().IsReferenceType();
809*317c8bf8SMichael Buch   }
810*317c8bf8SMichael Buch 
GetName() const811*317c8bf8SMichael Buch   ConstString GetName() const override { return m_variable_sp->GetName(); }
812*317c8bf8SMichael Buch 
SetupValueObject(ExecutionContextScope * scope)813*317c8bf8SMichael Buch   lldb::ValueObjectSP SetupValueObject(ExecutionContextScope *scope) override {
814*317c8bf8SMichael Buch     assert(m_variable_sp != nullptr);
815*317c8bf8SMichael Buch     return ValueObjectVariable::Create(scope, m_variable_sp);
816*317c8bf8SMichael Buch   }
817*317c8bf8SMichael Buch 
818*317c8bf8SMichael Buch   llvm::Optional<uint64_t>
GetByteSize(ExecutionContextScope * scope) const819*317c8bf8SMichael Buch   GetByteSize(ExecutionContextScope *scope) const override {
820*317c8bf8SMichael Buch     return m_variable_sp->GetType()->GetByteSize(scope);
821*317c8bf8SMichael Buch   }
822*317c8bf8SMichael Buch 
LocationExpressionIsValid() const823*317c8bf8SMichael Buch   bool LocationExpressionIsValid() const override {
824*317c8bf8SMichael Buch     return m_variable_sp->LocationExpressionList().IsValid();
825*317c8bf8SMichael Buch   }
826*317c8bf8SMichael Buch 
827*317c8bf8SMichael Buch   llvm::Optional<size_t>
GetTypeBitAlign(ExecutionContextScope * scope) const828*317c8bf8SMichael Buch   GetTypeBitAlign(ExecutionContextScope *scope) const override {
829*317c8bf8SMichael Buch     return m_variable_sp->GetType()->GetLayoutCompilerType().GetTypeBitAlign(
830*317c8bf8SMichael Buch         scope);
831*317c8bf8SMichael Buch   }
832*317c8bf8SMichael Buch 
833*317c8bf8SMichael Buch private:
834*317c8bf8SMichael Buch   lldb::VariableSP m_variable_sp; ///< Variable that this entity is based on.
835*317c8bf8SMichael Buch };
836*317c8bf8SMichael Buch 
837*317c8bf8SMichael Buch /// Represents an Entity constructed from a VariableSP.
838*317c8bf8SMichael Buch ///
839*317c8bf8SMichael Buch /// This class is used for materialization of variables for
840*317c8bf8SMichael Buch /// which the user does not have a VariableSP available (e.g.,
841*317c8bf8SMichael Buch /// when materializing ivars).
842*317c8bf8SMichael Buch class EntityValueObject : public EntityVariableBase {
843*317c8bf8SMichael Buch public:
EntityValueObject(ConstString name,ValueObjectProviderTy provider)844*317c8bf8SMichael Buch   EntityValueObject(ConstString name, ValueObjectProviderTy provider)
845*317c8bf8SMichael Buch       : m_name(name), m_valobj_provider(std::move(provider)) {
846*317c8bf8SMichael Buch     assert(m_valobj_provider);
847*317c8bf8SMichael Buch   }
848*317c8bf8SMichael Buch 
GetName() const849*317c8bf8SMichael Buch   ConstString GetName() const override { return m_name; }
850*317c8bf8SMichael Buch 
SetupValueObject(ExecutionContextScope * scope)851*317c8bf8SMichael Buch   lldb::ValueObjectSP SetupValueObject(ExecutionContextScope *scope) override {
852*317c8bf8SMichael Buch     m_valobj_sp =
853*317c8bf8SMichael Buch         m_valobj_provider(GetName(), scope->CalculateStackFrame().get());
854*317c8bf8SMichael Buch 
855*317c8bf8SMichael Buch     if (m_valobj_sp)
856*317c8bf8SMichael Buch       m_is_reference = m_valobj_sp->GetCompilerType().IsReferenceType();
857*317c8bf8SMichael Buch 
858*317c8bf8SMichael Buch     return m_valobj_sp;
859*317c8bf8SMichael Buch   }
860*317c8bf8SMichael Buch 
861*317c8bf8SMichael Buch   llvm::Optional<uint64_t>
GetByteSize(ExecutionContextScope * scope) const862*317c8bf8SMichael Buch   GetByteSize(ExecutionContextScope *scope) const override {
863*317c8bf8SMichael Buch     if (m_valobj_sp)
864*317c8bf8SMichael Buch       return m_valobj_sp->GetCompilerType().GetByteSize(scope);
865*317c8bf8SMichael Buch 
866*317c8bf8SMichael Buch     return {};
867*317c8bf8SMichael Buch   }
868*317c8bf8SMichael Buch 
LocationExpressionIsValid() const869*317c8bf8SMichael Buch   bool LocationExpressionIsValid() const override {
870*317c8bf8SMichael Buch     if (m_valobj_sp)
871*317c8bf8SMichael Buch       return m_valobj_sp->GetError().Success();
872*317c8bf8SMichael Buch 
873*317c8bf8SMichael Buch     return false;
874*317c8bf8SMichael Buch   }
875*317c8bf8SMichael Buch 
876*317c8bf8SMichael Buch   llvm::Optional<size_t>
GetTypeBitAlign(ExecutionContextScope * scope) const877*317c8bf8SMichael Buch   GetTypeBitAlign(ExecutionContextScope *scope) const override {
878*317c8bf8SMichael Buch     if (m_valobj_sp)
879*317c8bf8SMichael Buch       return m_valobj_sp->GetCompilerType().GetTypeBitAlign(scope);
880*317c8bf8SMichael Buch 
881*317c8bf8SMichael Buch     return {};
882*317c8bf8SMichael Buch   }
883*317c8bf8SMichael Buch 
884*317c8bf8SMichael Buch private:
885*317c8bf8SMichael Buch   ConstString m_name;
886*317c8bf8SMichael Buch   lldb::ValueObjectSP m_valobj_sp;
887*317c8bf8SMichael Buch   ValueObjectProviderTy m_valobj_provider;
888*317c8bf8SMichael Buch };
889*317c8bf8SMichael Buch 
AddVariable(lldb::VariableSP & variable_sp,Status & err)89097206d57SZachary Turner uint32_t Materializer::AddVariable(lldb::VariableSP &variable_sp, Status &err) {
89196d2730aSSean Callanan   EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
89206412daeSJonas Devlieghere   *iter = std::make_unique<EntityVariable>(variable_sp);
89396d2730aSSean Callanan   uint32_t ret = AddStructMember(**iter);
89496d2730aSSean Callanan   (*iter)->SetOffset(ret);
89596d2730aSSean Callanan   return ret;
89696d2730aSSean Callanan }
89796d2730aSSean Callanan 
AddValueObject(ConstString name,ValueObjectProviderTy valobj_provider,Status & err)898*317c8bf8SMichael Buch uint32_t Materializer::AddValueObject(ConstString name,
899*317c8bf8SMichael Buch                                       ValueObjectProviderTy valobj_provider,
900*317c8bf8SMichael Buch                                       Status &err) {
901*317c8bf8SMichael Buch   assert(valobj_provider);
902*317c8bf8SMichael Buch   EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
903*317c8bf8SMichael Buch   *iter = std::make_unique<EntityValueObject>(name, std::move(valobj_provider));
904*317c8bf8SMichael Buch   uint32_t ret = AddStructMember(**iter);
905*317c8bf8SMichael Buch   (*iter)->SetOffset(ret);
906*317c8bf8SMichael Buch   return ret;
907*317c8bf8SMichael Buch }
908*317c8bf8SMichael Buch 
909b9c1b51eSKate Stone class EntityResultVariable : public Materializer::Entity {
91096d2730aSSean Callanan public:
EntityResultVariable(const CompilerType & type,bool is_program_reference,bool keep_in_memory,Materializer::PersistentVariableDelegate * delegate)911b9c1b51eSKate Stone   EntityResultVariable(const CompilerType &type, bool is_program_reference,
9129fda9d21SSean Callanan                        bool keep_in_memory,
913b9c1b51eSKate Stone                        Materializer::PersistentVariableDelegate *delegate)
914b9c1b51eSKate Stone       : Entity(), m_type(type), m_is_program_reference(is_program_reference),
91528c878aeSShafik Yaghmour         m_keep_in_memory(keep_in_memory), m_delegate(delegate) {
916b9c1b51eSKate Stone     // Hard-coding to maximum size of a pointer since all results are
917b9c1b51eSKate Stone     // materialized by reference
918fcf4e252SMichael Buch     m_size = g_default_var_byte_size;
919fcf4e252SMichael Buch     m_alignment = g_default_var_alignment;
92096d2730aSSean Callanan   }
92196d2730aSSean Callanan 
Materialize(lldb::StackFrameSP & frame_sp,IRMemoryMap & map,lldb::addr_t process_address,Status & err)922b9c1b51eSKate Stone   void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
92397206d57SZachary Turner                    lldb::addr_t process_address, Status &err) override {
924b9c1b51eSKate Stone     if (!m_is_program_reference) {
925b9c1b51eSKate Stone       if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
926b9c1b51eSKate Stone         err.SetErrorString("Trying to create a temporary region for the result "
927b9c1b51eSKate Stone                            "but one exists");
9281582ee68SSean Callanan         return;
9291582ee68SSean Callanan       }
9301582ee68SSean Callanan 
93157ee3067SGreg Clayton       const lldb::addr_t load_addr = process_address + m_offset;
93257ee3067SGreg Clayton 
9333728133dSAdrian Prantl       ExecutionContextScope *exe_scope = frame_sp.get();
9343728133dSAdrian Prantl       if (!exe_scope)
9353728133dSAdrian Prantl         exe_scope = map.GetBestExecutionContextScope();
936799a3fc6SSean Callanan 
937d6a9bbf6SAdrian Prantl       llvm::Optional<uint64_t> byte_size = m_type.GetByteSize(exe_scope);
938d963a7c3SAdrian Prantl       if (!byte_size) {
9398fb53dcaSAdrian Prantl         err.SetErrorStringWithFormat("can't get size of type \"%s\"",
9408fb53dcaSAdrian Prantl                                      m_type.GetTypeName().AsCString());
941d963a7c3SAdrian Prantl         return;
942d963a7c3SAdrian Prantl       }
9431582ee68SSean Callanan 
9447f9bbe05SDavide Italiano       llvm::Optional<size_t> opt_bit_align = m_type.GetTypeBitAlign(exe_scope);
94536f13e49SDavide Italiano       if (!opt_bit_align) {
9468fb53dcaSAdrian Prantl         err.SetErrorStringWithFormat("can't get the alignment of type  \"%s\"",
9478fb53dcaSAdrian Prantl                                      m_type.GetTypeName().AsCString());
94836f13e49SDavide Italiano         return;
94936f13e49SDavide Italiano       }
95036f13e49SDavide Italiano 
95136f13e49SDavide Italiano       size_t byte_align = (*opt_bit_align + 7) / 8;
95222ac610cSSean Callanan 
95397206d57SZachary Turner       Status alloc_error;
9542c381414SJim Ingham       const bool zero_memory = true;
9551582ee68SSean Callanan 
956b9c1b51eSKate Stone       m_temporary_allocation = map.Malloc(
957d963a7c3SAdrian Prantl           *byte_size, byte_align,
9582c381414SJim Ingham           lldb::ePermissionsReadable | lldb::ePermissionsWritable,
959b9c1b51eSKate Stone           IRMemoryMap::eAllocationPolicyMirror, zero_memory, alloc_error);
960d963a7c3SAdrian Prantl       m_temporary_allocation_size = *byte_size;
9611582ee68SSean Callanan 
962b9c1b51eSKate Stone       if (!alloc_error.Success()) {
963b9c1b51eSKate Stone         err.SetErrorStringWithFormat(
964b9c1b51eSKate Stone             "couldn't allocate a temporary region for the result: %s",
965b9c1b51eSKate Stone             alloc_error.AsCString());
9661582ee68SSean Callanan         return;
9671582ee68SSean Callanan       }
9681582ee68SSean Callanan 
96997206d57SZachary Turner       Status pointer_write_error;
9701582ee68SSean Callanan 
971b9c1b51eSKate Stone       map.WritePointerToMemory(load_addr, m_temporary_allocation,
972b9c1b51eSKate Stone                                pointer_write_error);
9731582ee68SSean Callanan 
974b9c1b51eSKate Stone       if (!pointer_write_error.Success()) {
975b9c1b51eSKate Stone         err.SetErrorStringWithFormat("couldn't write the address of the "
976b9c1b51eSKate Stone                                      "temporary region for the result: %s",
977b9c1b51eSKate Stone                                      pointer_write_error.AsCString());
9781582ee68SSean Callanan       }
9791582ee68SSean Callanan     }
98096d2730aSSean Callanan   }
98196d2730aSSean Callanan 
Dematerialize(lldb::StackFrameSP & frame_sp,IRMemoryMap & map,lldb::addr_t process_address,lldb::addr_t frame_top,lldb::addr_t frame_bottom,Status & err)982b9c1b51eSKate Stone   void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
983b9c1b51eSKate Stone                      lldb::addr_t process_address, lldb::addr_t frame_top,
98497206d57SZachary Turner                      lldb::addr_t frame_bottom, Status &err) override {
9851582ee68SSean Callanan     err.Clear();
9861582ee68SSean Callanan 
9873728133dSAdrian Prantl     ExecutionContextScope *exe_scope = frame_sp.get();
9883728133dSAdrian Prantl     if (!exe_scope)
9893728133dSAdrian Prantl       exe_scope = map.GetBestExecutionContextScope();
9901582ee68SSean Callanan 
991b9c1b51eSKate Stone     if (!exe_scope) {
992b9c1b51eSKate Stone       err.SetErrorString("Couldn't dematerialize a result variable: invalid "
993b9c1b51eSKate Stone                          "execution context scope");
9941582ee68SSean Callanan       return;
9951582ee68SSean Callanan     }
9961582ee68SSean Callanan 
9971582ee68SSean Callanan     lldb::addr_t address;
99897206d57SZachary Turner     Status read_error;
99957ee3067SGreg Clayton     const lldb::addr_t load_addr = process_address + m_offset;
10001582ee68SSean Callanan 
100157ee3067SGreg Clayton     map.ReadPointerFromMemory(&address, load_addr, read_error);
10021582ee68SSean Callanan 
1003b9c1b51eSKate Stone     if (!read_error.Success()) {
1004b9c1b51eSKate Stone       err.SetErrorString("Couldn't dematerialize a result variable: couldn't "
1005b9c1b51eSKate Stone                          "read its address");
10061582ee68SSean Callanan       return;
10071582ee68SSean Callanan     }
10081582ee68SSean Callanan 
10091582ee68SSean Callanan     lldb::TargetSP target_sp = exe_scope->CalculateTarget();
10101582ee68SSean Callanan 
1011b9c1b51eSKate Stone     if (!target_sp) {
10121582ee68SSean Callanan       err.SetErrorString("Couldn't dematerialize a result variable: no target");
10131582ee68SSean Callanan       return;
10141582ee68SSean Callanan     }
10151582ee68SSean Callanan 
10160e252e38SAlex Langford     auto type_system_or_err =
10170e252e38SAlex Langford         target_sp->GetScratchTypeSystemForLanguage(m_type.GetMinimumLanguage());
10181582ee68SSean Callanan 
10190e252e38SAlex Langford     if (auto error = type_system_or_err.takeError()) {
1020b9c1b51eSKate Stone       err.SetErrorStringWithFormat("Couldn't dematerialize a result variable: "
1021b9c1b51eSKate Stone                                    "couldn't get the corresponding type "
1022b9c1b51eSKate Stone                                    "system: %s",
10230e252e38SAlex Langford                                    llvm::toString(std::move(error)).c_str());
10248f1f9a1bSSean Callanan       return;
10258f1f9a1bSSean Callanan     }
1026b9c1b51eSKate Stone     PersistentExpressionState *persistent_state =
10270e252e38SAlex Langford         type_system_or_err->GetPersistentExpressionState();
10288f1f9a1bSSean Callanan 
1029b9c1b51eSKate Stone     if (!persistent_state) {
1030b9c1b51eSKate Stone       err.SetErrorString("Couldn't dematerialize a result variable: "
1031b9c1b51eSKate Stone                          "corresponding type system doesn't handle persistent "
1032b9c1b51eSKate Stone                          "variables");
10338f1f9a1bSSean Callanan       return;
10348f1f9a1bSSean Callanan     }
10358f1f9a1bSSean Callanan 
103667d67ebeSJim Ingham     ConstString name = m_delegate
1037b9c1b51eSKate Stone                            ? m_delegate->GetName()
103867d67ebeSJim Ingham                            : persistent_state->GetNextPersistentVariableName();
10398f1f9a1bSSean Callanan 
1040b9c1b51eSKate Stone     lldb::ExpressionVariableSP ret = persistent_state->CreatePersistentVariable(
1041b9c1b51eSKate Stone         exe_scope, name, m_type, map.GetByteOrder(), map.GetAddressByteSize());
10421582ee68SSean Callanan 
1043b9c1b51eSKate Stone     if (!ret) {
1044b9c1b51eSKate Stone       err.SetErrorStringWithFormat("couldn't dematerialize a result variable: "
1045b9c1b51eSKate Stone                                    "failed to make persistent variable %s",
1046b9c1b51eSKate Stone                                    name.AsCString());
10471582ee68SSean Callanan       return;
10481582ee68SSean Callanan     }
10491582ee68SSean Callanan 
1050b9c1b51eSKate Stone     lldb::ProcessSP process_sp =
1051b9c1b51eSKate Stone         map.GetBestExecutionContextScope()->CalculateProcess();
10522afbf444SSean Callanan 
1053b9c1b51eSKate Stone     if (m_delegate) {
10549fda9d21SSean Callanan       m_delegate->DidDematerialize(ret);
10559fda9d21SSean Callanan     }
10569fda9d21SSean Callanan 
1057b9c1b51eSKate Stone     bool can_persist =
1058b9c1b51eSKate Stone         (m_is_program_reference && process_sp && process_sp->CanJIT() &&
1059b9c1b51eSKate Stone          !(address >= frame_bottom && address < frame_top));
10602afbf444SSean Callanan 
1061b9c1b51eSKate Stone     if (can_persist && m_keep_in_memory) {
1062b9c1b51eSKate Stone       ret->m_live_sp = ValueObjectConstResult::Create(exe_scope, m_type, name,
1063b9c1b51eSKate Stone                                                       address, eAddressTypeLoad,
10643e68903eSSean Callanan                                                       map.GetAddressByteSize());
10652afbf444SSean Callanan     }
10661582ee68SSean Callanan 
10671582ee68SSean Callanan     ret->ValueUpdated();
10681582ee68SSean Callanan 
1069aa88161bSKazu Hirata     const size_t pvar_byte_size = ret->GetByteSize().value_or(0);
10701582ee68SSean Callanan     uint8_t *pvar_data = ret->GetValueBytes();
10711582ee68SSean Callanan 
10721582ee68SSean Callanan     map.ReadMemory(pvar_data, address, pvar_byte_size, read_error);
10731582ee68SSean Callanan 
1074b9c1b51eSKate Stone     if (!read_error.Success()) {
1075b9c1b51eSKate Stone       err.SetErrorString(
1076b9c1b51eSKate Stone           "Couldn't dematerialize a result variable: couldn't read its memory");
10771582ee68SSean Callanan       return;
10781582ee68SSean Callanan     }
10791582ee68SSean Callanan 
1080b9c1b51eSKate Stone     if (!can_persist || !m_keep_in_memory) {
1081e6f4a826SSean Callanan       ret->m_flags |= ExpressionVariable::EVNeedsAllocation;
10821582ee68SSean Callanan 
1083b9c1b51eSKate Stone       if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
108497206d57SZachary Turner         Status free_error;
10851582ee68SSean Callanan         map.Free(m_temporary_allocation, free_error);
10861582ee68SSean Callanan       }
1087b9c1b51eSKate Stone     } else {
1088e6f4a826SSean Callanan       ret->m_flags |= ExpressionVariable::EVIsLLDBAllocated;
10891582ee68SSean Callanan     }
10901582ee68SSean Callanan 
10911582ee68SSean Callanan     m_temporary_allocation = LLDB_INVALID_ADDRESS;
10921582ee68SSean Callanan     m_temporary_allocation_size = 0;
109396d2730aSSean Callanan   }
10942d37e5a5SSean Callanan 
DumpToLog(IRMemoryMap & map,lldb::addr_t process_address,Log * log)1095b9c1b51eSKate Stone   void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
1096b9c1b51eSKate Stone                  Log *log) override {
10972d37e5a5SSean Callanan     StreamString dump_stream;
10982d37e5a5SSean Callanan 
109957ee3067SGreg Clayton     const lldb::addr_t load_addr = process_address + m_offset;
110057ee3067SGreg Clayton 
110157ee3067SGreg Clayton     dump_stream.Printf("0x%" PRIx64 ": EntityResultVariable\n", load_addr);
11022d37e5a5SSean Callanan 
110397206d57SZachary Turner     Status err;
11041582ee68SSean Callanan 
11051582ee68SSean Callanan     lldb::addr_t ptr = LLDB_INVALID_ADDRESS;
11061582ee68SSean Callanan 
11071582ee68SSean Callanan     {
11081582ee68SSean Callanan       dump_stream.Printf("Pointer:\n");
11091582ee68SSean Callanan 
11101582ee68SSean Callanan       DataBufferHeap data(m_size, 0);
11111582ee68SSean Callanan 
111257ee3067SGreg Clayton       map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
11131582ee68SSean Callanan 
1114b9c1b51eSKate Stone       if (!err.Success()) {
11151582ee68SSean Callanan         dump_stream.Printf("  <could not be read>\n");
1116b9c1b51eSKate Stone       } else {
1117b9c1b51eSKate Stone         DataExtractor extractor(data.GetBytes(), data.GetByteSize(),
1118b9c1b51eSKate Stone                                 map.GetByteOrder(), map.GetAddressByteSize());
11191582ee68SSean Callanan 
112029cb868aSZachary Turner         DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
112129cb868aSZachary Turner                      load_addr);
11221582ee68SSean Callanan 
1123dcd0926aSPavel Labath         lldb::offset_t offset = 0;
11241582ee68SSean Callanan 
11250863f675SPavel Labath         ptr = extractor.GetAddress(&offset);
11261582ee68SSean Callanan 
11271582ee68SSean Callanan         dump_stream.PutChar('\n');
11281582ee68SSean Callanan       }
11291582ee68SSean Callanan     }
11301582ee68SSean Callanan 
1131b9c1b51eSKate Stone     if (m_temporary_allocation == LLDB_INVALID_ADDRESS) {
11321582ee68SSean Callanan       dump_stream.Printf("Points to process memory:\n");
1133b9c1b51eSKate Stone     } else {
11341582ee68SSean Callanan       dump_stream.Printf("Temporary allocation:\n");
11351582ee68SSean Callanan     }
11361582ee68SSean Callanan 
1137b9c1b51eSKate Stone     if (ptr == LLDB_INVALID_ADDRESS) {
11381582ee68SSean Callanan       dump_stream.Printf("  <could not be be found>\n");
1139b9c1b51eSKate Stone     } else {
11401582ee68SSean Callanan       DataBufferHeap data(m_temporary_allocation_size, 0);
11411582ee68SSean Callanan 
1142b9c1b51eSKate Stone       map.ReadMemory(data.GetBytes(), m_temporary_allocation,
1143b9c1b51eSKate Stone                      m_temporary_allocation_size, err);
11441582ee68SSean Callanan 
1145b9c1b51eSKate Stone       if (!err.Success()) {
11461582ee68SSean Callanan         dump_stream.Printf("  <could not be read>\n");
1147b9c1b51eSKate Stone       } else {
114829cb868aSZachary Turner         DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
114929cb868aSZachary Turner                      load_addr);
11501582ee68SSean Callanan 
11511582ee68SSean Callanan         dump_stream.PutChar('\n');
11521582ee68SSean Callanan       }
11531582ee68SSean Callanan     }
11541582ee68SSean Callanan 
1155c156427dSZachary Turner     log->PutString(dump_stream.GetString());
11562d37e5a5SSean Callanan   }
115714b1bae5SSean Callanan 
Wipe(IRMemoryMap & map,lldb::addr_t process_address)1158b9c1b51eSKate Stone   void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {
1159b9c1b51eSKate Stone     if (!m_keep_in_memory && m_temporary_allocation != LLDB_INVALID_ADDRESS) {
116097206d57SZachary Turner       Status free_error;
11611582ee68SSean Callanan 
11621582ee68SSean Callanan       map.Free(m_temporary_allocation, free_error);
11631582ee68SSean Callanan     }
11641582ee68SSean Callanan 
11651582ee68SSean Callanan     m_temporary_allocation = LLDB_INVALID_ADDRESS;
11661582ee68SSean Callanan     m_temporary_allocation_size = 0;
116714b1bae5SSean Callanan   }
1168315b6884SEugene Zelenko 
116996d2730aSSean Callanan private:
1170e6f4a826SSean Callanan   CompilerType m_type;
11711582ee68SSean Callanan   bool m_is_program_reference;
117235005f76SSean Callanan   bool m_keep_in_memory;
11731582ee68SSean Callanan 
117428c878aeSShafik Yaghmour   lldb::addr_t m_temporary_allocation = LLDB_INVALID_ADDRESS;
117528c878aeSShafik Yaghmour   size_t m_temporary_allocation_size = 0;
11769fda9d21SSean Callanan   Materializer::PersistentVariableDelegate *m_delegate;
117796d2730aSSean Callanan };
117896d2730aSSean Callanan 
AddResultVariable(const CompilerType & type,bool is_program_reference,bool keep_in_memory,PersistentVariableDelegate * delegate,Status & err)1179b9c1b51eSKate Stone uint32_t Materializer::AddResultVariable(const CompilerType &type,
11809fda9d21SSean Callanan                                          bool is_program_reference,
11819fda9d21SSean Callanan                                          bool keep_in_memory,
11829fda9d21SSean Callanan                                          PersistentVariableDelegate *delegate,
118397206d57SZachary Turner                                          Status &err) {
118496d2730aSSean Callanan   EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
118506412daeSJonas Devlieghere   *iter = std::make_unique<EntityResultVariable>(type, is_program_reference,
118606412daeSJonas Devlieghere                                                  keep_in_memory, delegate);
118796d2730aSSean Callanan   uint32_t ret = AddStructMember(**iter);
118896d2730aSSean Callanan   (*iter)->SetOffset(ret);
118996d2730aSSean Callanan   return ret;
119096d2730aSSean Callanan }
119196d2730aSSean Callanan 
1192b9c1b51eSKate Stone class EntitySymbol : public Materializer::Entity {
119396d2730aSSean Callanan public:
EntitySymbol(const Symbol & symbol)1194b9c1b51eSKate Stone   EntitySymbol(const Symbol &symbol) : Entity(), m_symbol(symbol) {
119596d2730aSSean Callanan     // Hard-coding to maximum size of a symbol
1196fcf4e252SMichael Buch     m_size = g_default_var_byte_size;
1197fcf4e252SMichael Buch     m_alignment = g_default_var_alignment;
119896d2730aSSean Callanan   }
119996d2730aSSean Callanan 
Materialize(lldb::StackFrameSP & frame_sp,IRMemoryMap & map,lldb::addr_t process_address,Status & err)1200b9c1b51eSKate Stone   void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
120197206d57SZachary Turner                    lldb::addr_t process_address, Status &err) override {
1202a007a6d8SPavel Labath     Log *log = GetLog(LLDBLog::Expressions);
1203b5717e00SSean Callanan 
120457ee3067SGreg Clayton     const lldb::addr_t load_addr = process_address + m_offset;
120557ee3067SGreg Clayton 
1206b9c1b51eSKate Stone     if (log) {
120763e5fb76SJonas Devlieghere       LLDB_LOGF(log,
120863e5fb76SJonas Devlieghere                 "EntitySymbol::Materialize [address = 0x%" PRIx64
1209b9c1b51eSKate Stone                 ", m_symbol = %s]",
1210b9c1b51eSKate Stone                 (uint64_t)load_addr, m_symbol.GetName().AsCString());
1211b5717e00SSean Callanan     }
1212b5717e00SSean Callanan 
1213358cf1eaSGreg Clayton     const Address sym_address = m_symbol.GetAddress();
12142f1edcd7SSean Callanan 
12153728133dSAdrian Prantl     ExecutionContextScope *exe_scope = frame_sp.get();
12163728133dSAdrian Prantl     if (!exe_scope)
12173728133dSAdrian Prantl       exe_scope = map.GetBestExecutionContextScope();
12182f1edcd7SSean Callanan 
12192f1edcd7SSean Callanan     lldb::TargetSP target_sp;
12202f1edcd7SSean Callanan 
12212f1edcd7SSean Callanan     if (exe_scope)
12222f1edcd7SSean Callanan       target_sp = map.GetBestExecutionContextScope()->CalculateTarget();
12232f1edcd7SSean Callanan 
1224b9c1b51eSKate Stone     if (!target_sp) {
1225b9c1b51eSKate Stone       err.SetErrorStringWithFormat(
1226b9c1b51eSKate Stone           "couldn't resolve symbol %s because there is no target",
1227b9c1b51eSKate Stone           m_symbol.GetName().AsCString());
12282f1edcd7SSean Callanan       return;
12292f1edcd7SSean Callanan     }
12302f1edcd7SSean Callanan 
12312f1edcd7SSean Callanan     lldb::addr_t resolved_address = sym_address.GetLoadAddress(target_sp.get());
12322f1edcd7SSean Callanan 
12332f1edcd7SSean Callanan     if (resolved_address == LLDB_INVALID_ADDRESS)
12342f1edcd7SSean Callanan       resolved_address = sym_address.GetFileAddress();
12352f1edcd7SSean Callanan 
123697206d57SZachary Turner     Status pointer_write_error;
12372f1edcd7SSean Callanan 
123857ee3067SGreg Clayton     map.WritePointerToMemory(load_addr, resolved_address, pointer_write_error);
12392f1edcd7SSean Callanan 
1240b9c1b51eSKate Stone     if (!pointer_write_error.Success()) {
1241b9c1b51eSKate Stone       err.SetErrorStringWithFormat(
1242b9c1b51eSKate Stone           "couldn't write the address of symbol %s: %s",
1243b9c1b51eSKate Stone           m_symbol.GetName().AsCString(), pointer_write_error.AsCString());
1244b5717e00SSean Callanan       return;
12452f1edcd7SSean Callanan     }
124696d2730aSSean Callanan   }
124796d2730aSSean Callanan 
Dematerialize(lldb::StackFrameSP & frame_sp,IRMemoryMap & map,lldb::addr_t process_address,lldb::addr_t frame_top,lldb::addr_t frame_bottom,Status & err)1248b9c1b51eSKate Stone   void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1249b9c1b51eSKate Stone                      lldb::addr_t process_address, lldb::addr_t frame_top,
125097206d57SZachary Turner                      lldb::addr_t frame_bottom, Status &err) override {
1251a007a6d8SPavel Labath     Log *log = GetLog(LLDBLog::Expressions);
1252b5717e00SSean Callanan 
125357ee3067SGreg Clayton     const lldb::addr_t load_addr = process_address + m_offset;
125457ee3067SGreg Clayton 
1255b9c1b51eSKate Stone     if (log) {
125663e5fb76SJonas Devlieghere       LLDB_LOGF(log,
125763e5fb76SJonas Devlieghere                 "EntitySymbol::Dematerialize [address = 0x%" PRIx64
1258b9c1b51eSKate Stone                 ", m_symbol = %s]",
1259b9c1b51eSKate Stone                 (uint64_t)load_addr, m_symbol.GetName().AsCString());
1260b5717e00SSean Callanan     }
1261b5717e00SSean Callanan 
12622f1edcd7SSean Callanan     // no work needs to be done
126396d2730aSSean Callanan   }
12642d37e5a5SSean Callanan 
DumpToLog(IRMemoryMap & map,lldb::addr_t process_address,Log * log)1265b9c1b51eSKate Stone   void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
1266b9c1b51eSKate Stone                  Log *log) override {
12672d37e5a5SSean Callanan     StreamString dump_stream;
12682d37e5a5SSean Callanan 
126997206d57SZachary Turner     Status err;
12702d37e5a5SSean Callanan 
127157ee3067SGreg Clayton     const lldb::addr_t load_addr = process_address + m_offset;
127257ee3067SGreg Clayton 
1273b9c1b51eSKate Stone     dump_stream.Printf("0x%" PRIx64 ": EntitySymbol (%s)\n", load_addr,
1274b9c1b51eSKate Stone                        m_symbol.GetName().AsCString());
12752d37e5a5SSean Callanan 
12762d37e5a5SSean Callanan     {
12772d37e5a5SSean Callanan       dump_stream.Printf("Pointer:\n");
12782d37e5a5SSean Callanan 
12792d37e5a5SSean Callanan       DataBufferHeap data(m_size, 0);
12802d37e5a5SSean Callanan 
128157ee3067SGreg Clayton       map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
12822d37e5a5SSean Callanan 
1283b9c1b51eSKate Stone       if (!err.Success()) {
12842d37e5a5SSean Callanan         dump_stream.Printf("  <could not be read>\n");
1285b9c1b51eSKate Stone       } else {
128629cb868aSZachary Turner         DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
128729cb868aSZachary Turner                      load_addr);
128814b1bae5SSean Callanan 
128914b1bae5SSean Callanan         dump_stream.PutChar('\n');
12902d37e5a5SSean Callanan       }
12912d37e5a5SSean Callanan     }
12922d37e5a5SSean Callanan 
1293c156427dSZachary Turner     log->PutString(dump_stream.GetString());
12942d37e5a5SSean Callanan   }
129514b1bae5SSean Callanan 
Wipe(IRMemoryMap & map,lldb::addr_t process_address)1296b9c1b51eSKate Stone   void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {}
1297315b6884SEugene Zelenko 
129896d2730aSSean Callanan private:
129996d2730aSSean Callanan   Symbol m_symbol;
130096d2730aSSean Callanan };
130196d2730aSSean Callanan 
AddSymbol(const Symbol & symbol_sp,Status & err)130297206d57SZachary Turner uint32_t Materializer::AddSymbol(const Symbol &symbol_sp, Status &err) {
130396d2730aSSean Callanan   EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
130406412daeSJonas Devlieghere   *iter = std::make_unique<EntitySymbol>(symbol_sp);
130596d2730aSSean Callanan   uint32_t ret = AddStructMember(**iter);
130696d2730aSSean Callanan   (*iter)->SetOffset(ret);
130796d2730aSSean Callanan   return ret;
130896d2730aSSean Callanan }
130996d2730aSSean Callanan 
1310b9c1b51eSKate Stone class EntityRegister : public Materializer::Entity {
131196d2730aSSean Callanan public:
EntityRegister(const RegisterInfo & register_info)1312b9c1b51eSKate Stone   EntityRegister(const RegisterInfo &register_info)
1313b9c1b51eSKate Stone       : Entity(), m_register_info(register_info) {
131496d2730aSSean Callanan     // Hard-coding alignment conservatively
131596d2730aSSean Callanan     m_size = m_register_info.byte_size;
131696d2730aSSean Callanan     m_alignment = m_register_info.byte_size;
131796d2730aSSean Callanan   }
131896d2730aSSean Callanan 
Materialize(lldb::StackFrameSP & frame_sp,IRMemoryMap & map,lldb::addr_t process_address,Status & err)1319b9c1b51eSKate Stone   void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
132097206d57SZachary Turner                    lldb::addr_t process_address, Status &err) override {
1321a007a6d8SPavel Labath     Log *log = GetLog(LLDBLog::Expressions);
1322b5717e00SSean Callanan 
132357ee3067SGreg Clayton     const lldb::addr_t load_addr = process_address + m_offset;
132457ee3067SGreg Clayton 
1325b9c1b51eSKate Stone     if (log) {
132663e5fb76SJonas Devlieghere       LLDB_LOGF(log,
132763e5fb76SJonas Devlieghere                 "EntityRegister::Materialize [address = 0x%" PRIx64
1328b9c1b51eSKate Stone                 ", m_register_info = %s]",
1329b9c1b51eSKate Stone                 (uint64_t)load_addr, m_register_info.name);
1330b5717e00SSean Callanan     }
1331b5717e00SSean Callanan 
1332b5717e00SSean Callanan     RegisterValue reg_value;
1333b5717e00SSean Callanan 
1334b9c1b51eSKate Stone     if (!frame_sp.get()) {
1335b9c1b51eSKate Stone       err.SetErrorStringWithFormat(
1336b9c1b51eSKate Stone           "couldn't materialize register %s without a stack frame",
1337b9c1b51eSKate Stone           m_register_info.name);
1338b5717e00SSean Callanan       return;
1339b5717e00SSean Callanan     }
1340b5717e00SSean Callanan 
1341b5717e00SSean Callanan     lldb::RegisterContextSP reg_context_sp = frame_sp->GetRegisterContext();
1342b5717e00SSean Callanan 
1343b9c1b51eSKate Stone     if (!reg_context_sp->ReadRegister(&m_register_info, reg_value)) {
1344b9c1b51eSKate Stone       err.SetErrorStringWithFormat("couldn't read the value of register %s",
1345b9c1b51eSKate Stone                                    m_register_info.name);
1346b5717e00SSean Callanan       return;
1347b5717e00SSean Callanan     }
1348b5717e00SSean Callanan 
1349b5717e00SSean Callanan     DataExtractor register_data;
1350b5717e00SSean Callanan 
1351b9c1b51eSKate Stone     if (!reg_value.GetData(register_data)) {
1352b9c1b51eSKate Stone       err.SetErrorStringWithFormat("couldn't get the data for register %s",
1353b9c1b51eSKate Stone                                    m_register_info.name);
1354b5717e00SSean Callanan       return;
1355b5717e00SSean Callanan     }
1356b5717e00SSean Callanan 
1357b9c1b51eSKate Stone     if (register_data.GetByteSize() != m_register_info.byte_size) {
1358b9c1b51eSKate Stone       err.SetErrorStringWithFormat(
1359b9c1b51eSKate Stone           "data for register %s had size %llu but we expected %llu",
1360b9c1b51eSKate Stone           m_register_info.name, (unsigned long long)register_data.GetByteSize(),
1361b9c1b51eSKate Stone           (unsigned long long)m_register_info.byte_size);
1362b5717e00SSean Callanan       return;
1363b5717e00SSean Callanan     }
1364b5717e00SSean Callanan 
1365796ac80bSJonas Devlieghere     m_register_contents = std::make_shared<DataBufferHeap>(
1366796ac80bSJonas Devlieghere         register_data.GetDataStart(), register_data.GetByteSize());
1367d2a507a6SSean Callanan 
136897206d57SZachary Turner     Status write_error;
1369b5717e00SSean Callanan 
1370b9c1b51eSKate Stone     map.WriteMemory(load_addr, register_data.GetDataStart(),
1371b9c1b51eSKate Stone                     register_data.GetByteSize(), write_error);
1372b5717e00SSean Callanan 
1373b9c1b51eSKate Stone     if (!write_error.Success()) {
1374b9c1b51eSKate Stone       err.SetErrorStringWithFormat(
1375b9c1b51eSKate Stone           "couldn't write the contents of register %s: %s",
1376b9c1b51eSKate Stone           m_register_info.name, write_error.AsCString());
1377b5717e00SSean Callanan       return;
1378b5717e00SSean Callanan     }
137996d2730aSSean Callanan   }
138096d2730aSSean Callanan 
Dematerialize(lldb::StackFrameSP & frame_sp,IRMemoryMap & map,lldb::addr_t process_address,lldb::addr_t frame_top,lldb::addr_t frame_bottom,Status & err)1381b9c1b51eSKate Stone   void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1382b9c1b51eSKate Stone                      lldb::addr_t process_address, lldb::addr_t frame_top,
138397206d57SZachary Turner                      lldb::addr_t frame_bottom, Status &err) override {
1384a007a6d8SPavel Labath     Log *log = GetLog(LLDBLog::Expressions);
1385b5717e00SSean Callanan 
138657ee3067SGreg Clayton     const lldb::addr_t load_addr = process_address + m_offset;
138757ee3067SGreg Clayton 
1388b9c1b51eSKate Stone     if (log) {
138963e5fb76SJonas Devlieghere       LLDB_LOGF(log,
139063e5fb76SJonas Devlieghere                 "EntityRegister::Dematerialize [address = 0x%" PRIx64
1391b9c1b51eSKate Stone                 ", m_register_info = %s]",
1392b9c1b51eSKate Stone                 (uint64_t)load_addr, m_register_info.name);
1393b5717e00SSean Callanan     }
1394b5717e00SSean Callanan 
139597206d57SZachary Turner     Status extract_error;
1396b5717e00SSean Callanan 
1397b5717e00SSean Callanan     DataExtractor register_data;
1398b5717e00SSean Callanan 
1399b9c1b51eSKate Stone     if (!frame_sp.get()) {
1400b9c1b51eSKate Stone       err.SetErrorStringWithFormat(
1401b9c1b51eSKate Stone           "couldn't dematerialize register %s without a stack frame",
1402b9c1b51eSKate Stone           m_register_info.name);
1403b5717e00SSean Callanan       return;
1404b5717e00SSean Callanan     }
1405b5717e00SSean Callanan 
1406b5717e00SSean Callanan     lldb::RegisterContextSP reg_context_sp = frame_sp->GetRegisterContext();
1407b5717e00SSean Callanan 
1408b9c1b51eSKate Stone     map.GetMemoryData(register_data, load_addr, m_register_info.byte_size,
1409b9c1b51eSKate Stone                       extract_error);
1410b5717e00SSean Callanan 
1411b9c1b51eSKate Stone     if (!extract_error.Success()) {
1412b9c1b51eSKate Stone       err.SetErrorStringWithFormat("couldn't get the data for register %s: %s",
1413b9c1b51eSKate Stone                                    m_register_info.name,
1414b9c1b51eSKate Stone                                    extract_error.AsCString());
1415b5717e00SSean Callanan       return;
1416b5717e00SSean Callanan     }
1417b5717e00SSean Callanan 
1418b9c1b51eSKate Stone     if (!memcmp(register_data.GetDataStart(), m_register_contents->GetBytes(),
1419b9c1b51eSKate Stone                 register_data.GetByteSize())) {
1420b9c1b51eSKate Stone       // No write required, and in particular we avoid errors if the register
1421b9c1b51eSKate Stone       // wasn't writable
1422d2a507a6SSean Callanan 
1423d2a507a6SSean Callanan       m_register_contents.reset();
1424d2a507a6SSean Callanan       return;
1425d2a507a6SSean Callanan     }
1426d2a507a6SSean Callanan 
1427d2a507a6SSean Callanan     m_register_contents.reset();
1428d2a507a6SSean Callanan 
1429d2700b78SPavel Labath     RegisterValue register_value(register_data.GetData(),
1430d2700b78SPavel Labath                                  register_data.GetByteOrder());
1431b5717e00SSean Callanan 
1432b9c1b51eSKate Stone     if (!reg_context_sp->WriteRegister(&m_register_info, register_value)) {
1433b9c1b51eSKate Stone       err.SetErrorStringWithFormat("couldn't write the value of register %s",
1434b9c1b51eSKate Stone                                    m_register_info.name);
1435b5717e00SSean Callanan       return;
1436b5717e00SSean Callanan     }
143796d2730aSSean Callanan   }
14382d37e5a5SSean Callanan 
DumpToLog(IRMemoryMap & map,lldb::addr_t process_address,Log * log)1439b9c1b51eSKate Stone   void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
1440b9c1b51eSKate Stone                  Log *log) override {
14412d37e5a5SSean Callanan     StreamString dump_stream;
14422d37e5a5SSean Callanan 
144397206d57SZachary Turner     Status err;
14442d37e5a5SSean Callanan 
144557ee3067SGreg Clayton     const lldb::addr_t load_addr = process_address + m_offset;
144657ee3067SGreg Clayton 
1447b9c1b51eSKate Stone     dump_stream.Printf("0x%" PRIx64 ": EntityRegister (%s)\n", load_addr,
1448b9c1b51eSKate Stone                        m_register_info.name);
14492d37e5a5SSean Callanan 
14502d37e5a5SSean Callanan     {
14512d37e5a5SSean Callanan       dump_stream.Printf("Value:\n");
14522d37e5a5SSean Callanan 
14532d37e5a5SSean Callanan       DataBufferHeap data(m_size, 0);
14542d37e5a5SSean Callanan 
145557ee3067SGreg Clayton       map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
14562d37e5a5SSean Callanan 
1457b9c1b51eSKate Stone       if (!err.Success()) {
14582d37e5a5SSean Callanan         dump_stream.Printf("  <could not be read>\n");
1459b9c1b51eSKate Stone       } else {
146029cb868aSZachary Turner         DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
146129cb868aSZachary Turner                      load_addr);
146214b1bae5SSean Callanan 
146314b1bae5SSean Callanan         dump_stream.PutChar('\n');
14642d37e5a5SSean Callanan       }
14652d37e5a5SSean Callanan     }
14662d37e5a5SSean Callanan 
1467c156427dSZachary Turner     log->PutString(dump_stream.GetString());
14682d37e5a5SSean Callanan   }
146914b1bae5SSean Callanan 
Wipe(IRMemoryMap & map,lldb::addr_t process_address)1470b9c1b51eSKate Stone   void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {}
1471315b6884SEugene Zelenko 
147296d2730aSSean Callanan private:
147396d2730aSSean Callanan   RegisterInfo m_register_info;
1474d2a507a6SSean Callanan   lldb::DataBufferSP m_register_contents;
147596d2730aSSean Callanan };
147696d2730aSSean Callanan 
AddRegister(const RegisterInfo & register_info,Status & err)1477b9c1b51eSKate Stone uint32_t Materializer::AddRegister(const RegisterInfo &register_info,
147897206d57SZachary Turner                                    Status &err) {
147996d2730aSSean Callanan   EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
148006412daeSJonas Devlieghere   *iter = std::make_unique<EntityRegister>(register_info);
148196d2730aSSean Callanan   uint32_t ret = AddStructMember(**iter);
148296d2730aSSean Callanan   (*iter)->SetOffset(ret);
148396d2730aSSean Callanan   return ret;
148496d2730aSSean Callanan }
148596d2730aSSean Callanan 
~Materializer()1486b9c1b51eSKate Stone Materializer::~Materializer() {
148714b1bae5SSean Callanan   DematerializerSP dematerializer_sp = m_dematerializer_wp.lock();
148896d2730aSSean Callanan 
148914b1bae5SSean Callanan   if (dematerializer_sp)
149014b1bae5SSean Callanan     dematerializer_sp->Wipe();
149114b1bae5SSean Callanan }
149214b1bae5SSean Callanan 
149314b1bae5SSean Callanan Materializer::DematerializerSP
Materialize(lldb::StackFrameSP & frame_sp,IRMemoryMap & map,lldb::addr_t process_address,Status & error)1494b9c1b51eSKate Stone Materializer::Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
149597206d57SZachary Turner                           lldb::addr_t process_address, Status &error) {
1496b024d878SSean Callanan   ExecutionContextScope *exe_scope = frame_sp.get();
1497b024d878SSean Callanan   if (!exe_scope)
1498b024d878SSean Callanan     exe_scope = map.GetBestExecutionContextScope();
1499b024d878SSean Callanan 
150014b1bae5SSean Callanan   DematerializerSP dematerializer_sp = m_dematerializer_wp.lock();
150114b1bae5SSean Callanan 
1502b9c1b51eSKate Stone   if (dematerializer_sp) {
150314b1bae5SSean Callanan     error.SetErrorToGenericError();
150414b1bae5SSean Callanan     error.SetErrorString("Couldn't materialize: already materialized");
150514b1bae5SSean Callanan   }
150614b1bae5SSean Callanan 
1507b9c1b51eSKate Stone   DematerializerSP ret(
1508b9c1b51eSKate Stone       new Dematerializer(*this, frame_sp, map, process_address));
150914b1bae5SSean Callanan 
1510b9c1b51eSKate Stone   if (!exe_scope) {
1511b024d878SSean Callanan     error.SetErrorToGenericError();
151214b1bae5SSean Callanan     error.SetErrorString("Couldn't materialize: target doesn't exist");
1513b024d878SSean Callanan   }
1514b024d878SSean Callanan 
1515b9c1b51eSKate Stone   for (EntityUP &entity_up : m_entities) {
151696d2730aSSean Callanan     entity_up->Materialize(frame_sp, map, process_address, error);
151796d2730aSSean Callanan 
151896d2730aSSean Callanan     if (!error.Success())
151914b1bae5SSean Callanan       return DematerializerSP();
152096d2730aSSean Callanan   }
152196d2730aSSean Callanan 
1522a007a6d8SPavel Labath   if (Log *log = GetLog(LLDBLog::Expressions)) {
152363e5fb76SJonas Devlieghere     LLDB_LOGF(
152463e5fb76SJonas Devlieghere         log,
1525b9c1b51eSKate Stone         "Materializer::Materialize (frame_sp = %p, process_address = 0x%" PRIx64
1526b9c1b51eSKate Stone         ") materialized:",
1527324a1036SSaleem Abdulrasool         static_cast<void *>(frame_sp.get()), process_address);
15282d37e5a5SSean Callanan     for (EntityUP &entity_up : m_entities)
15292d37e5a5SSean Callanan       entity_up->DumpToLog(map, process_address, log);
15302d37e5a5SSean Callanan   }
15312d37e5a5SSean Callanan 
153214b1bae5SSean Callanan   m_dematerializer_wp = ret;
153396d2730aSSean Callanan 
153414b1bae5SSean Callanan   return ret;
153596d2730aSSean Callanan }
153696d2730aSSean Callanan 
Dematerialize(Status & error,lldb::addr_t frame_bottom,lldb::addr_t frame_top)153797206d57SZachary Turner void Materializer::Dematerializer::Dematerialize(Status &error,
15389fda9d21SSean Callanan                                                  lldb::addr_t frame_bottom,
1539b9c1b51eSKate Stone                                                  lldb::addr_t frame_top) {
1540b57e4a1bSJason Molenda   lldb::StackFrameSP frame_sp;
1541a4e8105bSSean Callanan 
1542a4e8105bSSean Callanan   lldb::ThreadSP thread_sp = m_thread_wp.lock();
1543a4e8105bSSean Callanan   if (thread_sp)
1544a4e8105bSSean Callanan     frame_sp = thread_sp->GetFrameWithStackID(m_stack_id);
154596d2730aSSean Callanan 
15463728133dSAdrian Prantl   ExecutionContextScope *exe_scope = frame_sp.get();
15473728133dSAdrian Prantl   if (!exe_scope)
15483728133dSAdrian Prantl     exe_scope = m_map->GetBestExecutionContextScope();
154914b1bae5SSean Callanan 
1550b9c1b51eSKate Stone   if (!IsValid()) {
155114b1bae5SSean Callanan     error.SetErrorToGenericError();
155214b1bae5SSean Callanan     error.SetErrorString("Couldn't dematerialize: invalid dematerializer");
155314b1bae5SSean Callanan   }
1554b024d878SSean Callanan 
1555b9c1b51eSKate Stone   if (!exe_scope) {
155696d2730aSSean Callanan     error.SetErrorToGenericError();
1557b024d878SSean Callanan     error.SetErrorString("Couldn't dematerialize: target is gone");
1558b9c1b51eSKate Stone   } else {
1559a007a6d8SPavel Labath     if (Log *log = GetLog(LLDBLog::Expressions)) {
156063e5fb76SJonas Devlieghere       LLDB_LOGF(log,
156163e5fb76SJonas Devlieghere                 "Materializer::Dematerialize (frame_sp = %p, process_address "
1562b9c1b51eSKate Stone                 "= 0x%" PRIx64 ") about to dematerialize:",
1563324a1036SSaleem Abdulrasool                 static_cast<void *>(frame_sp.get()), m_process_address);
156414b1bae5SSean Callanan       for (EntityUP &entity_up : m_materializer->m_entities)
156514b1bae5SSean Callanan         entity_up->DumpToLog(*m_map, m_process_address, log);
15662d37e5a5SSean Callanan     }
15672d37e5a5SSean Callanan 
1568b9c1b51eSKate Stone     for (EntityUP &entity_up : m_materializer->m_entities) {
1569b9c1b51eSKate Stone       entity_up->Dematerialize(frame_sp, *m_map, m_process_address, frame_top,
1570b9c1b51eSKate Stone                                frame_bottom, error);
157196d2730aSSean Callanan 
157296d2730aSSean Callanan       if (!error.Success())
157396d2730aSSean Callanan         break;
157496d2730aSSean Callanan     }
157596d2730aSSean Callanan   }
157696d2730aSSean Callanan 
157714b1bae5SSean Callanan   Wipe();
157814b1bae5SSean Callanan }
157914b1bae5SSean Callanan 
Wipe()1580b9c1b51eSKate Stone void Materializer::Dematerializer::Wipe() {
158114b1bae5SSean Callanan   if (!IsValid())
158214b1bae5SSean Callanan     return;
158314b1bae5SSean Callanan 
1584b9c1b51eSKate Stone   for (EntityUP &entity_up : m_materializer->m_entities) {
158514b1bae5SSean Callanan     entity_up->Wipe(*m_map, m_process_address);
158614b1bae5SSean Callanan   }
158714b1bae5SSean Callanan 
1588315b6884SEugene Zelenko   m_materializer = nullptr;
1589315b6884SEugene Zelenko   m_map = nullptr;
159014b1bae5SSean Callanan   m_process_address = LLDB_INVALID_ADDRESS;
159196d2730aSSean Callanan }
15929fda9d21SSean Callanan 
1593b9c1b51eSKate Stone Materializer::PersistentVariableDelegate::~PersistentVariableDelegate() =
1594b9c1b51eSKate Stone     default;
1595