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 ®ister_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 ®ister_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