xref: /freebsd-src/contrib/llvm-project/lldb/source/Expression/Materializer.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
15ffd83dbSDimitry Andric //===-- Materializer.cpp --------------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "lldb/Expression/Materializer.h"
100b57cec5SDimitry Andric #include "lldb/Core/DumpDataExtractor.h"
110b57cec5SDimitry Andric #include "lldb/Core/ValueObjectConstResult.h"
120b57cec5SDimitry Andric #include "lldb/Core/ValueObjectVariable.h"
130b57cec5SDimitry Andric #include "lldb/Expression/ExpressionVariable.h"
140b57cec5SDimitry Andric #include "lldb/Symbol/Symbol.h"
150b57cec5SDimitry Andric #include "lldb/Symbol/Type.h"
160b57cec5SDimitry Andric #include "lldb/Symbol/Variable.h"
170b57cec5SDimitry Andric #include "lldb/Target/ExecutionContext.h"
180b57cec5SDimitry Andric #include "lldb/Target/RegisterContext.h"
190b57cec5SDimitry Andric #include "lldb/Target/StackFrame.h"
200b57cec5SDimitry Andric #include "lldb/Target/Target.h"
210b57cec5SDimitry Andric #include "lldb/Target/Thread.h"
2281ad6265SDimitry Andric #include "lldb/Utility/LLDBLog.h"
230b57cec5SDimitry Andric #include "lldb/Utility/Log.h"
240b57cec5SDimitry Andric #include "lldb/Utility/RegisterValue.h"
25fcaf7f86SDimitry Andric #include "lldb/lldb-forward.h"
260b57cec5SDimitry Andric 
270b57cec5SDimitry Andric #include <memory>
28bdd1243dSDimitry Andric #include <optional>
290b57cec5SDimitry Andric 
300b57cec5SDimitry Andric using namespace lldb_private;
310b57cec5SDimitry Andric 
32fcaf7f86SDimitry Andric // FIXME: these should be retrieved from the target
33fcaf7f86SDimitry Andric //        instead of being hard-coded. Currently we
34fcaf7f86SDimitry Andric //        assume that persistent vars are materialized
35fcaf7f86SDimitry Andric //        as references, and thus pick the size of a
36fcaf7f86SDimitry Andric //        64-bit pointer.
37fcaf7f86SDimitry Andric static constexpr uint32_t g_default_var_alignment = 8;
38fcaf7f86SDimitry Andric static constexpr uint32_t g_default_var_byte_size = 8;
39fcaf7f86SDimitry Andric 
AddStructMember(Entity & entity)400b57cec5SDimitry Andric uint32_t Materializer::AddStructMember(Entity &entity) {
410b57cec5SDimitry Andric   uint32_t size = entity.GetSize();
420b57cec5SDimitry Andric   uint32_t alignment = entity.GetAlignment();
430b57cec5SDimitry Andric 
440b57cec5SDimitry Andric   uint32_t ret;
450b57cec5SDimitry Andric 
460b57cec5SDimitry Andric   if (m_current_offset == 0)
470b57cec5SDimitry Andric     m_struct_alignment = alignment;
480b57cec5SDimitry Andric 
490b57cec5SDimitry Andric   if (m_current_offset % alignment)
500b57cec5SDimitry Andric     m_current_offset += (alignment - (m_current_offset % alignment));
510b57cec5SDimitry Andric 
520b57cec5SDimitry Andric   ret = m_current_offset;
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric   m_current_offset += size;
550b57cec5SDimitry Andric 
560b57cec5SDimitry Andric   return ret;
570b57cec5SDimitry Andric }
580b57cec5SDimitry Andric 
590b57cec5SDimitry Andric class EntityPersistentVariable : public Materializer::Entity {
600b57cec5SDimitry Andric public:
EntityPersistentVariable(lldb::ExpressionVariableSP & persistent_variable_sp,Materializer::PersistentVariableDelegate * delegate)610b57cec5SDimitry Andric   EntityPersistentVariable(lldb::ExpressionVariableSP &persistent_variable_sp,
620b57cec5SDimitry Andric                            Materializer::PersistentVariableDelegate *delegate)
630b57cec5SDimitry Andric       : Entity(), m_persistent_variable_sp(persistent_variable_sp),
640b57cec5SDimitry Andric         m_delegate(delegate) {
650b57cec5SDimitry Andric     // Hard-coding to maximum size of a pointer since persistent variables are
660b57cec5SDimitry Andric     // materialized by reference
67fcaf7f86SDimitry Andric     m_size = g_default_var_byte_size;
68fcaf7f86SDimitry Andric     m_alignment = g_default_var_alignment;
690b57cec5SDimitry Andric   }
700b57cec5SDimitry Andric 
MakeAllocation(IRMemoryMap & map,Status & err)710b57cec5SDimitry Andric   void MakeAllocation(IRMemoryMap &map, Status &err) {
7281ad6265SDimitry Andric     Log *log = GetLog(LLDBLog::Expressions);
730b57cec5SDimitry Andric 
740b57cec5SDimitry Andric     // Allocate a spare memory area to store the persistent variable's
750b57cec5SDimitry Andric     // contents.
760b57cec5SDimitry Andric 
770b57cec5SDimitry Andric     Status allocate_error;
780b57cec5SDimitry Andric     const bool zero_memory = false;
790b57cec5SDimitry Andric 
800b57cec5SDimitry Andric     lldb::addr_t mem = map.Malloc(
8181ad6265SDimitry Andric         m_persistent_variable_sp->GetByteSize().value_or(0), 8,
820b57cec5SDimitry Andric         lldb::ePermissionsReadable | lldb::ePermissionsWritable,
830b57cec5SDimitry Andric         IRMemoryMap::eAllocationPolicyMirror, zero_memory, allocate_error);
840b57cec5SDimitry Andric 
850b57cec5SDimitry Andric     if (!allocate_error.Success()) {
860b57cec5SDimitry Andric       err.SetErrorStringWithFormat(
870b57cec5SDimitry Andric           "couldn't allocate a memory area to store %s: %s",
880b57cec5SDimitry Andric           m_persistent_variable_sp->GetName().GetCString(),
890b57cec5SDimitry Andric           allocate_error.AsCString());
900b57cec5SDimitry Andric       return;
910b57cec5SDimitry Andric     }
920b57cec5SDimitry Andric 
939dba64beSDimitry Andric     LLDB_LOGF(log, "Allocated %s (0x%" PRIx64 ") successfully",
940b57cec5SDimitry Andric               m_persistent_variable_sp->GetName().GetCString(), mem);
950b57cec5SDimitry Andric 
960b57cec5SDimitry Andric     // Put the location of the spare memory into the live data of the
970b57cec5SDimitry Andric     // ValueObject.
980b57cec5SDimitry Andric 
990b57cec5SDimitry Andric     m_persistent_variable_sp->m_live_sp = ValueObjectConstResult::Create(
1000b57cec5SDimitry Andric         map.GetBestExecutionContextScope(),
1010b57cec5SDimitry Andric         m_persistent_variable_sp->GetCompilerType(),
1020b57cec5SDimitry Andric         m_persistent_variable_sp->GetName(), mem, eAddressTypeLoad,
1030b57cec5SDimitry Andric         map.GetAddressByteSize());
1040b57cec5SDimitry Andric 
1050b57cec5SDimitry Andric     // Clear the flag if the variable will never be deallocated.
1060b57cec5SDimitry Andric 
1070b57cec5SDimitry Andric     if (m_persistent_variable_sp->m_flags &
1080b57cec5SDimitry Andric         ExpressionVariable::EVKeepInTarget) {
1090b57cec5SDimitry Andric       Status leak_error;
1100b57cec5SDimitry Andric       map.Leak(mem, leak_error);
1110b57cec5SDimitry Andric       m_persistent_variable_sp->m_flags &=
1120b57cec5SDimitry Andric           ~ExpressionVariable::EVNeedsAllocation;
1130b57cec5SDimitry Andric     }
1140b57cec5SDimitry Andric 
1150b57cec5SDimitry Andric     // Write the contents of the variable to the area.
1160b57cec5SDimitry Andric 
1170b57cec5SDimitry Andric     Status write_error;
1180b57cec5SDimitry Andric 
1190b57cec5SDimitry Andric     map.WriteMemory(mem, m_persistent_variable_sp->GetValueBytes(),
12081ad6265SDimitry Andric                     m_persistent_variable_sp->GetByteSize().value_or(0),
121e8d8bef9SDimitry Andric                     write_error);
1220b57cec5SDimitry Andric 
1230b57cec5SDimitry Andric     if (!write_error.Success()) {
1240b57cec5SDimitry Andric       err.SetErrorStringWithFormat(
1250b57cec5SDimitry Andric           "couldn't write %s to the target: %s",
1260b57cec5SDimitry Andric           m_persistent_variable_sp->GetName().AsCString(),
1270b57cec5SDimitry Andric           write_error.AsCString());
1280b57cec5SDimitry Andric       return;
1290b57cec5SDimitry Andric     }
1300b57cec5SDimitry Andric   }
1310b57cec5SDimitry Andric 
DestroyAllocation(IRMemoryMap & map,Status & err)1320b57cec5SDimitry Andric   void DestroyAllocation(IRMemoryMap &map, Status &err) {
1330b57cec5SDimitry Andric     Status deallocate_error;
1340b57cec5SDimitry Andric 
1350b57cec5SDimitry Andric     map.Free((lldb::addr_t)m_persistent_variable_sp->m_live_sp->GetValue()
1360b57cec5SDimitry Andric                  .GetScalar()
1370b57cec5SDimitry Andric                  .ULongLong(),
1380b57cec5SDimitry Andric              deallocate_error);
1390b57cec5SDimitry Andric 
1400b57cec5SDimitry Andric     m_persistent_variable_sp->m_live_sp.reset();
1410b57cec5SDimitry Andric 
1420b57cec5SDimitry Andric     if (!deallocate_error.Success()) {
1430b57cec5SDimitry Andric       err.SetErrorStringWithFormat(
1440b57cec5SDimitry Andric           "couldn't deallocate memory for %s: %s",
1450b57cec5SDimitry Andric           m_persistent_variable_sp->GetName().GetCString(),
1460b57cec5SDimitry Andric           deallocate_error.AsCString());
1470b57cec5SDimitry Andric     }
1480b57cec5SDimitry Andric   }
1490b57cec5SDimitry Andric 
Materialize(lldb::StackFrameSP & frame_sp,IRMemoryMap & map,lldb::addr_t process_address,Status & err)1500b57cec5SDimitry Andric   void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1510b57cec5SDimitry Andric                    lldb::addr_t process_address, Status &err) override {
15281ad6265SDimitry Andric     Log *log = GetLog(LLDBLog::Expressions);
1530b57cec5SDimitry Andric 
1540b57cec5SDimitry Andric     const lldb::addr_t load_addr = process_address + m_offset;
1550b57cec5SDimitry Andric 
1560b57cec5SDimitry Andric     if (log) {
1579dba64beSDimitry Andric       LLDB_LOGF(log,
1589dba64beSDimitry Andric                 "EntityPersistentVariable::Materialize [address = 0x%" PRIx64
1590b57cec5SDimitry Andric                 ", m_name = %s, m_flags = 0x%hx]",
1600b57cec5SDimitry Andric                 (uint64_t)load_addr,
1610b57cec5SDimitry Andric                 m_persistent_variable_sp->GetName().AsCString(),
1620b57cec5SDimitry Andric                 m_persistent_variable_sp->m_flags);
1630b57cec5SDimitry Andric     }
1640b57cec5SDimitry Andric 
1650b57cec5SDimitry Andric     if (m_persistent_variable_sp->m_flags &
1660b57cec5SDimitry Andric         ExpressionVariable::EVNeedsAllocation) {
1670b57cec5SDimitry Andric       MakeAllocation(map, err);
1680b57cec5SDimitry Andric       m_persistent_variable_sp->m_flags |=
1690b57cec5SDimitry Andric           ExpressionVariable::EVIsLLDBAllocated;
1700b57cec5SDimitry Andric 
1710b57cec5SDimitry Andric       if (!err.Success())
1720b57cec5SDimitry Andric         return;
1730b57cec5SDimitry Andric     }
1740b57cec5SDimitry Andric 
1750b57cec5SDimitry Andric     if ((m_persistent_variable_sp->m_flags &
1760b57cec5SDimitry Andric              ExpressionVariable::EVIsProgramReference &&
1770b57cec5SDimitry Andric          m_persistent_variable_sp->m_live_sp) ||
1780b57cec5SDimitry Andric         m_persistent_variable_sp->m_flags &
1790b57cec5SDimitry Andric             ExpressionVariable::EVIsLLDBAllocated) {
1800b57cec5SDimitry Andric       Status write_error;
1810b57cec5SDimitry Andric 
1820b57cec5SDimitry Andric       map.WriteScalarToMemory(
1830b57cec5SDimitry Andric           load_addr,
1840b57cec5SDimitry Andric           m_persistent_variable_sp->m_live_sp->GetValue().GetScalar(),
1850b57cec5SDimitry Andric           map.GetAddressByteSize(), write_error);
1860b57cec5SDimitry Andric 
1870b57cec5SDimitry Andric       if (!write_error.Success()) {
1880b57cec5SDimitry Andric         err.SetErrorStringWithFormat(
1890b57cec5SDimitry Andric             "couldn't write the location of %s to memory: %s",
1900b57cec5SDimitry Andric             m_persistent_variable_sp->GetName().AsCString(),
1910b57cec5SDimitry Andric             write_error.AsCString());
1920b57cec5SDimitry Andric       }
1930b57cec5SDimitry Andric     } else {
1940b57cec5SDimitry Andric       err.SetErrorStringWithFormat(
1950b57cec5SDimitry Andric           "no materialization happened for persistent variable %s",
1960b57cec5SDimitry Andric           m_persistent_variable_sp->GetName().AsCString());
1970b57cec5SDimitry Andric       return;
1980b57cec5SDimitry Andric     }
1990b57cec5SDimitry Andric   }
2000b57cec5SDimitry Andric 
Dematerialize(lldb::StackFrameSP & frame_sp,IRMemoryMap & map,lldb::addr_t process_address,lldb::addr_t frame_top,lldb::addr_t frame_bottom,Status & err)2010b57cec5SDimitry Andric   void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
2020b57cec5SDimitry Andric                      lldb::addr_t process_address, lldb::addr_t frame_top,
2030b57cec5SDimitry Andric                      lldb::addr_t frame_bottom, Status &err) override {
20481ad6265SDimitry Andric     Log *log = GetLog(LLDBLog::Expressions);
2050b57cec5SDimitry Andric 
2060b57cec5SDimitry Andric     const lldb::addr_t load_addr = process_address + m_offset;
2070b57cec5SDimitry Andric 
2080b57cec5SDimitry Andric     if (log) {
2099dba64beSDimitry Andric       LLDB_LOGF(log,
2100b57cec5SDimitry Andric                 "EntityPersistentVariable::Dematerialize [address = 0x%" PRIx64
2110b57cec5SDimitry Andric                 ", m_name = %s, m_flags = 0x%hx]",
2120b57cec5SDimitry Andric                 (uint64_t)process_address + m_offset,
2130b57cec5SDimitry Andric                 m_persistent_variable_sp->GetName().AsCString(),
2140b57cec5SDimitry Andric                 m_persistent_variable_sp->m_flags);
2150b57cec5SDimitry Andric     }
2160b57cec5SDimitry Andric 
2170b57cec5SDimitry Andric     if (m_delegate) {
2180b57cec5SDimitry Andric       m_delegate->DidDematerialize(m_persistent_variable_sp);
2190b57cec5SDimitry Andric     }
2200b57cec5SDimitry Andric 
2210b57cec5SDimitry Andric     if ((m_persistent_variable_sp->m_flags &
2220b57cec5SDimitry Andric          ExpressionVariable::EVIsLLDBAllocated) ||
2230b57cec5SDimitry Andric         (m_persistent_variable_sp->m_flags &
2240b57cec5SDimitry Andric          ExpressionVariable::EVIsProgramReference)) {
2250b57cec5SDimitry Andric       if (m_persistent_variable_sp->m_flags &
2260b57cec5SDimitry Andric               ExpressionVariable::EVIsProgramReference &&
2270b57cec5SDimitry Andric           !m_persistent_variable_sp->m_live_sp) {
2280b57cec5SDimitry Andric         // If the reference comes from the program, then the
2290b57cec5SDimitry Andric         // ClangExpressionVariable's live variable data hasn't been set up yet.
2300b57cec5SDimitry Andric         // Do this now.
2310b57cec5SDimitry Andric 
2320b57cec5SDimitry Andric         lldb::addr_t location;
2330b57cec5SDimitry Andric         Status read_error;
2340b57cec5SDimitry Andric 
2350b57cec5SDimitry Andric         map.ReadPointerFromMemory(&location, load_addr, read_error);
2360b57cec5SDimitry Andric 
2370b57cec5SDimitry Andric         if (!read_error.Success()) {
2380b57cec5SDimitry Andric           err.SetErrorStringWithFormat(
2390b57cec5SDimitry Andric               "couldn't read the address of program-allocated variable %s: %s",
2400b57cec5SDimitry Andric               m_persistent_variable_sp->GetName().GetCString(),
2410b57cec5SDimitry Andric               read_error.AsCString());
2420b57cec5SDimitry Andric           return;
2430b57cec5SDimitry Andric         }
2440b57cec5SDimitry Andric 
2450b57cec5SDimitry Andric         m_persistent_variable_sp->m_live_sp = ValueObjectConstResult::Create(
2460b57cec5SDimitry Andric             map.GetBestExecutionContextScope(),
2470b57cec5SDimitry Andric             m_persistent_variable_sp.get()->GetCompilerType(),
2480b57cec5SDimitry Andric             m_persistent_variable_sp->GetName(), location, eAddressTypeLoad,
24981ad6265SDimitry Andric             m_persistent_variable_sp->GetByteSize().value_or(0));
2500b57cec5SDimitry Andric 
2510b57cec5SDimitry Andric         if (frame_top != LLDB_INVALID_ADDRESS &&
2520b57cec5SDimitry Andric             frame_bottom != LLDB_INVALID_ADDRESS && location >= frame_bottom &&
2530b57cec5SDimitry Andric             location <= frame_top) {
2540b57cec5SDimitry Andric           // If the variable is resident in the stack frame created by the
2550b57cec5SDimitry Andric           // expression, then it cannot be relied upon to stay around.  We
2560b57cec5SDimitry Andric           // treat it as needing reallocation.
2570b57cec5SDimitry Andric           m_persistent_variable_sp->m_flags |=
2580b57cec5SDimitry Andric               ExpressionVariable::EVIsLLDBAllocated;
2590b57cec5SDimitry Andric           m_persistent_variable_sp->m_flags |=
2600b57cec5SDimitry Andric               ExpressionVariable::EVNeedsAllocation;
2610b57cec5SDimitry Andric           m_persistent_variable_sp->m_flags |=
2620b57cec5SDimitry Andric               ExpressionVariable::EVNeedsFreezeDry;
2630b57cec5SDimitry Andric           m_persistent_variable_sp->m_flags &=
2640b57cec5SDimitry Andric               ~ExpressionVariable::EVIsProgramReference;
2650b57cec5SDimitry Andric         }
2660b57cec5SDimitry Andric       }
2670b57cec5SDimitry Andric 
2680b57cec5SDimitry Andric       lldb::addr_t mem = m_persistent_variable_sp->m_live_sp->GetValue()
2690b57cec5SDimitry Andric                              .GetScalar()
2700b57cec5SDimitry Andric                              .ULongLong();
2710b57cec5SDimitry Andric 
2720b57cec5SDimitry Andric       if (!m_persistent_variable_sp->m_live_sp) {
2730b57cec5SDimitry Andric         err.SetErrorStringWithFormat(
2740b57cec5SDimitry Andric             "couldn't find the memory area used to store %s",
2750b57cec5SDimitry Andric             m_persistent_variable_sp->GetName().GetCString());
2760b57cec5SDimitry Andric         return;
2770b57cec5SDimitry Andric       }
2780b57cec5SDimitry Andric 
2790b57cec5SDimitry Andric       if (m_persistent_variable_sp->m_live_sp->GetValue()
2800b57cec5SDimitry Andric               .GetValueAddressType() != eAddressTypeLoad) {
2810b57cec5SDimitry Andric         err.SetErrorStringWithFormat(
2820b57cec5SDimitry Andric             "the address of the memory area for %s is in an incorrect format",
2830b57cec5SDimitry Andric             m_persistent_variable_sp->GetName().GetCString());
2840b57cec5SDimitry Andric         return;
2850b57cec5SDimitry Andric       }
2860b57cec5SDimitry Andric 
2870b57cec5SDimitry Andric       if (m_persistent_variable_sp->m_flags &
2880b57cec5SDimitry Andric               ExpressionVariable::EVNeedsFreezeDry ||
2890b57cec5SDimitry Andric           m_persistent_variable_sp->m_flags &
2900b57cec5SDimitry Andric               ExpressionVariable::EVKeepInTarget) {
2919dba64beSDimitry Andric         LLDB_LOGF(log, "Dematerializing %s from 0x%" PRIx64 " (size = %llu)",
2929dba64beSDimitry Andric                   m_persistent_variable_sp->GetName().GetCString(),
2939dba64beSDimitry Andric                   (uint64_t)mem,
294e8d8bef9SDimitry Andric                   (unsigned long long)m_persistent_variable_sp->GetByteSize()
29581ad6265SDimitry Andric                       .value_or(0));
2960b57cec5SDimitry Andric 
2970b57cec5SDimitry Andric         // Read the contents of the spare memory area
2980b57cec5SDimitry Andric 
2990b57cec5SDimitry Andric         m_persistent_variable_sp->ValueUpdated();
3000b57cec5SDimitry Andric 
3010b57cec5SDimitry Andric         Status read_error;
3020b57cec5SDimitry Andric 
3030b57cec5SDimitry Andric         map.ReadMemory(m_persistent_variable_sp->GetValueBytes(), mem,
30481ad6265SDimitry Andric                        m_persistent_variable_sp->GetByteSize().value_or(0),
30581ad6265SDimitry Andric                        read_error);
3060b57cec5SDimitry Andric 
3070b57cec5SDimitry Andric         if (!read_error.Success()) {
3080b57cec5SDimitry Andric           err.SetErrorStringWithFormat(
3090b57cec5SDimitry Andric               "couldn't read the contents of %s from memory: %s",
3100b57cec5SDimitry Andric               m_persistent_variable_sp->GetName().GetCString(),
3110b57cec5SDimitry Andric               read_error.AsCString());
3120b57cec5SDimitry Andric           return;
3130b57cec5SDimitry Andric         }
3140b57cec5SDimitry Andric 
3150b57cec5SDimitry Andric         m_persistent_variable_sp->m_flags &=
3160b57cec5SDimitry Andric             ~ExpressionVariable::EVNeedsFreezeDry;
3170b57cec5SDimitry Andric       }
3180b57cec5SDimitry Andric     } else {
3190b57cec5SDimitry Andric       err.SetErrorStringWithFormat(
3200b57cec5SDimitry Andric           "no dematerialization happened for persistent variable %s",
3210b57cec5SDimitry Andric           m_persistent_variable_sp->GetName().AsCString());
3220b57cec5SDimitry Andric       return;
3230b57cec5SDimitry Andric     }
3240b57cec5SDimitry Andric 
3250b57cec5SDimitry Andric     lldb::ProcessSP process_sp =
3260b57cec5SDimitry Andric         map.GetBestExecutionContextScope()->CalculateProcess();
3270b57cec5SDimitry Andric     if (!process_sp || !process_sp->CanJIT()) {
3280b57cec5SDimitry Andric       // Allocations are not persistent so persistent variables cannot stay
3290b57cec5SDimitry Andric       // materialized.
3300b57cec5SDimitry Andric 
3310b57cec5SDimitry Andric       m_persistent_variable_sp->m_flags |=
3320b57cec5SDimitry Andric           ExpressionVariable::EVNeedsAllocation;
3330b57cec5SDimitry Andric 
3340b57cec5SDimitry Andric       DestroyAllocation(map, err);
3350b57cec5SDimitry Andric       if (!err.Success())
3360b57cec5SDimitry Andric         return;
3370b57cec5SDimitry Andric     } else if (m_persistent_variable_sp->m_flags &
3380b57cec5SDimitry Andric                    ExpressionVariable::EVNeedsAllocation &&
3390b57cec5SDimitry Andric                !(m_persistent_variable_sp->m_flags &
3400b57cec5SDimitry Andric                  ExpressionVariable::EVKeepInTarget)) {
3410b57cec5SDimitry Andric       DestroyAllocation(map, err);
3420b57cec5SDimitry Andric       if (!err.Success())
3430b57cec5SDimitry Andric         return;
3440b57cec5SDimitry Andric     }
3450b57cec5SDimitry Andric   }
3460b57cec5SDimitry Andric 
DumpToLog(IRMemoryMap & map,lldb::addr_t process_address,Log * log)3470b57cec5SDimitry Andric   void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
3480b57cec5SDimitry Andric                  Log *log) override {
3490b57cec5SDimitry Andric     StreamString dump_stream;
3500b57cec5SDimitry Andric 
3510b57cec5SDimitry Andric     Status err;
3520b57cec5SDimitry Andric 
3530b57cec5SDimitry Andric     const lldb::addr_t load_addr = process_address + m_offset;
3540b57cec5SDimitry Andric 
3550b57cec5SDimitry Andric     dump_stream.Printf("0x%" PRIx64 ": EntityPersistentVariable (%s)\n",
3560b57cec5SDimitry Andric                        load_addr,
3570b57cec5SDimitry Andric                        m_persistent_variable_sp->GetName().AsCString());
3580b57cec5SDimitry Andric 
3590b57cec5SDimitry Andric     {
3600b57cec5SDimitry Andric       dump_stream.Printf("Pointer:\n");
3610b57cec5SDimitry Andric 
3620b57cec5SDimitry Andric       DataBufferHeap data(m_size, 0);
3630b57cec5SDimitry Andric 
3640b57cec5SDimitry Andric       map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
3650b57cec5SDimitry Andric 
3660b57cec5SDimitry Andric       if (!err.Success()) {
3670b57cec5SDimitry Andric         dump_stream.Printf("  <could not be read>\n");
3680b57cec5SDimitry Andric       } else {
3690b57cec5SDimitry Andric         DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
3700b57cec5SDimitry Andric                      load_addr);
3710b57cec5SDimitry Andric 
3720b57cec5SDimitry Andric         dump_stream.PutChar('\n');
3730b57cec5SDimitry Andric       }
3740b57cec5SDimitry Andric     }
3750b57cec5SDimitry Andric 
3760b57cec5SDimitry Andric     {
3770b57cec5SDimitry Andric       dump_stream.Printf("Target:\n");
3780b57cec5SDimitry Andric 
3790b57cec5SDimitry Andric       lldb::addr_t target_address;
3800b57cec5SDimitry Andric 
3810b57cec5SDimitry Andric       map.ReadPointerFromMemory(&target_address, load_addr, err);
3820b57cec5SDimitry Andric 
3830b57cec5SDimitry Andric       if (!err.Success()) {
3840b57cec5SDimitry Andric         dump_stream.Printf("  <could not be read>\n");
3850b57cec5SDimitry Andric       } else {
38681ad6265SDimitry Andric         DataBufferHeap data(m_persistent_variable_sp->GetByteSize().value_or(0),
38781ad6265SDimitry Andric                             0);
3880b57cec5SDimitry Andric 
3890b57cec5SDimitry Andric         map.ReadMemory(data.GetBytes(), target_address,
39081ad6265SDimitry Andric                        m_persistent_variable_sp->GetByteSize().value_or(0),
39181ad6265SDimitry Andric                        err);
3920b57cec5SDimitry Andric 
3930b57cec5SDimitry Andric         if (!err.Success()) {
3940b57cec5SDimitry Andric           dump_stream.Printf("  <could not be read>\n");
3950b57cec5SDimitry Andric         } else {
3960b57cec5SDimitry Andric           DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
3970b57cec5SDimitry Andric                        target_address);
3980b57cec5SDimitry Andric 
3990b57cec5SDimitry Andric           dump_stream.PutChar('\n');
4000b57cec5SDimitry Andric         }
4010b57cec5SDimitry Andric       }
4020b57cec5SDimitry Andric     }
4030b57cec5SDimitry Andric 
4040b57cec5SDimitry Andric     log->PutString(dump_stream.GetString());
4050b57cec5SDimitry Andric   }
4060b57cec5SDimitry Andric 
Wipe(IRMemoryMap & map,lldb::addr_t process_address)4070b57cec5SDimitry Andric   void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {}
4080b57cec5SDimitry Andric 
4090b57cec5SDimitry Andric private:
4100b57cec5SDimitry Andric   lldb::ExpressionVariableSP m_persistent_variable_sp;
4110b57cec5SDimitry Andric   Materializer::PersistentVariableDelegate *m_delegate;
4120b57cec5SDimitry Andric };
4130b57cec5SDimitry Andric 
AddPersistentVariable(lldb::ExpressionVariableSP & persistent_variable_sp,PersistentVariableDelegate * delegate,Status & err)4140b57cec5SDimitry Andric uint32_t Materializer::AddPersistentVariable(
4150b57cec5SDimitry Andric     lldb::ExpressionVariableSP &persistent_variable_sp,
4160b57cec5SDimitry Andric     PersistentVariableDelegate *delegate, Status &err) {
4170b57cec5SDimitry Andric   EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
4185ffd83dbSDimitry Andric   *iter = std::make_unique<EntityPersistentVariable>(persistent_variable_sp,
4195ffd83dbSDimitry Andric                                                      delegate);
4200b57cec5SDimitry Andric   uint32_t ret = AddStructMember(**iter);
4210b57cec5SDimitry Andric   (*iter)->SetOffset(ret);
4220b57cec5SDimitry Andric   return ret;
4230b57cec5SDimitry Andric }
4240b57cec5SDimitry Andric 
425fcaf7f86SDimitry Andric /// Base class for materialization of Variables and ValueObjects.
426fcaf7f86SDimitry Andric ///
427fcaf7f86SDimitry Andric /// Subclasses specify how to obtain the Value which is to be
428fcaf7f86SDimitry Andric /// materialized.
429fcaf7f86SDimitry Andric class EntityVariableBase : public Materializer::Entity {
4300b57cec5SDimitry Andric public:
431fcaf7f86SDimitry Andric   virtual ~EntityVariableBase() = default;
432fcaf7f86SDimitry Andric 
EntityVariableBase()433fcaf7f86SDimitry Andric   EntityVariableBase() {
4340b57cec5SDimitry Andric     // Hard-coding to maximum size of a pointer since all variables are
4350b57cec5SDimitry Andric     // materialized by reference
436fcaf7f86SDimitry Andric     m_size = g_default_var_byte_size;
437fcaf7f86SDimitry Andric     m_alignment = g_default_var_alignment;
4380b57cec5SDimitry Andric   }
4390b57cec5SDimitry Andric 
Materialize(lldb::StackFrameSP & frame_sp,IRMemoryMap & map,lldb::addr_t process_address,Status & err)4400b57cec5SDimitry Andric   void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
4410b57cec5SDimitry Andric                    lldb::addr_t process_address, Status &err) override {
44281ad6265SDimitry Andric     Log *log = GetLog(LLDBLog::Expressions);
4430b57cec5SDimitry Andric 
4440b57cec5SDimitry Andric     const lldb::addr_t load_addr = process_address + m_offset;
4450b57cec5SDimitry Andric     if (log) {
4469dba64beSDimitry Andric       LLDB_LOGF(log,
4479dba64beSDimitry Andric                 "EntityVariable::Materialize [address = 0x%" PRIx64
4480b57cec5SDimitry Andric                 ", m_variable_sp = %s]",
449fcaf7f86SDimitry Andric                 (uint64_t)load_addr, GetName().GetCString());
4500b57cec5SDimitry Andric     }
4510b57cec5SDimitry Andric 
4520b57cec5SDimitry Andric     ExecutionContextScope *scope = frame_sp.get();
4530b57cec5SDimitry Andric 
4540b57cec5SDimitry Andric     if (!scope)
4550b57cec5SDimitry Andric       scope = map.GetBestExecutionContextScope();
4560b57cec5SDimitry Andric 
457fcaf7f86SDimitry Andric     lldb::ValueObjectSP valobj_sp = SetupValueObject(scope);
4580b57cec5SDimitry Andric 
4590b57cec5SDimitry Andric     if (!valobj_sp) {
4600b57cec5SDimitry Andric       err.SetErrorStringWithFormat(
461fcaf7f86SDimitry Andric           "couldn't get a value object for variable %s", GetName().AsCString());
4620b57cec5SDimitry Andric       return;
4630b57cec5SDimitry Andric     }
4640b57cec5SDimitry Andric 
4650b57cec5SDimitry Andric     Status valobj_error = valobj_sp->GetError();
4660b57cec5SDimitry Andric 
4670b57cec5SDimitry Andric     if (valobj_error.Fail()) {
4680b57cec5SDimitry Andric       err.SetErrorStringWithFormat("couldn't get the value of variable %s: %s",
469fcaf7f86SDimitry Andric                                    GetName().AsCString(),
4700b57cec5SDimitry Andric                                    valobj_error.AsCString());
4710b57cec5SDimitry Andric       return;
4720b57cec5SDimitry Andric     }
4730b57cec5SDimitry Andric 
4740b57cec5SDimitry Andric     if (m_is_reference) {
4750b57cec5SDimitry Andric       DataExtractor valobj_extractor;
4760b57cec5SDimitry Andric       Status extract_error;
4770b57cec5SDimitry Andric       valobj_sp->GetData(valobj_extractor, extract_error);
4780b57cec5SDimitry Andric 
4790b57cec5SDimitry Andric       if (!extract_error.Success()) {
4800b57cec5SDimitry Andric         err.SetErrorStringWithFormat(
4810b57cec5SDimitry Andric             "couldn't read contents of reference variable %s: %s",
482fcaf7f86SDimitry Andric             GetName().AsCString(), extract_error.AsCString());
4830b57cec5SDimitry Andric         return;
4840b57cec5SDimitry Andric       }
4850b57cec5SDimitry Andric 
4860b57cec5SDimitry Andric       lldb::offset_t offset = 0;
4870b57cec5SDimitry Andric       lldb::addr_t reference_addr = valobj_extractor.GetAddress(&offset);
4880b57cec5SDimitry Andric 
4890b57cec5SDimitry Andric       Status write_error;
4900b57cec5SDimitry Andric       map.WritePointerToMemory(load_addr, reference_addr, write_error);
4910b57cec5SDimitry Andric 
4920b57cec5SDimitry Andric       if (!write_error.Success()) {
4930b57cec5SDimitry Andric         err.SetErrorStringWithFormat("couldn't write the contents of reference "
4940b57cec5SDimitry Andric                                      "variable %s to memory: %s",
495fcaf7f86SDimitry Andric                                      GetName().AsCString(),
4960b57cec5SDimitry Andric                                      write_error.AsCString());
4970b57cec5SDimitry Andric         return;
4980b57cec5SDimitry Andric       }
4990b57cec5SDimitry Andric     } else {
5000b57cec5SDimitry Andric       AddressType address_type = eAddressTypeInvalid;
5010b57cec5SDimitry Andric       const bool scalar_is_load_address = false;
5020b57cec5SDimitry Andric       lldb::addr_t addr_of_valobj =
5030b57cec5SDimitry Andric           valobj_sp->GetAddressOf(scalar_is_load_address, &address_type);
5040b57cec5SDimitry Andric       if (addr_of_valobj != LLDB_INVALID_ADDRESS) {
5050b57cec5SDimitry Andric         Status write_error;
5060b57cec5SDimitry Andric         map.WritePointerToMemory(load_addr, addr_of_valobj, write_error);
5070b57cec5SDimitry Andric 
5080b57cec5SDimitry Andric         if (!write_error.Success()) {
5090b57cec5SDimitry Andric           err.SetErrorStringWithFormat(
5100b57cec5SDimitry Andric               "couldn't write the address of variable %s to memory: %s",
511fcaf7f86SDimitry Andric               GetName().AsCString(), write_error.AsCString());
5120b57cec5SDimitry Andric           return;
5130b57cec5SDimitry Andric         }
5140b57cec5SDimitry Andric       } else {
5150b57cec5SDimitry Andric         DataExtractor data;
5160b57cec5SDimitry Andric         Status extract_error;
5170b57cec5SDimitry Andric         valobj_sp->GetData(data, extract_error);
5180b57cec5SDimitry Andric         if (!extract_error.Success()) {
5190b57cec5SDimitry Andric           err.SetErrorStringWithFormat("couldn't get the value of %s: %s",
520fcaf7f86SDimitry Andric                                        GetName().AsCString(),
5210b57cec5SDimitry Andric                                        extract_error.AsCString());
5220b57cec5SDimitry Andric           return;
5230b57cec5SDimitry Andric         }
5240b57cec5SDimitry Andric 
5250b57cec5SDimitry Andric         if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
5260b57cec5SDimitry Andric           err.SetErrorStringWithFormat(
5270b57cec5SDimitry Andric               "trying to create a temporary region for %s but one exists",
528fcaf7f86SDimitry Andric               GetName().AsCString());
5290b57cec5SDimitry Andric           return;
5300b57cec5SDimitry Andric         }
5310b57cec5SDimitry Andric 
532fcaf7f86SDimitry Andric         if (data.GetByteSize() < GetByteSize(scope)) {
533fcaf7f86SDimitry Andric           if (data.GetByteSize() == 0 && !LocationExpressionIsValid()) {
5340b57cec5SDimitry Andric             err.SetErrorStringWithFormat("the variable '%s' has no location, "
5350b57cec5SDimitry Andric                                          "it may have been optimized out",
536fcaf7f86SDimitry Andric                                          GetName().AsCString());
5370b57cec5SDimitry Andric           } else {
5380b57cec5SDimitry Andric             err.SetErrorStringWithFormat(
5390b57cec5SDimitry Andric                 "size of variable %s (%" PRIu64
5400b57cec5SDimitry Andric                 ") is larger than the ValueObject's size (%" PRIu64 ")",
541fcaf7f86SDimitry Andric                 GetName().AsCString(), GetByteSize(scope).value_or(0),
5420b57cec5SDimitry Andric                 data.GetByteSize());
5430b57cec5SDimitry Andric           }
5440b57cec5SDimitry Andric           return;
5450b57cec5SDimitry Andric         }
5460b57cec5SDimitry Andric 
547bdd1243dSDimitry Andric         std::optional<size_t> opt_bit_align = GetTypeBitAlign(scope);
5489dba64beSDimitry Andric         if (!opt_bit_align) {
5499dba64beSDimitry Andric           err.SetErrorStringWithFormat("can't get the type alignment for %s",
550fcaf7f86SDimitry Andric                                        GetName().AsCString());
5519dba64beSDimitry Andric           return;
5529dba64beSDimitry Andric         }
5530b57cec5SDimitry Andric 
5549dba64beSDimitry Andric         size_t byte_align = (*opt_bit_align + 7) / 8;
5550b57cec5SDimitry Andric 
5560b57cec5SDimitry Andric         Status alloc_error;
5570b57cec5SDimitry Andric         const bool zero_memory = false;
5580b57cec5SDimitry Andric 
5590b57cec5SDimitry Andric         m_temporary_allocation = map.Malloc(
5600b57cec5SDimitry Andric             data.GetByteSize(), byte_align,
5610b57cec5SDimitry Andric             lldb::ePermissionsReadable | lldb::ePermissionsWritable,
5620b57cec5SDimitry Andric             IRMemoryMap::eAllocationPolicyMirror, zero_memory, alloc_error);
5630b57cec5SDimitry Andric 
5640b57cec5SDimitry Andric         m_temporary_allocation_size = data.GetByteSize();
5650b57cec5SDimitry Andric 
5660b57cec5SDimitry Andric         m_original_data = std::make_shared<DataBufferHeap>(data.GetDataStart(),
5670b57cec5SDimitry Andric                                                            data.GetByteSize());
5680b57cec5SDimitry Andric 
5690b57cec5SDimitry Andric         if (!alloc_error.Success()) {
5700b57cec5SDimitry Andric           err.SetErrorStringWithFormat(
5710b57cec5SDimitry Andric               "couldn't allocate a temporary region for %s: %s",
572fcaf7f86SDimitry Andric               GetName().AsCString(), alloc_error.AsCString());
5730b57cec5SDimitry Andric           return;
5740b57cec5SDimitry Andric         }
5750b57cec5SDimitry Andric 
5760b57cec5SDimitry Andric         Status write_error;
5770b57cec5SDimitry Andric 
5780b57cec5SDimitry Andric         map.WriteMemory(m_temporary_allocation, data.GetDataStart(),
5790b57cec5SDimitry Andric                         data.GetByteSize(), write_error);
5800b57cec5SDimitry Andric 
5810b57cec5SDimitry Andric         if (!write_error.Success()) {
5820b57cec5SDimitry Andric           err.SetErrorStringWithFormat(
5830b57cec5SDimitry Andric               "couldn't write to the temporary region for %s: %s",
584fcaf7f86SDimitry Andric               GetName().AsCString(), write_error.AsCString());
5850b57cec5SDimitry Andric           return;
5860b57cec5SDimitry Andric         }
5870b57cec5SDimitry Andric 
5880b57cec5SDimitry Andric         Status pointer_write_error;
5890b57cec5SDimitry Andric 
5900b57cec5SDimitry Andric         map.WritePointerToMemory(load_addr, m_temporary_allocation,
5910b57cec5SDimitry Andric                                  pointer_write_error);
5920b57cec5SDimitry Andric 
5930b57cec5SDimitry Andric         if (!pointer_write_error.Success()) {
5940b57cec5SDimitry Andric           err.SetErrorStringWithFormat(
5950b57cec5SDimitry Andric               "couldn't write the address of the temporary region for %s: %s",
596fcaf7f86SDimitry Andric               GetName().AsCString(), pointer_write_error.AsCString());
5970b57cec5SDimitry Andric         }
5980b57cec5SDimitry Andric       }
5990b57cec5SDimitry Andric     }
6000b57cec5SDimitry Andric   }
6010b57cec5SDimitry Andric 
Dematerialize(lldb::StackFrameSP & frame_sp,IRMemoryMap & map,lldb::addr_t process_address,lldb::addr_t frame_top,lldb::addr_t frame_bottom,Status & err)6020b57cec5SDimitry Andric   void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
6030b57cec5SDimitry Andric                      lldb::addr_t process_address, lldb::addr_t frame_top,
6040b57cec5SDimitry Andric                      lldb::addr_t frame_bottom, Status &err) override {
60581ad6265SDimitry Andric     Log *log = GetLog(LLDBLog::Expressions);
6060b57cec5SDimitry Andric 
6070b57cec5SDimitry Andric     const lldb::addr_t load_addr = process_address + m_offset;
6080b57cec5SDimitry Andric     if (log) {
6099dba64beSDimitry Andric       LLDB_LOGF(log,
6109dba64beSDimitry Andric                 "EntityVariable::Dematerialize [address = 0x%" PRIx64
6110b57cec5SDimitry Andric                 ", m_variable_sp = %s]",
612fcaf7f86SDimitry Andric                 (uint64_t)load_addr, GetName().AsCString());
6130b57cec5SDimitry Andric     }
6140b57cec5SDimitry Andric 
6150b57cec5SDimitry Andric     if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
6160b57cec5SDimitry Andric       ExecutionContextScope *scope = frame_sp.get();
6170b57cec5SDimitry Andric 
6180b57cec5SDimitry Andric       if (!scope)
6190b57cec5SDimitry Andric         scope = map.GetBestExecutionContextScope();
6200b57cec5SDimitry Andric 
621fcaf7f86SDimitry Andric       lldb::ValueObjectSP valobj_sp = SetupValueObject(scope);
6220b57cec5SDimitry Andric 
6230b57cec5SDimitry Andric       if (!valobj_sp) {
6240b57cec5SDimitry Andric         err.SetErrorStringWithFormat(
6250b57cec5SDimitry Andric             "couldn't get a value object for variable %s",
626fcaf7f86SDimitry Andric             GetName().AsCString());
6270b57cec5SDimitry Andric         return;
6280b57cec5SDimitry Andric       }
6290b57cec5SDimitry Andric 
6300b57cec5SDimitry Andric       lldb_private::DataExtractor data;
6310b57cec5SDimitry Andric 
6320b57cec5SDimitry Andric       Status extract_error;
6330b57cec5SDimitry Andric 
634e8d8bef9SDimitry Andric       map.GetMemoryData(data, m_temporary_allocation,
63581ad6265SDimitry Andric                         valobj_sp->GetByteSize().value_or(0), extract_error);
6360b57cec5SDimitry Andric 
6370b57cec5SDimitry Andric       if (!extract_error.Success()) {
6380b57cec5SDimitry Andric         err.SetErrorStringWithFormat("couldn't get the data for variable %s",
639fcaf7f86SDimitry Andric                                      GetName().AsCString());
6400b57cec5SDimitry Andric         return;
6410b57cec5SDimitry Andric       }
6420b57cec5SDimitry Andric 
6430b57cec5SDimitry Andric       bool actually_write = true;
6440b57cec5SDimitry Andric 
6450b57cec5SDimitry Andric       if (m_original_data) {
6460b57cec5SDimitry Andric         if ((data.GetByteSize() == m_original_data->GetByteSize()) &&
6470b57cec5SDimitry Andric             !memcmp(m_original_data->GetBytes(), data.GetDataStart(),
6480b57cec5SDimitry Andric                     data.GetByteSize())) {
6490b57cec5SDimitry Andric           actually_write = false;
6500b57cec5SDimitry Andric         }
6510b57cec5SDimitry Andric       }
6520b57cec5SDimitry Andric 
6530b57cec5SDimitry Andric       Status set_error;
6540b57cec5SDimitry Andric 
6550b57cec5SDimitry Andric       if (actually_write) {
6560b57cec5SDimitry Andric         valobj_sp->SetData(data, set_error);
6570b57cec5SDimitry Andric 
6580b57cec5SDimitry Andric         if (!set_error.Success()) {
6590b57cec5SDimitry Andric           err.SetErrorStringWithFormat(
6600b57cec5SDimitry Andric               "couldn't write the new contents of %s back into the variable",
661fcaf7f86SDimitry Andric               GetName().AsCString());
6620b57cec5SDimitry Andric           return;
6630b57cec5SDimitry Andric         }
6640b57cec5SDimitry Andric       }
6650b57cec5SDimitry Andric 
6660b57cec5SDimitry Andric       Status free_error;
6670b57cec5SDimitry Andric 
6680b57cec5SDimitry Andric       map.Free(m_temporary_allocation, free_error);
6690b57cec5SDimitry Andric 
6700b57cec5SDimitry Andric       if (!free_error.Success()) {
6710b57cec5SDimitry Andric         err.SetErrorStringWithFormat(
6720b57cec5SDimitry Andric             "couldn't free the temporary region for %s: %s",
673fcaf7f86SDimitry Andric             GetName().AsCString(), free_error.AsCString());
6740b57cec5SDimitry Andric         return;
6750b57cec5SDimitry Andric       }
6760b57cec5SDimitry Andric 
6770b57cec5SDimitry Andric       m_original_data.reset();
6780b57cec5SDimitry Andric       m_temporary_allocation = LLDB_INVALID_ADDRESS;
6790b57cec5SDimitry Andric       m_temporary_allocation_size = 0;
6800b57cec5SDimitry Andric     }
6810b57cec5SDimitry Andric   }
6820b57cec5SDimitry Andric 
DumpToLog(IRMemoryMap & map,lldb::addr_t process_address,Log * log)6830b57cec5SDimitry Andric   void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
6840b57cec5SDimitry Andric                  Log *log) override {
6850b57cec5SDimitry Andric     StreamString dump_stream;
6860b57cec5SDimitry Andric 
6870b57cec5SDimitry Andric     const lldb::addr_t load_addr = process_address + m_offset;
6880b57cec5SDimitry Andric     dump_stream.Printf("0x%" PRIx64 ": EntityVariable\n", load_addr);
6890b57cec5SDimitry Andric 
6900b57cec5SDimitry Andric     Status err;
6910b57cec5SDimitry Andric 
6920b57cec5SDimitry Andric     lldb::addr_t ptr = LLDB_INVALID_ADDRESS;
6930b57cec5SDimitry Andric 
6940b57cec5SDimitry Andric     {
6950b57cec5SDimitry Andric       dump_stream.Printf("Pointer:\n");
6960b57cec5SDimitry Andric 
6970b57cec5SDimitry Andric       DataBufferHeap data(m_size, 0);
6980b57cec5SDimitry Andric 
6990b57cec5SDimitry Andric       map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
7000b57cec5SDimitry Andric 
7010b57cec5SDimitry Andric       if (!err.Success()) {
7020b57cec5SDimitry Andric         dump_stream.Printf("  <could not be read>\n");
7030b57cec5SDimitry Andric       } else {
7040b57cec5SDimitry Andric         DataExtractor extractor(data.GetBytes(), data.GetByteSize(),
7050b57cec5SDimitry Andric                                 map.GetByteOrder(), map.GetAddressByteSize());
7060b57cec5SDimitry Andric 
7070b57cec5SDimitry Andric         DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
7080b57cec5SDimitry Andric                      load_addr);
7090b57cec5SDimitry Andric 
71004eeddc0SDimitry Andric         lldb::offset_t offset = 0;
7110b57cec5SDimitry Andric 
7125ffd83dbSDimitry Andric         ptr = extractor.GetAddress(&offset);
7130b57cec5SDimitry Andric 
7140b57cec5SDimitry Andric         dump_stream.PutChar('\n');
7150b57cec5SDimitry Andric       }
7160b57cec5SDimitry Andric     }
7170b57cec5SDimitry Andric 
7180b57cec5SDimitry Andric     if (m_temporary_allocation == LLDB_INVALID_ADDRESS) {
7190b57cec5SDimitry Andric       dump_stream.Printf("Points to process memory:\n");
7200b57cec5SDimitry Andric     } else {
7210b57cec5SDimitry Andric       dump_stream.Printf("Temporary allocation:\n");
7220b57cec5SDimitry Andric     }
7230b57cec5SDimitry Andric 
7240b57cec5SDimitry Andric     if (ptr == LLDB_INVALID_ADDRESS) {
7250b57cec5SDimitry Andric       dump_stream.Printf("  <could not be be found>\n");
7260b57cec5SDimitry Andric     } else {
7270b57cec5SDimitry Andric       DataBufferHeap data(m_temporary_allocation_size, 0);
7280b57cec5SDimitry Andric 
7290b57cec5SDimitry Andric       map.ReadMemory(data.GetBytes(), m_temporary_allocation,
7300b57cec5SDimitry Andric                      m_temporary_allocation_size, err);
7310b57cec5SDimitry Andric 
7320b57cec5SDimitry Andric       if (!err.Success()) {
7330b57cec5SDimitry Andric         dump_stream.Printf("  <could not be read>\n");
7340b57cec5SDimitry Andric       } else {
7350b57cec5SDimitry Andric         DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
7360b57cec5SDimitry Andric                      load_addr);
7370b57cec5SDimitry Andric 
7380b57cec5SDimitry Andric         dump_stream.PutChar('\n');
7390b57cec5SDimitry Andric       }
7400b57cec5SDimitry Andric     }
7410b57cec5SDimitry Andric 
7420b57cec5SDimitry Andric     log->PutString(dump_stream.GetString());
7430b57cec5SDimitry Andric   }
7440b57cec5SDimitry Andric 
Wipe(IRMemoryMap & map,lldb::addr_t process_address)7450b57cec5SDimitry Andric   void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {
7460b57cec5SDimitry Andric     if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
7470b57cec5SDimitry Andric       Status free_error;
7480b57cec5SDimitry Andric 
7490b57cec5SDimitry Andric       map.Free(m_temporary_allocation, free_error);
7500b57cec5SDimitry Andric 
7510b57cec5SDimitry Andric       m_temporary_allocation = LLDB_INVALID_ADDRESS;
7520b57cec5SDimitry Andric       m_temporary_allocation_size = 0;
7530b57cec5SDimitry Andric     }
7540b57cec5SDimitry Andric   }
7550b57cec5SDimitry Andric 
7560b57cec5SDimitry Andric private:
757fcaf7f86SDimitry Andric   virtual ConstString GetName() const = 0;
758fcaf7f86SDimitry Andric 
759fcaf7f86SDimitry Andric   /// Creates and returns ValueObject tied to this variable
760fcaf7f86SDimitry Andric   /// and prepares Entity for materialization.
761fcaf7f86SDimitry Andric   ///
762fcaf7f86SDimitry Andric   /// Called each time the Materializer (de)materializes a
763fcaf7f86SDimitry Andric   /// variable. We re-create the ValueObject based on the
764fcaf7f86SDimitry Andric   /// current ExecutionContextScope since clients such as
765fcaf7f86SDimitry Andric   /// conditional breakpoints may materialize the same
766fcaf7f86SDimitry Andric   /// EntityVariable multiple times with different frames.
767fcaf7f86SDimitry Andric   ///
768fcaf7f86SDimitry Andric   /// Each subsequent use of the EntityVariableBase interface
769fcaf7f86SDimitry Andric   /// will query the newly created ValueObject until this
770fcaf7f86SDimitry Andric   /// function is called again.
771fcaf7f86SDimitry Andric   virtual lldb::ValueObjectSP
772fcaf7f86SDimitry Andric   SetupValueObject(ExecutionContextScope *scope) = 0;
773fcaf7f86SDimitry Andric 
774fcaf7f86SDimitry Andric   /// Returns size in bytes of the type associated with this variable
775fcaf7f86SDimitry Andric   ///
776fcaf7f86SDimitry Andric   /// \returns On success, returns byte size of the type associated
777bdd1243dSDimitry Andric   ///          with this variable. Returns std::nullopt otherwise.
778bdd1243dSDimitry Andric   virtual std::optional<uint64_t>
779fcaf7f86SDimitry Andric   GetByteSize(ExecutionContextScope *scope) const = 0;
780fcaf7f86SDimitry Andric 
781fcaf7f86SDimitry Andric   /// Returns 'true' if the location expression associated with this variable
782fcaf7f86SDimitry Andric   /// is valid.
783fcaf7f86SDimitry Andric   virtual bool LocationExpressionIsValid() const = 0;
784fcaf7f86SDimitry Andric 
785fcaf7f86SDimitry Andric   /// Returns alignment of the type associated with this variable in bits.
786fcaf7f86SDimitry Andric   ///
787fcaf7f86SDimitry Andric   /// \returns On success, returns alignment in bits for the type associated
788bdd1243dSDimitry Andric   ///          with this variable. Returns std::nullopt otherwise.
789bdd1243dSDimitry Andric   virtual std::optional<size_t>
790fcaf7f86SDimitry Andric   GetTypeBitAlign(ExecutionContextScope *scope) const = 0;
791fcaf7f86SDimitry Andric 
792fcaf7f86SDimitry Andric protected:
79381ad6265SDimitry Andric   bool m_is_reference = false;
79481ad6265SDimitry Andric   lldb::addr_t m_temporary_allocation = LLDB_INVALID_ADDRESS;
79581ad6265SDimitry Andric   size_t m_temporary_allocation_size = 0;
7960b57cec5SDimitry Andric   lldb::DataBufferSP m_original_data;
7970b57cec5SDimitry Andric };
7980b57cec5SDimitry Andric 
799fcaf7f86SDimitry Andric /// Represents an Entity constructed from a VariableSP.
800fcaf7f86SDimitry Andric ///
801fcaf7f86SDimitry Andric /// This class is used for materialization of variables for which
802fcaf7f86SDimitry Andric /// the user has a VariableSP on hand. The ValueObject is then
803fcaf7f86SDimitry Andric /// derived from the associated DWARF location expression when needed
804fcaf7f86SDimitry Andric /// by the Materializer.
805fcaf7f86SDimitry Andric class EntityVariable : public EntityVariableBase {
806fcaf7f86SDimitry Andric public:
EntityVariable(lldb::VariableSP & variable_sp)807fcaf7f86SDimitry Andric   EntityVariable(lldb::VariableSP &variable_sp) : m_variable_sp(variable_sp) {
808fcaf7f86SDimitry Andric     m_is_reference =
809fcaf7f86SDimitry Andric         m_variable_sp->GetType()->GetForwardCompilerType().IsReferenceType();
810fcaf7f86SDimitry Andric   }
811fcaf7f86SDimitry Andric 
GetName() const812fcaf7f86SDimitry Andric   ConstString GetName() const override { return m_variable_sp->GetName(); }
813fcaf7f86SDimitry Andric 
SetupValueObject(ExecutionContextScope * scope)814fcaf7f86SDimitry Andric   lldb::ValueObjectSP SetupValueObject(ExecutionContextScope *scope) override {
815fcaf7f86SDimitry Andric     assert(m_variable_sp != nullptr);
816fcaf7f86SDimitry Andric     return ValueObjectVariable::Create(scope, m_variable_sp);
817fcaf7f86SDimitry Andric   }
818fcaf7f86SDimitry Andric 
819bdd1243dSDimitry Andric   std::optional<uint64_t>
GetByteSize(ExecutionContextScope * scope) const820fcaf7f86SDimitry Andric   GetByteSize(ExecutionContextScope *scope) const override {
821fcaf7f86SDimitry Andric     return m_variable_sp->GetType()->GetByteSize(scope);
822fcaf7f86SDimitry Andric   }
823fcaf7f86SDimitry Andric 
LocationExpressionIsValid() const824fcaf7f86SDimitry Andric   bool LocationExpressionIsValid() const override {
825fcaf7f86SDimitry Andric     return m_variable_sp->LocationExpressionList().IsValid();
826fcaf7f86SDimitry Andric   }
827fcaf7f86SDimitry Andric 
828bdd1243dSDimitry Andric   std::optional<size_t>
GetTypeBitAlign(ExecutionContextScope * scope) const829fcaf7f86SDimitry Andric   GetTypeBitAlign(ExecutionContextScope *scope) const override {
830fcaf7f86SDimitry Andric     return m_variable_sp->GetType()->GetLayoutCompilerType().GetTypeBitAlign(
831fcaf7f86SDimitry Andric         scope);
832fcaf7f86SDimitry Andric   }
833fcaf7f86SDimitry Andric 
834fcaf7f86SDimitry Andric private:
835fcaf7f86SDimitry Andric   lldb::VariableSP m_variable_sp; ///< Variable that this entity is based on.
836fcaf7f86SDimitry Andric };
837fcaf7f86SDimitry Andric 
838fcaf7f86SDimitry Andric /// Represents an Entity constructed from a VariableSP.
839fcaf7f86SDimitry Andric ///
840fcaf7f86SDimitry Andric /// This class is used for materialization of variables for
841fcaf7f86SDimitry Andric /// which the user does not have a VariableSP available (e.g.,
842fcaf7f86SDimitry Andric /// when materializing ivars).
843fcaf7f86SDimitry Andric class EntityValueObject : public EntityVariableBase {
844fcaf7f86SDimitry Andric public:
EntityValueObject(ConstString name,ValueObjectProviderTy provider)845fcaf7f86SDimitry Andric   EntityValueObject(ConstString name, ValueObjectProviderTy provider)
846fcaf7f86SDimitry Andric       : m_name(name), m_valobj_provider(std::move(provider)) {
847fcaf7f86SDimitry Andric     assert(m_valobj_provider);
848fcaf7f86SDimitry Andric   }
849fcaf7f86SDimitry Andric 
GetName() const850fcaf7f86SDimitry Andric   ConstString GetName() const override { return m_name; }
851fcaf7f86SDimitry Andric 
SetupValueObject(ExecutionContextScope * scope)852fcaf7f86SDimitry Andric   lldb::ValueObjectSP SetupValueObject(ExecutionContextScope *scope) override {
853fcaf7f86SDimitry Andric     m_valobj_sp =
854fcaf7f86SDimitry Andric         m_valobj_provider(GetName(), scope->CalculateStackFrame().get());
855fcaf7f86SDimitry Andric 
856fcaf7f86SDimitry Andric     if (m_valobj_sp)
857fcaf7f86SDimitry Andric       m_is_reference = m_valobj_sp->GetCompilerType().IsReferenceType();
858fcaf7f86SDimitry Andric 
859fcaf7f86SDimitry Andric     return m_valobj_sp;
860fcaf7f86SDimitry Andric   }
861fcaf7f86SDimitry Andric 
862bdd1243dSDimitry Andric   std::optional<uint64_t>
GetByteSize(ExecutionContextScope * scope) const863fcaf7f86SDimitry Andric   GetByteSize(ExecutionContextScope *scope) const override {
864fcaf7f86SDimitry Andric     if (m_valobj_sp)
865fcaf7f86SDimitry Andric       return m_valobj_sp->GetCompilerType().GetByteSize(scope);
866fcaf7f86SDimitry Andric 
867fcaf7f86SDimitry Andric     return {};
868fcaf7f86SDimitry Andric   }
869fcaf7f86SDimitry Andric 
LocationExpressionIsValid() const870fcaf7f86SDimitry Andric   bool LocationExpressionIsValid() const override {
871fcaf7f86SDimitry Andric     if (m_valobj_sp)
872fcaf7f86SDimitry Andric       return m_valobj_sp->GetError().Success();
873fcaf7f86SDimitry Andric 
874fcaf7f86SDimitry Andric     return false;
875fcaf7f86SDimitry Andric   }
876fcaf7f86SDimitry Andric 
877bdd1243dSDimitry Andric   std::optional<size_t>
GetTypeBitAlign(ExecutionContextScope * scope) const878fcaf7f86SDimitry Andric   GetTypeBitAlign(ExecutionContextScope *scope) const override {
879fcaf7f86SDimitry Andric     if (m_valobj_sp)
880fcaf7f86SDimitry Andric       return m_valobj_sp->GetCompilerType().GetTypeBitAlign(scope);
881fcaf7f86SDimitry Andric 
882fcaf7f86SDimitry Andric     return {};
883fcaf7f86SDimitry Andric   }
884fcaf7f86SDimitry Andric 
885fcaf7f86SDimitry Andric private:
886fcaf7f86SDimitry Andric   ConstString m_name;
887fcaf7f86SDimitry Andric   lldb::ValueObjectSP m_valobj_sp;
888fcaf7f86SDimitry Andric   ValueObjectProviderTy m_valobj_provider;
889fcaf7f86SDimitry Andric };
890fcaf7f86SDimitry Andric 
AddVariable(lldb::VariableSP & variable_sp,Status & err)8910b57cec5SDimitry Andric uint32_t Materializer::AddVariable(lldb::VariableSP &variable_sp, Status &err) {
8920b57cec5SDimitry Andric   EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
8935ffd83dbSDimitry Andric   *iter = std::make_unique<EntityVariable>(variable_sp);
8940b57cec5SDimitry Andric   uint32_t ret = AddStructMember(**iter);
8950b57cec5SDimitry Andric   (*iter)->SetOffset(ret);
8960b57cec5SDimitry Andric   return ret;
8970b57cec5SDimitry Andric }
8980b57cec5SDimitry Andric 
AddValueObject(ConstString name,ValueObjectProviderTy valobj_provider,Status & err)899fcaf7f86SDimitry Andric uint32_t Materializer::AddValueObject(ConstString name,
900fcaf7f86SDimitry Andric                                       ValueObjectProviderTy valobj_provider,
901fcaf7f86SDimitry Andric                                       Status &err) {
902fcaf7f86SDimitry Andric   assert(valobj_provider);
903fcaf7f86SDimitry Andric   EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
904fcaf7f86SDimitry Andric   *iter = std::make_unique<EntityValueObject>(name, std::move(valobj_provider));
905fcaf7f86SDimitry Andric   uint32_t ret = AddStructMember(**iter);
906fcaf7f86SDimitry Andric   (*iter)->SetOffset(ret);
907fcaf7f86SDimitry Andric   return ret;
908fcaf7f86SDimitry Andric }
909fcaf7f86SDimitry Andric 
9100b57cec5SDimitry Andric class EntityResultVariable : public Materializer::Entity {
9110b57cec5SDimitry Andric public:
EntityResultVariable(const CompilerType & type,bool is_program_reference,bool keep_in_memory,Materializer::PersistentVariableDelegate * delegate)9120b57cec5SDimitry Andric   EntityResultVariable(const CompilerType &type, bool is_program_reference,
9130b57cec5SDimitry Andric                        bool keep_in_memory,
9140b57cec5SDimitry Andric                        Materializer::PersistentVariableDelegate *delegate)
9150b57cec5SDimitry Andric       : Entity(), m_type(type), m_is_program_reference(is_program_reference),
91681ad6265SDimitry Andric         m_keep_in_memory(keep_in_memory), m_delegate(delegate) {
9170b57cec5SDimitry Andric     // Hard-coding to maximum size of a pointer since all results are
9180b57cec5SDimitry Andric     // materialized by reference
919fcaf7f86SDimitry Andric     m_size = g_default_var_byte_size;
920fcaf7f86SDimitry Andric     m_alignment = g_default_var_alignment;
9210b57cec5SDimitry Andric   }
9220b57cec5SDimitry Andric 
Materialize(lldb::StackFrameSP & frame_sp,IRMemoryMap & map,lldb::addr_t process_address,Status & err)9230b57cec5SDimitry Andric   void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
9240b57cec5SDimitry Andric                    lldb::addr_t process_address, Status &err) override {
9250b57cec5SDimitry Andric     if (!m_is_program_reference) {
9260b57cec5SDimitry Andric       if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
9270b57cec5SDimitry Andric         err.SetErrorString("Trying to create a temporary region for the result "
9280b57cec5SDimitry Andric                            "but one exists");
9290b57cec5SDimitry Andric         return;
9300b57cec5SDimitry Andric       }
9310b57cec5SDimitry Andric 
9320b57cec5SDimitry Andric       const lldb::addr_t load_addr = process_address + m_offset;
9330b57cec5SDimitry Andric 
9345ffd83dbSDimitry Andric       ExecutionContextScope *exe_scope = frame_sp.get();
9355ffd83dbSDimitry Andric       if (!exe_scope)
9365ffd83dbSDimitry Andric         exe_scope = map.GetBestExecutionContextScope();
9370b57cec5SDimitry Andric 
938bdd1243dSDimitry Andric       std::optional<uint64_t> byte_size = m_type.GetByteSize(exe_scope);
9390b57cec5SDimitry Andric       if (!byte_size) {
940fe6060f1SDimitry Andric         err.SetErrorStringWithFormat("can't get size of type \"%s\"",
941fe6060f1SDimitry Andric                                      m_type.GetTypeName().AsCString());
9420b57cec5SDimitry Andric         return;
9430b57cec5SDimitry Andric       }
9440b57cec5SDimitry Andric 
945bdd1243dSDimitry Andric       std::optional<size_t> opt_bit_align = m_type.GetTypeBitAlign(exe_scope);
9469dba64beSDimitry Andric       if (!opt_bit_align) {
947fe6060f1SDimitry Andric         err.SetErrorStringWithFormat("can't get the alignment of type  \"%s\"",
948fe6060f1SDimitry Andric                                      m_type.GetTypeName().AsCString());
9499dba64beSDimitry Andric         return;
9509dba64beSDimitry Andric       }
9519dba64beSDimitry Andric 
9529dba64beSDimitry Andric       size_t byte_align = (*opt_bit_align + 7) / 8;
9530b57cec5SDimitry Andric 
9540b57cec5SDimitry Andric       Status alloc_error;
9550b57cec5SDimitry Andric       const bool zero_memory = true;
9560b57cec5SDimitry Andric 
9570b57cec5SDimitry Andric       m_temporary_allocation = map.Malloc(
9580b57cec5SDimitry Andric           *byte_size, byte_align,
9590b57cec5SDimitry Andric           lldb::ePermissionsReadable | lldb::ePermissionsWritable,
9600b57cec5SDimitry Andric           IRMemoryMap::eAllocationPolicyMirror, zero_memory, alloc_error);
9610b57cec5SDimitry Andric       m_temporary_allocation_size = *byte_size;
9620b57cec5SDimitry Andric 
9630b57cec5SDimitry Andric       if (!alloc_error.Success()) {
9640b57cec5SDimitry Andric         err.SetErrorStringWithFormat(
9650b57cec5SDimitry Andric             "couldn't allocate a temporary region for the result: %s",
9660b57cec5SDimitry Andric             alloc_error.AsCString());
9670b57cec5SDimitry Andric         return;
9680b57cec5SDimitry Andric       }
9690b57cec5SDimitry Andric 
9700b57cec5SDimitry Andric       Status pointer_write_error;
9710b57cec5SDimitry Andric 
9720b57cec5SDimitry Andric       map.WritePointerToMemory(load_addr, m_temporary_allocation,
9730b57cec5SDimitry Andric                                pointer_write_error);
9740b57cec5SDimitry Andric 
9750b57cec5SDimitry Andric       if (!pointer_write_error.Success()) {
9760b57cec5SDimitry Andric         err.SetErrorStringWithFormat("couldn't write the address of the "
9770b57cec5SDimitry Andric                                      "temporary region for the result: %s",
9780b57cec5SDimitry Andric                                      pointer_write_error.AsCString());
9790b57cec5SDimitry Andric       }
9800b57cec5SDimitry Andric     }
9810b57cec5SDimitry Andric   }
9820b57cec5SDimitry Andric 
Dematerialize(lldb::StackFrameSP & frame_sp,IRMemoryMap & map,lldb::addr_t process_address,lldb::addr_t frame_top,lldb::addr_t frame_bottom,Status & err)9830b57cec5SDimitry Andric   void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
9840b57cec5SDimitry Andric                      lldb::addr_t process_address, lldb::addr_t frame_top,
9850b57cec5SDimitry Andric                      lldb::addr_t frame_bottom, Status &err) override {
9860b57cec5SDimitry Andric     err.Clear();
9870b57cec5SDimitry Andric 
9885ffd83dbSDimitry Andric     ExecutionContextScope *exe_scope = frame_sp.get();
9895ffd83dbSDimitry Andric     if (!exe_scope)
9905ffd83dbSDimitry Andric       exe_scope = map.GetBestExecutionContextScope();
9910b57cec5SDimitry Andric 
9920b57cec5SDimitry Andric     if (!exe_scope) {
9930b57cec5SDimitry Andric       err.SetErrorString("Couldn't dematerialize a result variable: invalid "
9940b57cec5SDimitry Andric                          "execution context scope");
9950b57cec5SDimitry Andric       return;
9960b57cec5SDimitry Andric     }
9970b57cec5SDimitry Andric 
9980b57cec5SDimitry Andric     lldb::addr_t address;
9990b57cec5SDimitry Andric     Status read_error;
10000b57cec5SDimitry Andric     const lldb::addr_t load_addr = process_address + m_offset;
10010b57cec5SDimitry Andric 
10020b57cec5SDimitry Andric     map.ReadPointerFromMemory(&address, load_addr, read_error);
10030b57cec5SDimitry Andric 
10040b57cec5SDimitry Andric     if (!read_error.Success()) {
10050b57cec5SDimitry Andric       err.SetErrorString("Couldn't dematerialize a result variable: couldn't "
10060b57cec5SDimitry Andric                          "read its address");
10070b57cec5SDimitry Andric       return;
10080b57cec5SDimitry Andric     }
10090b57cec5SDimitry Andric 
10100b57cec5SDimitry Andric     lldb::TargetSP target_sp = exe_scope->CalculateTarget();
10110b57cec5SDimitry Andric 
10120b57cec5SDimitry Andric     if (!target_sp) {
10130b57cec5SDimitry Andric       err.SetErrorString("Couldn't dematerialize a result variable: no target");
10140b57cec5SDimitry Andric       return;
10150b57cec5SDimitry Andric     }
10160b57cec5SDimitry Andric 
10179dba64beSDimitry Andric     auto type_system_or_err =
10189dba64beSDimitry Andric         target_sp->GetScratchTypeSystemForLanguage(m_type.GetMinimumLanguage());
10190b57cec5SDimitry Andric 
10209dba64beSDimitry Andric     if (auto error = type_system_or_err.takeError()) {
10210b57cec5SDimitry Andric       err.SetErrorStringWithFormat("Couldn't dematerialize a result variable: "
10220b57cec5SDimitry Andric                                    "couldn't get the corresponding type "
10230b57cec5SDimitry Andric                                    "system: %s",
10249dba64beSDimitry Andric                                    llvm::toString(std::move(error)).c_str());
10250b57cec5SDimitry Andric       return;
10260b57cec5SDimitry Andric     }
1027bdd1243dSDimitry Andric     auto ts = *type_system_or_err;
1028bdd1243dSDimitry Andric     if (!ts) {
1029bdd1243dSDimitry Andric       err.SetErrorStringWithFormat("Couldn't dematerialize a result variable: "
1030bdd1243dSDimitry Andric                                    "couldn't corresponding type system is "
1031bdd1243dSDimitry Andric                                    "no longer live.");
1032bdd1243dSDimitry Andric       return;
1033bdd1243dSDimitry Andric     }
10340b57cec5SDimitry Andric     PersistentExpressionState *persistent_state =
1035bdd1243dSDimitry Andric         ts->GetPersistentExpressionState();
10360b57cec5SDimitry Andric 
10370b57cec5SDimitry Andric     if (!persistent_state) {
10380b57cec5SDimitry Andric       err.SetErrorString("Couldn't dematerialize a result variable: "
10390b57cec5SDimitry Andric                          "corresponding type system doesn't handle persistent "
10400b57cec5SDimitry Andric                          "variables");
10410b57cec5SDimitry Andric       return;
10420b57cec5SDimitry Andric     }
10430b57cec5SDimitry Andric 
10445ffd83dbSDimitry Andric     ConstString name = m_delegate
10450b57cec5SDimitry Andric                            ? m_delegate->GetName()
10465ffd83dbSDimitry Andric                            : persistent_state->GetNextPersistentVariableName();
10470b57cec5SDimitry Andric 
10480b57cec5SDimitry Andric     lldb::ExpressionVariableSP ret = persistent_state->CreatePersistentVariable(
10490b57cec5SDimitry Andric         exe_scope, name, m_type, map.GetByteOrder(), map.GetAddressByteSize());
10500b57cec5SDimitry Andric 
10510b57cec5SDimitry Andric     if (!ret) {
10520b57cec5SDimitry Andric       err.SetErrorStringWithFormat("couldn't dematerialize a result variable: "
10530b57cec5SDimitry Andric                                    "failed to make persistent variable %s",
10540b57cec5SDimitry Andric                                    name.AsCString());
10550b57cec5SDimitry Andric       return;
10560b57cec5SDimitry Andric     }
10570b57cec5SDimitry Andric 
10580b57cec5SDimitry Andric     lldb::ProcessSP process_sp =
10590b57cec5SDimitry Andric         map.GetBestExecutionContextScope()->CalculateProcess();
10600b57cec5SDimitry Andric 
10610b57cec5SDimitry Andric     if (m_delegate) {
10620b57cec5SDimitry Andric       m_delegate->DidDematerialize(ret);
10630b57cec5SDimitry Andric     }
10640b57cec5SDimitry Andric 
10650b57cec5SDimitry Andric     bool can_persist =
10660b57cec5SDimitry Andric         (m_is_program_reference && process_sp && process_sp->CanJIT() &&
10670b57cec5SDimitry Andric          !(address >= frame_bottom && address < frame_top));
10680b57cec5SDimitry Andric 
10690b57cec5SDimitry Andric     if (can_persist && m_keep_in_memory) {
10700b57cec5SDimitry Andric       ret->m_live_sp = ValueObjectConstResult::Create(exe_scope, m_type, name,
10710b57cec5SDimitry Andric                                                       address, eAddressTypeLoad,
10720b57cec5SDimitry Andric                                                       map.GetAddressByteSize());
10730b57cec5SDimitry Andric     }
10740b57cec5SDimitry Andric 
10750b57cec5SDimitry Andric     ret->ValueUpdated();
10760b57cec5SDimitry Andric 
107781ad6265SDimitry Andric     const size_t pvar_byte_size = ret->GetByteSize().value_or(0);
10780b57cec5SDimitry Andric     uint8_t *pvar_data = ret->GetValueBytes();
10790b57cec5SDimitry Andric 
10800b57cec5SDimitry Andric     map.ReadMemory(pvar_data, address, pvar_byte_size, read_error);
10810b57cec5SDimitry Andric 
10820b57cec5SDimitry Andric     if (!read_error.Success()) {
10830b57cec5SDimitry Andric       err.SetErrorString(
10840b57cec5SDimitry Andric           "Couldn't dematerialize a result variable: couldn't read its memory");
10850b57cec5SDimitry Andric       return;
10860b57cec5SDimitry Andric     }
10870b57cec5SDimitry Andric 
10880b57cec5SDimitry Andric     if (!can_persist || !m_keep_in_memory) {
10890b57cec5SDimitry Andric       ret->m_flags |= ExpressionVariable::EVNeedsAllocation;
10900b57cec5SDimitry Andric 
10910b57cec5SDimitry Andric       if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
10920b57cec5SDimitry Andric         Status free_error;
10930b57cec5SDimitry Andric         map.Free(m_temporary_allocation, free_error);
10940b57cec5SDimitry Andric       }
10950b57cec5SDimitry Andric     } else {
10960b57cec5SDimitry Andric       ret->m_flags |= ExpressionVariable::EVIsLLDBAllocated;
10970b57cec5SDimitry Andric     }
10980b57cec5SDimitry Andric 
10990b57cec5SDimitry Andric     m_temporary_allocation = LLDB_INVALID_ADDRESS;
11000b57cec5SDimitry Andric     m_temporary_allocation_size = 0;
11010b57cec5SDimitry Andric   }
11020b57cec5SDimitry Andric 
DumpToLog(IRMemoryMap & map,lldb::addr_t process_address,Log * log)11030b57cec5SDimitry Andric   void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
11040b57cec5SDimitry Andric                  Log *log) override {
11050b57cec5SDimitry Andric     StreamString dump_stream;
11060b57cec5SDimitry Andric 
11070b57cec5SDimitry Andric     const lldb::addr_t load_addr = process_address + m_offset;
11080b57cec5SDimitry Andric 
11090b57cec5SDimitry Andric     dump_stream.Printf("0x%" PRIx64 ": EntityResultVariable\n", load_addr);
11100b57cec5SDimitry Andric 
11110b57cec5SDimitry Andric     Status err;
11120b57cec5SDimitry Andric 
11130b57cec5SDimitry Andric     lldb::addr_t ptr = LLDB_INVALID_ADDRESS;
11140b57cec5SDimitry Andric 
11150b57cec5SDimitry Andric     {
11160b57cec5SDimitry Andric       dump_stream.Printf("Pointer:\n");
11170b57cec5SDimitry Andric 
11180b57cec5SDimitry Andric       DataBufferHeap data(m_size, 0);
11190b57cec5SDimitry Andric 
11200b57cec5SDimitry Andric       map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
11210b57cec5SDimitry Andric 
11220b57cec5SDimitry Andric       if (!err.Success()) {
11230b57cec5SDimitry Andric         dump_stream.Printf("  <could not be read>\n");
11240b57cec5SDimitry Andric       } else {
11250b57cec5SDimitry Andric         DataExtractor extractor(data.GetBytes(), data.GetByteSize(),
11260b57cec5SDimitry Andric                                 map.GetByteOrder(), map.GetAddressByteSize());
11270b57cec5SDimitry Andric 
11280b57cec5SDimitry Andric         DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
11290b57cec5SDimitry Andric                      load_addr);
11300b57cec5SDimitry Andric 
113104eeddc0SDimitry Andric         lldb::offset_t offset = 0;
11320b57cec5SDimitry Andric 
11335ffd83dbSDimitry Andric         ptr = extractor.GetAddress(&offset);
11340b57cec5SDimitry Andric 
11350b57cec5SDimitry Andric         dump_stream.PutChar('\n');
11360b57cec5SDimitry Andric       }
11370b57cec5SDimitry Andric     }
11380b57cec5SDimitry Andric 
11390b57cec5SDimitry Andric     if (m_temporary_allocation == LLDB_INVALID_ADDRESS) {
11400b57cec5SDimitry Andric       dump_stream.Printf("Points to process memory:\n");
11410b57cec5SDimitry Andric     } else {
11420b57cec5SDimitry Andric       dump_stream.Printf("Temporary allocation:\n");
11430b57cec5SDimitry Andric     }
11440b57cec5SDimitry Andric 
11450b57cec5SDimitry Andric     if (ptr == LLDB_INVALID_ADDRESS) {
11460b57cec5SDimitry Andric       dump_stream.Printf("  <could not be be found>\n");
11470b57cec5SDimitry Andric     } else {
11480b57cec5SDimitry Andric       DataBufferHeap data(m_temporary_allocation_size, 0);
11490b57cec5SDimitry Andric 
11500b57cec5SDimitry Andric       map.ReadMemory(data.GetBytes(), m_temporary_allocation,
11510b57cec5SDimitry Andric                      m_temporary_allocation_size, err);
11520b57cec5SDimitry Andric 
11530b57cec5SDimitry Andric       if (!err.Success()) {
11540b57cec5SDimitry Andric         dump_stream.Printf("  <could not be read>\n");
11550b57cec5SDimitry Andric       } else {
11560b57cec5SDimitry Andric         DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
11570b57cec5SDimitry Andric                      load_addr);
11580b57cec5SDimitry Andric 
11590b57cec5SDimitry Andric         dump_stream.PutChar('\n');
11600b57cec5SDimitry Andric       }
11610b57cec5SDimitry Andric     }
11620b57cec5SDimitry Andric 
11630b57cec5SDimitry Andric     log->PutString(dump_stream.GetString());
11640b57cec5SDimitry Andric   }
11650b57cec5SDimitry Andric 
Wipe(IRMemoryMap & map,lldb::addr_t process_address)11660b57cec5SDimitry Andric   void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {
11670b57cec5SDimitry Andric     if (!m_keep_in_memory && m_temporary_allocation != LLDB_INVALID_ADDRESS) {
11680b57cec5SDimitry Andric       Status free_error;
11690b57cec5SDimitry Andric 
11700b57cec5SDimitry Andric       map.Free(m_temporary_allocation, free_error);
11710b57cec5SDimitry Andric     }
11720b57cec5SDimitry Andric 
11730b57cec5SDimitry Andric     m_temporary_allocation = LLDB_INVALID_ADDRESS;
11740b57cec5SDimitry Andric     m_temporary_allocation_size = 0;
11750b57cec5SDimitry Andric   }
11760b57cec5SDimitry Andric 
11770b57cec5SDimitry Andric private:
11780b57cec5SDimitry Andric   CompilerType m_type;
11790b57cec5SDimitry Andric   bool m_is_program_reference;
11800b57cec5SDimitry Andric   bool m_keep_in_memory;
11810b57cec5SDimitry Andric 
118281ad6265SDimitry Andric   lldb::addr_t m_temporary_allocation = LLDB_INVALID_ADDRESS;
118381ad6265SDimitry Andric   size_t m_temporary_allocation_size = 0;
11840b57cec5SDimitry Andric   Materializer::PersistentVariableDelegate *m_delegate;
11850b57cec5SDimitry Andric };
11860b57cec5SDimitry Andric 
AddResultVariable(const CompilerType & type,bool is_program_reference,bool keep_in_memory,PersistentVariableDelegate * delegate,Status & err)11870b57cec5SDimitry Andric uint32_t Materializer::AddResultVariable(const CompilerType &type,
11880b57cec5SDimitry Andric                                          bool is_program_reference,
11890b57cec5SDimitry Andric                                          bool keep_in_memory,
11900b57cec5SDimitry Andric                                          PersistentVariableDelegate *delegate,
11910b57cec5SDimitry Andric                                          Status &err) {
11920b57cec5SDimitry Andric   EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
11935ffd83dbSDimitry Andric   *iter = std::make_unique<EntityResultVariable>(type, is_program_reference,
11945ffd83dbSDimitry Andric                                                  keep_in_memory, delegate);
11950b57cec5SDimitry Andric   uint32_t ret = AddStructMember(**iter);
11960b57cec5SDimitry Andric   (*iter)->SetOffset(ret);
11970b57cec5SDimitry Andric   return ret;
11980b57cec5SDimitry Andric }
11990b57cec5SDimitry Andric 
12000b57cec5SDimitry Andric class EntitySymbol : public Materializer::Entity {
12010b57cec5SDimitry Andric public:
EntitySymbol(const Symbol & symbol)12020b57cec5SDimitry Andric   EntitySymbol(const Symbol &symbol) : Entity(), m_symbol(symbol) {
12030b57cec5SDimitry Andric     // Hard-coding to maximum size of a symbol
1204fcaf7f86SDimitry Andric     m_size = g_default_var_byte_size;
1205fcaf7f86SDimitry Andric     m_alignment = g_default_var_alignment;
12060b57cec5SDimitry Andric   }
12070b57cec5SDimitry Andric 
Materialize(lldb::StackFrameSP & frame_sp,IRMemoryMap & map,lldb::addr_t process_address,Status & err)12080b57cec5SDimitry Andric   void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
12090b57cec5SDimitry Andric                    lldb::addr_t process_address, Status &err) override {
121081ad6265SDimitry Andric     Log *log = GetLog(LLDBLog::Expressions);
12110b57cec5SDimitry Andric 
12120b57cec5SDimitry Andric     const lldb::addr_t load_addr = process_address + m_offset;
12130b57cec5SDimitry Andric 
12140b57cec5SDimitry Andric     if (log) {
12159dba64beSDimitry Andric       LLDB_LOGF(log,
12169dba64beSDimitry Andric                 "EntitySymbol::Materialize [address = 0x%" PRIx64
12170b57cec5SDimitry Andric                 ", m_symbol = %s]",
12180b57cec5SDimitry Andric                 (uint64_t)load_addr, m_symbol.GetName().AsCString());
12190b57cec5SDimitry Andric     }
12200b57cec5SDimitry Andric 
12210b57cec5SDimitry Andric     const Address sym_address = m_symbol.GetAddress();
12220b57cec5SDimitry Andric 
12235ffd83dbSDimitry Andric     ExecutionContextScope *exe_scope = frame_sp.get();
12245ffd83dbSDimitry Andric     if (!exe_scope)
12255ffd83dbSDimitry Andric       exe_scope = map.GetBestExecutionContextScope();
12260b57cec5SDimitry Andric 
12270b57cec5SDimitry Andric     lldb::TargetSP target_sp;
12280b57cec5SDimitry Andric 
12290b57cec5SDimitry Andric     if (exe_scope)
12300b57cec5SDimitry Andric       target_sp = map.GetBestExecutionContextScope()->CalculateTarget();
12310b57cec5SDimitry Andric 
12320b57cec5SDimitry Andric     if (!target_sp) {
12330b57cec5SDimitry Andric       err.SetErrorStringWithFormat(
12340b57cec5SDimitry Andric           "couldn't resolve symbol %s because there is no target",
12350b57cec5SDimitry Andric           m_symbol.GetName().AsCString());
12360b57cec5SDimitry Andric       return;
12370b57cec5SDimitry Andric     }
12380b57cec5SDimitry Andric 
12390b57cec5SDimitry Andric     lldb::addr_t resolved_address = sym_address.GetLoadAddress(target_sp.get());
12400b57cec5SDimitry Andric 
12410b57cec5SDimitry Andric     if (resolved_address == LLDB_INVALID_ADDRESS)
12420b57cec5SDimitry Andric       resolved_address = sym_address.GetFileAddress();
12430b57cec5SDimitry Andric 
12440b57cec5SDimitry Andric     Status pointer_write_error;
12450b57cec5SDimitry Andric 
12460b57cec5SDimitry Andric     map.WritePointerToMemory(load_addr, resolved_address, pointer_write_error);
12470b57cec5SDimitry Andric 
12480b57cec5SDimitry Andric     if (!pointer_write_error.Success()) {
12490b57cec5SDimitry Andric       err.SetErrorStringWithFormat(
12500b57cec5SDimitry Andric           "couldn't write the address of symbol %s: %s",
12510b57cec5SDimitry Andric           m_symbol.GetName().AsCString(), pointer_write_error.AsCString());
12520b57cec5SDimitry Andric       return;
12530b57cec5SDimitry Andric     }
12540b57cec5SDimitry Andric   }
12550b57cec5SDimitry Andric 
Dematerialize(lldb::StackFrameSP & frame_sp,IRMemoryMap & map,lldb::addr_t process_address,lldb::addr_t frame_top,lldb::addr_t frame_bottom,Status & err)12560b57cec5SDimitry Andric   void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
12570b57cec5SDimitry Andric                      lldb::addr_t process_address, lldb::addr_t frame_top,
12580b57cec5SDimitry Andric                      lldb::addr_t frame_bottom, Status &err) override {
125981ad6265SDimitry Andric     Log *log = GetLog(LLDBLog::Expressions);
12600b57cec5SDimitry Andric 
12610b57cec5SDimitry Andric     const lldb::addr_t load_addr = process_address + m_offset;
12620b57cec5SDimitry Andric 
12630b57cec5SDimitry Andric     if (log) {
12649dba64beSDimitry Andric       LLDB_LOGF(log,
12659dba64beSDimitry Andric                 "EntitySymbol::Dematerialize [address = 0x%" PRIx64
12660b57cec5SDimitry Andric                 ", m_symbol = %s]",
12670b57cec5SDimitry Andric                 (uint64_t)load_addr, m_symbol.GetName().AsCString());
12680b57cec5SDimitry Andric     }
12690b57cec5SDimitry Andric 
12700b57cec5SDimitry Andric     // no work needs to be done
12710b57cec5SDimitry Andric   }
12720b57cec5SDimitry Andric 
DumpToLog(IRMemoryMap & map,lldb::addr_t process_address,Log * log)12730b57cec5SDimitry Andric   void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
12740b57cec5SDimitry Andric                  Log *log) override {
12750b57cec5SDimitry Andric     StreamString dump_stream;
12760b57cec5SDimitry Andric 
12770b57cec5SDimitry Andric     Status err;
12780b57cec5SDimitry Andric 
12790b57cec5SDimitry Andric     const lldb::addr_t load_addr = process_address + m_offset;
12800b57cec5SDimitry Andric 
12810b57cec5SDimitry Andric     dump_stream.Printf("0x%" PRIx64 ": EntitySymbol (%s)\n", load_addr,
12820b57cec5SDimitry Andric                        m_symbol.GetName().AsCString());
12830b57cec5SDimitry Andric 
12840b57cec5SDimitry Andric     {
12850b57cec5SDimitry Andric       dump_stream.Printf("Pointer:\n");
12860b57cec5SDimitry Andric 
12870b57cec5SDimitry Andric       DataBufferHeap data(m_size, 0);
12880b57cec5SDimitry Andric 
12890b57cec5SDimitry Andric       map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
12900b57cec5SDimitry Andric 
12910b57cec5SDimitry Andric       if (!err.Success()) {
12920b57cec5SDimitry Andric         dump_stream.Printf("  <could not be read>\n");
12930b57cec5SDimitry Andric       } else {
12940b57cec5SDimitry Andric         DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
12950b57cec5SDimitry Andric                      load_addr);
12960b57cec5SDimitry Andric 
12970b57cec5SDimitry Andric         dump_stream.PutChar('\n');
12980b57cec5SDimitry Andric       }
12990b57cec5SDimitry Andric     }
13000b57cec5SDimitry Andric 
13010b57cec5SDimitry Andric     log->PutString(dump_stream.GetString());
13020b57cec5SDimitry Andric   }
13030b57cec5SDimitry Andric 
Wipe(IRMemoryMap & map,lldb::addr_t process_address)13040b57cec5SDimitry Andric   void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {}
13050b57cec5SDimitry Andric 
13060b57cec5SDimitry Andric private:
13070b57cec5SDimitry Andric   Symbol m_symbol;
13080b57cec5SDimitry Andric };
13090b57cec5SDimitry Andric 
AddSymbol(const Symbol & symbol_sp,Status & err)13100b57cec5SDimitry Andric uint32_t Materializer::AddSymbol(const Symbol &symbol_sp, Status &err) {
13110b57cec5SDimitry Andric   EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
13125ffd83dbSDimitry Andric   *iter = std::make_unique<EntitySymbol>(symbol_sp);
13130b57cec5SDimitry Andric   uint32_t ret = AddStructMember(**iter);
13140b57cec5SDimitry Andric   (*iter)->SetOffset(ret);
13150b57cec5SDimitry Andric   return ret;
13160b57cec5SDimitry Andric }
13170b57cec5SDimitry Andric 
13180b57cec5SDimitry Andric class EntityRegister : public Materializer::Entity {
13190b57cec5SDimitry Andric public:
EntityRegister(const RegisterInfo & register_info)13200b57cec5SDimitry Andric   EntityRegister(const RegisterInfo &register_info)
13210b57cec5SDimitry Andric       : Entity(), m_register_info(register_info) {
13220b57cec5SDimitry Andric     // Hard-coding alignment conservatively
13230b57cec5SDimitry Andric     m_size = m_register_info.byte_size;
13240b57cec5SDimitry Andric     m_alignment = m_register_info.byte_size;
13250b57cec5SDimitry Andric   }
13260b57cec5SDimitry Andric 
Materialize(lldb::StackFrameSP & frame_sp,IRMemoryMap & map,lldb::addr_t process_address,Status & err)13270b57cec5SDimitry Andric   void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
13280b57cec5SDimitry Andric                    lldb::addr_t process_address, Status &err) override {
132981ad6265SDimitry Andric     Log *log = GetLog(LLDBLog::Expressions);
13300b57cec5SDimitry Andric 
13310b57cec5SDimitry Andric     const lldb::addr_t load_addr = process_address + m_offset;
13320b57cec5SDimitry Andric 
13330b57cec5SDimitry Andric     if (log) {
13349dba64beSDimitry Andric       LLDB_LOGF(log,
13359dba64beSDimitry Andric                 "EntityRegister::Materialize [address = 0x%" PRIx64
13360b57cec5SDimitry Andric                 ", m_register_info = %s]",
13370b57cec5SDimitry Andric                 (uint64_t)load_addr, m_register_info.name);
13380b57cec5SDimitry Andric     }
13390b57cec5SDimitry Andric 
13400b57cec5SDimitry Andric     RegisterValue reg_value;
13410b57cec5SDimitry Andric 
13420b57cec5SDimitry Andric     if (!frame_sp.get()) {
13430b57cec5SDimitry Andric       err.SetErrorStringWithFormat(
13440b57cec5SDimitry Andric           "couldn't materialize register %s without a stack frame",
13450b57cec5SDimitry Andric           m_register_info.name);
13460b57cec5SDimitry Andric       return;
13470b57cec5SDimitry Andric     }
13480b57cec5SDimitry Andric 
13490b57cec5SDimitry Andric     lldb::RegisterContextSP reg_context_sp = frame_sp->GetRegisterContext();
13500b57cec5SDimitry Andric 
13510b57cec5SDimitry Andric     if (!reg_context_sp->ReadRegister(&m_register_info, reg_value)) {
13520b57cec5SDimitry Andric       err.SetErrorStringWithFormat("couldn't read the value of register %s",
13530b57cec5SDimitry Andric                                    m_register_info.name);
13540b57cec5SDimitry Andric       return;
13550b57cec5SDimitry Andric     }
13560b57cec5SDimitry Andric 
13570b57cec5SDimitry Andric     DataExtractor register_data;
13580b57cec5SDimitry Andric 
13590b57cec5SDimitry Andric     if (!reg_value.GetData(register_data)) {
13600b57cec5SDimitry Andric       err.SetErrorStringWithFormat("couldn't get the data for register %s",
13610b57cec5SDimitry Andric                                    m_register_info.name);
13620b57cec5SDimitry Andric       return;
13630b57cec5SDimitry Andric     }
13640b57cec5SDimitry Andric 
13650b57cec5SDimitry Andric     if (register_data.GetByteSize() != m_register_info.byte_size) {
13660b57cec5SDimitry Andric       err.SetErrorStringWithFormat(
13670b57cec5SDimitry Andric           "data for register %s had size %llu but we expected %llu",
13680b57cec5SDimitry Andric           m_register_info.name, (unsigned long long)register_data.GetByteSize(),
13690b57cec5SDimitry Andric           (unsigned long long)m_register_info.byte_size);
13700b57cec5SDimitry Andric       return;
13710b57cec5SDimitry Andric     }
13720b57cec5SDimitry Andric 
13730b57cec5SDimitry Andric     m_register_contents = std::make_shared<DataBufferHeap>(
13740b57cec5SDimitry Andric         register_data.GetDataStart(), register_data.GetByteSize());
13750b57cec5SDimitry Andric 
13760b57cec5SDimitry Andric     Status write_error;
13770b57cec5SDimitry Andric 
13780b57cec5SDimitry Andric     map.WriteMemory(load_addr, register_data.GetDataStart(),
13790b57cec5SDimitry Andric                     register_data.GetByteSize(), write_error);
13800b57cec5SDimitry Andric 
13810b57cec5SDimitry Andric     if (!write_error.Success()) {
13820b57cec5SDimitry Andric       err.SetErrorStringWithFormat(
13830b57cec5SDimitry Andric           "couldn't write the contents of register %s: %s",
13840b57cec5SDimitry Andric           m_register_info.name, write_error.AsCString());
13850b57cec5SDimitry Andric       return;
13860b57cec5SDimitry Andric     }
13870b57cec5SDimitry Andric   }
13880b57cec5SDimitry Andric 
Dematerialize(lldb::StackFrameSP & frame_sp,IRMemoryMap & map,lldb::addr_t process_address,lldb::addr_t frame_top,lldb::addr_t frame_bottom,Status & err)13890b57cec5SDimitry Andric   void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
13900b57cec5SDimitry Andric                      lldb::addr_t process_address, lldb::addr_t frame_top,
13910b57cec5SDimitry Andric                      lldb::addr_t frame_bottom, Status &err) override {
139281ad6265SDimitry Andric     Log *log = GetLog(LLDBLog::Expressions);
13930b57cec5SDimitry Andric 
13940b57cec5SDimitry Andric     const lldb::addr_t load_addr = process_address + m_offset;
13950b57cec5SDimitry Andric 
13960b57cec5SDimitry Andric     if (log) {
13979dba64beSDimitry Andric       LLDB_LOGF(log,
13989dba64beSDimitry Andric                 "EntityRegister::Dematerialize [address = 0x%" PRIx64
13990b57cec5SDimitry Andric                 ", m_register_info = %s]",
14000b57cec5SDimitry Andric                 (uint64_t)load_addr, m_register_info.name);
14010b57cec5SDimitry Andric     }
14020b57cec5SDimitry Andric 
14030b57cec5SDimitry Andric     Status extract_error;
14040b57cec5SDimitry Andric 
14050b57cec5SDimitry Andric     DataExtractor register_data;
14060b57cec5SDimitry Andric 
14070b57cec5SDimitry Andric     if (!frame_sp.get()) {
14080b57cec5SDimitry Andric       err.SetErrorStringWithFormat(
14090b57cec5SDimitry Andric           "couldn't dematerialize register %s without a stack frame",
14100b57cec5SDimitry Andric           m_register_info.name);
14110b57cec5SDimitry Andric       return;
14120b57cec5SDimitry Andric     }
14130b57cec5SDimitry Andric 
14140b57cec5SDimitry Andric     lldb::RegisterContextSP reg_context_sp = frame_sp->GetRegisterContext();
14150b57cec5SDimitry Andric 
14160b57cec5SDimitry Andric     map.GetMemoryData(register_data, load_addr, m_register_info.byte_size,
14170b57cec5SDimitry Andric                       extract_error);
14180b57cec5SDimitry Andric 
14190b57cec5SDimitry Andric     if (!extract_error.Success()) {
14200b57cec5SDimitry Andric       err.SetErrorStringWithFormat("couldn't get the data for register %s: %s",
14210b57cec5SDimitry Andric                                    m_register_info.name,
14220b57cec5SDimitry Andric                                    extract_error.AsCString());
14230b57cec5SDimitry Andric       return;
14240b57cec5SDimitry Andric     }
14250b57cec5SDimitry Andric 
14260b57cec5SDimitry Andric     if (!memcmp(register_data.GetDataStart(), m_register_contents->GetBytes(),
14270b57cec5SDimitry Andric                 register_data.GetByteSize())) {
14280b57cec5SDimitry Andric       // No write required, and in particular we avoid errors if the register
14290b57cec5SDimitry Andric       // wasn't writable
14300b57cec5SDimitry Andric 
14310b57cec5SDimitry Andric       m_register_contents.reset();
14320b57cec5SDimitry Andric       return;
14330b57cec5SDimitry Andric     }
14340b57cec5SDimitry Andric 
14350b57cec5SDimitry Andric     m_register_contents.reset();
14360b57cec5SDimitry Andric 
1437e8d8bef9SDimitry Andric     RegisterValue register_value(register_data.GetData(),
1438e8d8bef9SDimitry Andric                                  register_data.GetByteOrder());
14390b57cec5SDimitry Andric 
14400b57cec5SDimitry Andric     if (!reg_context_sp->WriteRegister(&m_register_info, register_value)) {
14410b57cec5SDimitry Andric       err.SetErrorStringWithFormat("couldn't write the value of register %s",
14420b57cec5SDimitry Andric                                    m_register_info.name);
14430b57cec5SDimitry Andric       return;
14440b57cec5SDimitry Andric     }
14450b57cec5SDimitry Andric   }
14460b57cec5SDimitry Andric 
DumpToLog(IRMemoryMap & map,lldb::addr_t process_address,Log * log)14470b57cec5SDimitry Andric   void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
14480b57cec5SDimitry Andric                  Log *log) override {
14490b57cec5SDimitry Andric     StreamString dump_stream;
14500b57cec5SDimitry Andric 
14510b57cec5SDimitry Andric     Status err;
14520b57cec5SDimitry Andric 
14530b57cec5SDimitry Andric     const lldb::addr_t load_addr = process_address + m_offset;
14540b57cec5SDimitry Andric 
14550b57cec5SDimitry Andric     dump_stream.Printf("0x%" PRIx64 ": EntityRegister (%s)\n", load_addr,
14560b57cec5SDimitry Andric                        m_register_info.name);
14570b57cec5SDimitry Andric 
14580b57cec5SDimitry Andric     {
14590b57cec5SDimitry Andric       dump_stream.Printf("Value:\n");
14600b57cec5SDimitry Andric 
14610b57cec5SDimitry Andric       DataBufferHeap data(m_size, 0);
14620b57cec5SDimitry Andric 
14630b57cec5SDimitry Andric       map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
14640b57cec5SDimitry Andric 
14650b57cec5SDimitry Andric       if (!err.Success()) {
14660b57cec5SDimitry Andric         dump_stream.Printf("  <could not be read>\n");
14670b57cec5SDimitry Andric       } else {
14680b57cec5SDimitry Andric         DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
14690b57cec5SDimitry Andric                      load_addr);
14700b57cec5SDimitry Andric 
14710b57cec5SDimitry Andric         dump_stream.PutChar('\n');
14720b57cec5SDimitry Andric       }
14730b57cec5SDimitry Andric     }
14740b57cec5SDimitry Andric 
14750b57cec5SDimitry Andric     log->PutString(dump_stream.GetString());
14760b57cec5SDimitry Andric   }
14770b57cec5SDimitry Andric 
Wipe(IRMemoryMap & map,lldb::addr_t process_address)14780b57cec5SDimitry Andric   void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {}
14790b57cec5SDimitry Andric 
14800b57cec5SDimitry Andric private:
14810b57cec5SDimitry Andric   RegisterInfo m_register_info;
14820b57cec5SDimitry Andric   lldb::DataBufferSP m_register_contents;
14830b57cec5SDimitry Andric };
14840b57cec5SDimitry Andric 
AddRegister(const RegisterInfo & register_info,Status & err)14850b57cec5SDimitry Andric uint32_t Materializer::AddRegister(const RegisterInfo &register_info,
14860b57cec5SDimitry Andric                                    Status &err) {
14870b57cec5SDimitry Andric   EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
14885ffd83dbSDimitry Andric   *iter = std::make_unique<EntityRegister>(register_info);
14890b57cec5SDimitry Andric   uint32_t ret = AddStructMember(**iter);
14900b57cec5SDimitry Andric   (*iter)->SetOffset(ret);
14910b57cec5SDimitry Andric   return ret;
14920b57cec5SDimitry Andric }
14930b57cec5SDimitry Andric 
~Materializer()14940b57cec5SDimitry Andric Materializer::~Materializer() {
14950b57cec5SDimitry Andric   DematerializerSP dematerializer_sp = m_dematerializer_wp.lock();
14960b57cec5SDimitry Andric 
14970b57cec5SDimitry Andric   if (dematerializer_sp)
14980b57cec5SDimitry Andric     dematerializer_sp->Wipe();
14990b57cec5SDimitry Andric }
15000b57cec5SDimitry Andric 
15010b57cec5SDimitry Andric Materializer::DematerializerSP
Materialize(lldb::StackFrameSP & frame_sp,IRMemoryMap & map,lldb::addr_t process_address,Status & error)15020b57cec5SDimitry Andric Materializer::Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
15030b57cec5SDimitry Andric                           lldb::addr_t process_address, Status &error) {
15040b57cec5SDimitry Andric   ExecutionContextScope *exe_scope = frame_sp.get();
15050b57cec5SDimitry Andric   if (!exe_scope)
15060b57cec5SDimitry Andric     exe_scope = map.GetBestExecutionContextScope();
15070b57cec5SDimitry Andric 
15080b57cec5SDimitry Andric   DematerializerSP dematerializer_sp = m_dematerializer_wp.lock();
15090b57cec5SDimitry Andric 
15100b57cec5SDimitry Andric   if (dematerializer_sp) {
15110b57cec5SDimitry Andric     error.SetErrorToGenericError();
15120b57cec5SDimitry Andric     error.SetErrorString("Couldn't materialize: already materialized");
15130b57cec5SDimitry Andric   }
15140b57cec5SDimitry Andric 
15150b57cec5SDimitry Andric   DematerializerSP ret(
15160b57cec5SDimitry Andric       new Dematerializer(*this, frame_sp, map, process_address));
15170b57cec5SDimitry Andric 
15180b57cec5SDimitry Andric   if (!exe_scope) {
15190b57cec5SDimitry Andric     error.SetErrorToGenericError();
15200b57cec5SDimitry Andric     error.SetErrorString("Couldn't materialize: target doesn't exist");
15210b57cec5SDimitry Andric   }
15220b57cec5SDimitry Andric 
15230b57cec5SDimitry Andric   for (EntityUP &entity_up : m_entities) {
15240b57cec5SDimitry Andric     entity_up->Materialize(frame_sp, map, process_address, error);
15250b57cec5SDimitry Andric 
15260b57cec5SDimitry Andric     if (!error.Success())
15270b57cec5SDimitry Andric       return DematerializerSP();
15280b57cec5SDimitry Andric   }
15290b57cec5SDimitry Andric 
153081ad6265SDimitry Andric   if (Log *log = GetLog(LLDBLog::Expressions)) {
15319dba64beSDimitry Andric     LLDB_LOGF(
15329dba64beSDimitry Andric         log,
15330b57cec5SDimitry Andric         "Materializer::Materialize (frame_sp = %p, process_address = 0x%" PRIx64
15340b57cec5SDimitry Andric         ") materialized:",
15350b57cec5SDimitry Andric         static_cast<void *>(frame_sp.get()), process_address);
15360b57cec5SDimitry Andric     for (EntityUP &entity_up : m_entities)
15370b57cec5SDimitry Andric       entity_up->DumpToLog(map, process_address, log);
15380b57cec5SDimitry Andric   }
15390b57cec5SDimitry Andric 
15400b57cec5SDimitry Andric   m_dematerializer_wp = ret;
15410b57cec5SDimitry Andric 
15420b57cec5SDimitry Andric   return ret;
15430b57cec5SDimitry Andric }
15440b57cec5SDimitry Andric 
Dematerialize(Status & error,lldb::addr_t frame_bottom,lldb::addr_t frame_top)15450b57cec5SDimitry Andric void Materializer::Dematerializer::Dematerialize(Status &error,
15460b57cec5SDimitry Andric                                                  lldb::addr_t frame_bottom,
15470b57cec5SDimitry Andric                                                  lldb::addr_t frame_top) {
15480b57cec5SDimitry Andric   lldb::StackFrameSP frame_sp;
15490b57cec5SDimitry Andric 
15500b57cec5SDimitry Andric   lldb::ThreadSP thread_sp = m_thread_wp.lock();
15510b57cec5SDimitry Andric   if (thread_sp)
15520b57cec5SDimitry Andric     frame_sp = thread_sp->GetFrameWithStackID(m_stack_id);
15530b57cec5SDimitry Andric 
15545ffd83dbSDimitry Andric   ExecutionContextScope *exe_scope = frame_sp.get();
15555ffd83dbSDimitry Andric   if (!exe_scope)
15565ffd83dbSDimitry Andric     exe_scope = m_map->GetBestExecutionContextScope();
15570b57cec5SDimitry Andric 
15580b57cec5SDimitry Andric   if (!IsValid()) {
15590b57cec5SDimitry Andric     error.SetErrorToGenericError();
15600b57cec5SDimitry Andric     error.SetErrorString("Couldn't dematerialize: invalid dematerializer");
15610b57cec5SDimitry Andric   }
15620b57cec5SDimitry Andric 
15630b57cec5SDimitry Andric   if (!exe_scope) {
15640b57cec5SDimitry Andric     error.SetErrorToGenericError();
15650b57cec5SDimitry Andric     error.SetErrorString("Couldn't dematerialize: target is gone");
15660b57cec5SDimitry Andric   } else {
156781ad6265SDimitry Andric     if (Log *log = GetLog(LLDBLog::Expressions)) {
15689dba64beSDimitry Andric       LLDB_LOGF(log,
15699dba64beSDimitry Andric                 "Materializer::Dematerialize (frame_sp = %p, process_address "
15700b57cec5SDimitry Andric                 "= 0x%" PRIx64 ") about to dematerialize:",
15710b57cec5SDimitry Andric                 static_cast<void *>(frame_sp.get()), m_process_address);
15720b57cec5SDimitry Andric       for (EntityUP &entity_up : m_materializer->m_entities)
15730b57cec5SDimitry Andric         entity_up->DumpToLog(*m_map, m_process_address, log);
15740b57cec5SDimitry Andric     }
15750b57cec5SDimitry Andric 
15760b57cec5SDimitry Andric     for (EntityUP &entity_up : m_materializer->m_entities) {
15770b57cec5SDimitry Andric       entity_up->Dematerialize(frame_sp, *m_map, m_process_address, frame_top,
15780b57cec5SDimitry Andric                                frame_bottom, error);
15790b57cec5SDimitry Andric 
15800b57cec5SDimitry Andric       if (!error.Success())
15810b57cec5SDimitry Andric         break;
15820b57cec5SDimitry Andric     }
15830b57cec5SDimitry Andric   }
15840b57cec5SDimitry Andric 
15850b57cec5SDimitry Andric   Wipe();
15860b57cec5SDimitry Andric }
15870b57cec5SDimitry Andric 
Wipe()15880b57cec5SDimitry Andric void Materializer::Dematerializer::Wipe() {
15890b57cec5SDimitry Andric   if (!IsValid())
15900b57cec5SDimitry Andric     return;
15910b57cec5SDimitry Andric 
15920b57cec5SDimitry Andric   for (EntityUP &entity_up : m_materializer->m_entities) {
15930b57cec5SDimitry Andric     entity_up->Wipe(*m_map, m_process_address);
15940b57cec5SDimitry Andric   }
15950b57cec5SDimitry Andric 
15960b57cec5SDimitry Andric   m_materializer = nullptr;
15970b57cec5SDimitry Andric   m_map = nullptr;
15980b57cec5SDimitry Andric   m_process_address = LLDB_INVALID_ADDRESS;
15990b57cec5SDimitry Andric }
16000b57cec5SDimitry Andric 
1601*06c3fb27SDimitry Andric Materializer::PersistentVariableDelegate::PersistentVariableDelegate() =
1602*06c3fb27SDimitry Andric     default;
16030b57cec5SDimitry Andric Materializer::PersistentVariableDelegate::~PersistentVariableDelegate() =
16040b57cec5SDimitry Andric     default;
1605