brintos

brintos / llvm-project-archived public Read only

0
0
Text · 52.6 KiB · 771a9ab Raw
1624 lines · cpp
1//===-- Materializer.cpp --------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "lldb/Expression/Materializer.h"10#include "lldb/Core/DumpDataExtractor.h"11#include "lldb/Expression/ExpressionVariable.h"12#include "lldb/Symbol/Symbol.h"13#include "lldb/Symbol/Type.h"14#include "lldb/Symbol/Variable.h"15#include "lldb/Target/ExecutionContext.h"16#include "lldb/Target/RegisterContext.h"17#include "lldb/Target/StackFrame.h"18#include "lldb/Target/Target.h"19#include "lldb/Target/Thread.h"20#include "lldb/Utility/LLDBLog.h"21#include "lldb/Utility/Log.h"22#include "lldb/Utility/RegisterValue.h"23#include "lldb/ValueObject/ValueObjectConstResult.h"24#include "lldb/ValueObject/ValueObjectVariable.h"25#include "lldb/lldb-forward.h"26 27#include <memory>28#include <optional>29 30using namespace lldb_private;31 32// FIXME: these should be retrieved from the target33//        instead of being hard-coded. Currently we34//        assume that persistent vars are materialized35//        as references, and thus pick the size of a36//        64-bit pointer.37static constexpr uint32_t g_default_var_alignment = 8;38static constexpr uint32_t g_default_var_byte_size = 8;39 40uint32_t Materializer::AddStructMember(Entity &entity) {41  uint32_t size = entity.GetSize();42  uint32_t alignment = entity.GetAlignment();43 44  uint32_t ret;45 46  if (m_current_offset == 0)47    m_struct_alignment = alignment;48 49  if (m_current_offset % alignment)50    m_current_offset += (alignment - (m_current_offset % alignment));51 52  ret = m_current_offset;53 54  m_current_offset += size;55 56  return ret;57}58 59class EntityPersistentVariable : public Materializer::Entity {60public:61  EntityPersistentVariable(lldb::ExpressionVariableSP &persistent_variable_sp,62                           Materializer::PersistentVariableDelegate *delegate)63      : Entity(), m_persistent_variable_sp(persistent_variable_sp),64        m_delegate(delegate) {65    // Hard-coding to maximum size of a pointer since persistent variables are66    // materialized by reference67    m_size = g_default_var_byte_size;68    m_alignment = g_default_var_alignment;69  }70 71  void MakeAllocation(IRMemoryMap &map, Status &err) {72    Log *log = GetLog(LLDBLog::Expressions);73 74    // Allocate a spare memory area to store the persistent variable's75    // contents.76 77    const bool zero_memory = false;78    IRMemoryMap::AllocationPolicy used_policy;79    auto address_or_error = map.Malloc(80        llvm::expectedToOptional(m_persistent_variable_sp->GetByteSize())81            .value_or(0),82        8, lldb::ePermissionsReadable | lldb::ePermissionsWritable,83        IRMemoryMap::eAllocationPolicyMirror, zero_memory, &used_policy);84    if (!address_or_error) {85      err = Status::FromErrorStringWithFormat(86          "couldn't allocate a memory area to store %s: %s",87          m_persistent_variable_sp->GetName().GetCString(),88          toString(address_or_error.takeError()).c_str());89      return;90    }91    lldb::addr_t mem = *address_or_error;92 93    LLDB_LOGF(log, "Allocated %s (0x%" PRIx64 ") successfully",94              m_persistent_variable_sp->GetName().GetCString(), mem);95 96    // Put the location of the spare memory into the live data of the97    // ValueObject.98 99    m_persistent_variable_sp->m_live_sp = ValueObjectConstResult::Create(100        map.GetBestExecutionContextScope(),101        m_persistent_variable_sp->GetCompilerType(),102        m_persistent_variable_sp->GetName(), mem, eAddressTypeLoad,103        map.GetAddressByteSize());104 105    if (used_policy == IRMemoryMap::eAllocationPolicyMirror) {106      if (m_persistent_variable_sp->m_flags &107          ExpressionVariable::EVKeepInTarget) {108        // Clear the flag if the variable will never be deallocated.109        Status leak_error;110        map.Leak(mem, leak_error);111        m_persistent_variable_sp->m_flags &=112            ~ExpressionVariable::EVNeedsAllocation;113      }114    } else {115      // If we cannot allocate memory in the process,116      // - clear the 'EVKeepInTarget' flag to ensure that 'm_live_sp' is reset117      //   during dematerialization,118      m_persistent_variable_sp->m_flags &= ~ExpressionVariable::EVKeepInTarget;119      // - set the 'EVNeedsFreezeDry' flag so that the value is copied to120      //   'm_frozen_sp' during dematerialization.121      m_persistent_variable_sp->m_flags |= ExpressionVariable::EVNeedsFreezeDry;122    }123 124    // Write the contents of the variable to the area.125 126    Status write_error;127 128    map.WriteMemory(129        mem, m_persistent_variable_sp->GetValueBytes(),130        llvm::expectedToOptional(m_persistent_variable_sp->GetByteSize())131            .value_or(0),132        write_error);133 134    if (!write_error.Success()) {135      err = Status::FromErrorStringWithFormat(136          "couldn't write %s to the target: %s",137          m_persistent_variable_sp->GetName().AsCString(),138          write_error.AsCString());139      return;140    }141  }142 143  void DestroyAllocation(IRMemoryMap &map, Status &err) {144    Status deallocate_error;145 146    map.Free((lldb::addr_t)m_persistent_variable_sp->m_live_sp->GetValue()147                 .GetScalar()148                 .ULongLong(),149             deallocate_error);150 151    m_persistent_variable_sp->m_live_sp.reset();152 153    if (!deallocate_error.Success()) {154      err = Status::FromErrorStringWithFormat(155          "couldn't deallocate memory for %s: %s",156          m_persistent_variable_sp->GetName().GetCString(),157          deallocate_error.AsCString());158    }159  }160 161  void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,162                   lldb::addr_t process_address, Status &err) override {163    Log *log = GetLog(LLDBLog::Expressions);164 165    const lldb::addr_t load_addr = process_address + m_offset;166 167    if (log) {168      LLDB_LOGF(log,169                "EntityPersistentVariable::Materialize [address = 0x%" PRIx64170                ", m_name = %s, m_flags = 0x%hx]",171                (uint64_t)load_addr,172                m_persistent_variable_sp->GetName().AsCString(),173                m_persistent_variable_sp->m_flags);174    }175 176    if (m_persistent_variable_sp->m_flags &177        ExpressionVariable::EVNeedsAllocation) {178      MakeAllocation(map, err);179      m_persistent_variable_sp->m_flags |=180          ExpressionVariable::EVIsLLDBAllocated;181 182      if (!err.Success())183        return;184    }185 186    if ((m_persistent_variable_sp->m_flags &187             ExpressionVariable::EVIsProgramReference &&188         m_persistent_variable_sp->m_live_sp) ||189        m_persistent_variable_sp->m_flags &190            ExpressionVariable::EVIsLLDBAllocated) {191      Status write_error;192 193      map.WriteScalarToMemory(194          load_addr,195          m_persistent_variable_sp->m_live_sp->GetValue().GetScalar(),196          map.GetAddressByteSize(), write_error);197 198      if (!write_error.Success()) {199        err = Status::FromErrorStringWithFormat(200            "couldn't write the location of %s to memory: %s",201            m_persistent_variable_sp->GetName().AsCString(),202            write_error.AsCString());203      }204    } else {205      err = Status::FromErrorStringWithFormat(206          "no materialization happened for persistent variable %s",207          m_persistent_variable_sp->GetName().AsCString());208      return;209    }210  }211 212  void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,213                     lldb::addr_t process_address, lldb::addr_t frame_top,214                     lldb::addr_t frame_bottom, Status &err) override {215    Log *log = GetLog(LLDBLog::Expressions);216 217    const lldb::addr_t load_addr = process_address + m_offset;218 219    if (log) {220      LLDB_LOGF(log,221                "EntityPersistentVariable::Dematerialize [address = 0x%" PRIx64222                ", m_name = %s, m_flags = 0x%hx]",223                (uint64_t)process_address + m_offset,224                m_persistent_variable_sp->GetName().AsCString(),225                m_persistent_variable_sp->m_flags);226    }227 228    if (m_delegate) {229      m_delegate->DidDematerialize(m_persistent_variable_sp);230    }231 232    if ((m_persistent_variable_sp->m_flags &233         ExpressionVariable::EVIsLLDBAllocated) ||234        (m_persistent_variable_sp->m_flags &235         ExpressionVariable::EVIsProgramReference)) {236      if (m_persistent_variable_sp->m_flags &237              ExpressionVariable::EVIsProgramReference &&238          !m_persistent_variable_sp->m_live_sp) {239        // If the reference comes from the program, then the240        // ClangExpressionVariable's live variable data hasn't been set up yet.241        // Do this now.242 243        lldb::addr_t location;244        Status read_error;245 246        map.ReadPointerFromMemory(&location, load_addr, read_error);247 248        if (!read_error.Success()) {249          err = Status::FromErrorStringWithFormat(250              "couldn't read the address of program-allocated variable %s: %s",251              m_persistent_variable_sp->GetName().GetCString(),252              read_error.AsCString());253          return;254        }255 256        m_persistent_variable_sp->m_live_sp = ValueObjectConstResult::Create(257            map.GetBestExecutionContextScope(),258            m_persistent_variable_sp.get()->GetCompilerType(),259            m_persistent_variable_sp->GetName(), location, eAddressTypeLoad,260            llvm::expectedToOptional(m_persistent_variable_sp->GetByteSize())261                .value_or(0));262 263        if (frame_top != LLDB_INVALID_ADDRESS &&264            frame_bottom != LLDB_INVALID_ADDRESS && location >= frame_bottom &&265            location <= frame_top) {266          // If the variable is resident in the stack frame created by the267          // expression, then it cannot be relied upon to stay around.  We268          // treat it as needing reallocation.269          m_persistent_variable_sp->m_flags |=270              ExpressionVariable::EVIsLLDBAllocated;271          m_persistent_variable_sp->m_flags |=272              ExpressionVariable::EVNeedsAllocation;273          m_persistent_variable_sp->m_flags |=274              ExpressionVariable::EVNeedsFreezeDry;275          m_persistent_variable_sp->m_flags &=276              ~ExpressionVariable::EVIsProgramReference;277        }278      }279 280      lldb::addr_t mem = m_persistent_variable_sp->m_live_sp->GetValue()281                             .GetScalar()282                             .ULongLong();283 284      if (!m_persistent_variable_sp->m_live_sp) {285        err = Status::FromErrorStringWithFormat(286            "couldn't find the memory area used to store %s",287            m_persistent_variable_sp->GetName().GetCString());288        return;289      }290 291      if (m_persistent_variable_sp->m_live_sp->GetValue()292              .GetValueAddressType() != eAddressTypeLoad) {293        err = Status::FromErrorStringWithFormat(294            "the address of the memory area for %s is in an incorrect format",295            m_persistent_variable_sp->GetName().GetCString());296        return;297      }298 299      if (m_persistent_variable_sp->m_flags &300              ExpressionVariable::EVNeedsFreezeDry ||301          m_persistent_variable_sp->m_flags &302              ExpressionVariable::EVKeepInTarget) {303        LLDB_LOGF(log, "Dematerializing %s from 0x%" PRIx64 " (size = %llu)",304                  m_persistent_variable_sp->GetName().GetCString(),305                  (uint64_t)mem,306                  (unsigned long long)llvm::expectedToOptional(307                      m_persistent_variable_sp->GetByteSize())308                      .value_or(0));309 310        // Read the contents of the spare memory area311 312        m_persistent_variable_sp->ValueUpdated();313 314        Status read_error;315 316        map.ReadMemory(317            m_persistent_variable_sp->GetValueBytes(), mem,318            llvm::expectedToOptional(m_persistent_variable_sp->GetByteSize())319                .value_or(0),320            read_error);321 322        if (!read_error.Success()) {323          err = Status::FromErrorStringWithFormat(324              "couldn't read the contents of %s from memory: %s",325              m_persistent_variable_sp->GetName().GetCString(),326              read_error.AsCString());327          return;328        }329 330        m_persistent_variable_sp->m_flags &=331            ~ExpressionVariable::EVNeedsFreezeDry;332      }333    } else {334      err = Status::FromErrorStringWithFormat(335          "no dematerialization happened for persistent variable %s",336          m_persistent_variable_sp->GetName().AsCString());337      return;338    }339 340    if (m_persistent_variable_sp->m_flags &341            ExpressionVariable::EVNeedsAllocation &&342        !(m_persistent_variable_sp->m_flags &343          ExpressionVariable::EVKeepInTarget)) {344      DestroyAllocation(map, err);345      if (!err.Success())346        return;347    }348  }349 350  void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,351                 Log *log) override {352    StreamString dump_stream;353 354    Status err;355 356    const lldb::addr_t load_addr = process_address + m_offset;357 358    dump_stream.Printf("0x%" PRIx64 ": EntityPersistentVariable (%s)\n",359                       load_addr,360                       m_persistent_variable_sp->GetName().AsCString());361 362    {363      dump_stream.Printf("Pointer:\n");364 365      DataBufferHeap data(m_size, 0);366 367      map.ReadMemory(data.GetBytes(), load_addr, m_size, err);368 369      if (!err.Success()) {370        dump_stream.Printf("  <could not be read>\n");371      } else {372        DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,373                     load_addr);374 375        dump_stream.PutChar('\n');376      }377    }378 379    {380      dump_stream.Printf("Target:\n");381 382      lldb::addr_t target_address;383 384      map.ReadPointerFromMemory(&target_address, load_addr, err);385 386      if (!err.Success()) {387        dump_stream.Printf("  <could not be read>\n");388      } else {389        DataBufferHeap data(390            llvm::expectedToOptional(m_persistent_variable_sp->GetByteSize())391                .value_or(0),392            0);393 394        map.ReadMemory(395            data.GetBytes(), target_address,396            llvm::expectedToOptional(m_persistent_variable_sp->GetByteSize())397                .value_or(0),398            err);399 400        if (!err.Success()) {401          dump_stream.Printf("  <could not be read>\n");402        } else {403          DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,404                       target_address);405 406          dump_stream.PutChar('\n');407        }408      }409    }410 411    log->PutString(dump_stream.GetString());412  }413 414  void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {}415 416private:417  lldb::ExpressionVariableSP m_persistent_variable_sp;418  Materializer::PersistentVariableDelegate *m_delegate;419};420 421uint32_t Materializer::AddPersistentVariable(422    lldb::ExpressionVariableSP &persistent_variable_sp,423    PersistentVariableDelegate *delegate, Status &err) {424  EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());425  *iter = std::make_unique<EntityPersistentVariable>(persistent_variable_sp,426                                                     delegate);427  uint32_t ret = AddStructMember(**iter);428  (*iter)->SetOffset(ret);429  return ret;430}431 432/// Base class for materialization of Variables and ValueObjects.433///434/// Subclasses specify how to obtain the Value which is to be435/// materialized.436class EntityVariableBase : public Materializer::Entity {437public:438  virtual ~EntityVariableBase() = default;439 440  EntityVariableBase() {441    // Hard-coding to maximum size of a pointer since all variables are442    // materialized by reference443    m_size = g_default_var_byte_size;444    m_alignment = g_default_var_alignment;445  }446 447  void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,448                   lldb::addr_t process_address, Status &err) override {449    Log *log = GetLog(LLDBLog::Expressions);450 451    const lldb::addr_t load_addr = process_address + m_offset;452    if (log) {453      LLDB_LOGF(log,454                "EntityVariable::Materialize [address = 0x%" PRIx64455                ", m_variable_sp = %s]",456                (uint64_t)load_addr, GetName().GetCString());457    }458 459    ExecutionContextScope *scope = frame_sp.get();460 461    if (!scope)462      scope = map.GetBestExecutionContextScope();463 464    lldb::ValueObjectSP valobj_sp = SetupValueObject(scope);465 466    if (!valobj_sp) {467      err = Status::FromErrorStringWithFormat(468          "couldn't get a value object for variable %s", GetName().AsCString());469      return;470    }471 472    Status valobj_error = valobj_sp->GetError().Clone();473 474    if (valobj_error.Fail()) {475      err = Status::FromErrorStringWithFormat(476          "couldn't get the value of variable %s: %s", GetName().AsCString(),477          valobj_error.AsCString());478      return;479    }480 481    if (m_is_reference) {482      DataExtractor valobj_extractor;483      Status extract_error;484      valobj_sp->GetData(valobj_extractor, extract_error);485 486      if (!extract_error.Success()) {487        err = Status::FromErrorStringWithFormat(488            "couldn't read contents of reference variable %s: %s",489            GetName().AsCString(), extract_error.AsCString());490        return;491      }492 493      lldb::offset_t offset = 0;494      lldb::addr_t reference_addr = valobj_extractor.GetAddress(&offset);495 496      Status write_error;497      map.WritePointerToMemory(load_addr, reference_addr, write_error);498 499      if (!write_error.Success()) {500        err = Status::FromErrorStringWithFormat(501            "couldn't write the contents of reference "502            "variable %s to memory: %s",503            GetName().AsCString(), write_error.AsCString());504        return;505      }506    } else {507      lldb::addr_t addr_of_valobj =508          valobj_sp->GetAddressOf(/*scalar_is_load_address=*/false).address;509      if (addr_of_valobj != LLDB_INVALID_ADDRESS) {510        Status write_error;511        map.WritePointerToMemory(load_addr, addr_of_valobj, write_error);512 513        if (!write_error.Success()) {514          err = Status::FromErrorStringWithFormat(515              "couldn't write the address of variable %s to memory: %s",516              GetName().AsCString(), write_error.AsCString());517          return;518        }519      } else {520        DataExtractor data;521        Status extract_error;522        valobj_sp->GetData(data, extract_error);523        if (!extract_error.Success()) {524          err = Status::FromErrorStringWithFormat(525              "couldn't get the value of %s: %s", GetName().AsCString(),526              extract_error.AsCString());527          return;528        }529 530        if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {531          err = Status::FromErrorStringWithFormat(532              "trying to create a temporary region for %s but one exists",533              GetName().AsCString());534          return;535        }536 537        if (data.GetByteSize() <538            llvm::expectedToOptional(GetByteSize(scope)).value_or(0)) {539          if (data.GetByteSize() == 0 && !LocationExpressionIsValid()) {540            err = Status::FromErrorStringWithFormat(541                "the variable '%s' has no location, "542                "it may have been optimized out",543                GetName().AsCString());544          } else {545            err = Status::FromErrorStringWithFormat(546                "size of variable %s (%" PRIu64547                ") is larger than the ValueObject's size (%" PRIu64 ")",548                GetName().AsCString(),549                llvm::expectedToOptional(GetByteSize(scope)).value_or(0),550                data.GetByteSize());551          }552          return;553        }554 555        std::optional<size_t> opt_bit_align = GetTypeBitAlign(scope);556        if (!opt_bit_align) {557          err = Status::FromErrorStringWithFormat(558              "can't get the type alignment for %s", GetName().AsCString());559          return;560        }561 562        size_t byte_align = (*opt_bit_align + 7) / 8;563 564        const bool zero_memory = false;565        if (auto address_or_error = map.Malloc(566                data.GetByteSize(), byte_align,567                lldb::ePermissionsReadable | lldb::ePermissionsWritable,568                IRMemoryMap::eAllocationPolicyMirror, zero_memory)) {569          m_temporary_allocation = *address_or_error;570        } else {571          err = Status::FromErrorStringWithFormat(572              "couldn't allocate a temporary region for %s: %s",573              GetName().AsCString(),574              toString(address_or_error.takeError()).c_str());575          return;576        }577 578        m_temporary_allocation_size = data.GetByteSize();579 580        m_original_data = std::make_shared<DataBufferHeap>(data.GetDataStart(),581                                                           data.GetByteSize());582 583        Status write_error;584 585        map.WriteMemory(m_temporary_allocation, data.GetDataStart(),586                        data.GetByteSize(), write_error);587 588        if (!write_error.Success()) {589          err = Status::FromErrorStringWithFormat(590              "couldn't write to the temporary region for %s: %s",591              GetName().AsCString(), write_error.AsCString());592          return;593        }594 595        Status pointer_write_error;596 597        map.WritePointerToMemory(load_addr, m_temporary_allocation,598                                 pointer_write_error);599 600        if (!pointer_write_error.Success()) {601          err = Status::FromErrorStringWithFormat(602              "couldn't write the address of the temporary region for %s: %s",603              GetName().AsCString(), pointer_write_error.AsCString());604        }605      }606    }607  }608 609  void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,610                     lldb::addr_t process_address, lldb::addr_t frame_top,611                     lldb::addr_t frame_bottom, Status &err) override {612    Log *log = GetLog(LLDBLog::Expressions);613 614    const lldb::addr_t load_addr = process_address + m_offset;615    if (log) {616      LLDB_LOGF(log,617                "EntityVariable::Dematerialize [address = 0x%" PRIx64618                ", m_variable_sp = %s]",619                (uint64_t)load_addr, GetName().AsCString());620    }621 622    if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {623      ExecutionContextScope *scope = frame_sp.get();624 625      if (!scope)626        scope = map.GetBestExecutionContextScope();627 628      lldb::ValueObjectSP valobj_sp = SetupValueObject(scope);629 630      if (!valobj_sp) {631        err = Status::FromErrorStringWithFormat(632            "couldn't get a value object for variable %s",633            GetName().AsCString());634        return;635      }636 637      lldb_private::DataExtractor data;638 639      Status extract_error;640 641      map.GetMemoryData(642          data, m_temporary_allocation,643          llvm::expectedToOptional(valobj_sp->GetByteSize()).value_or(0),644          extract_error);645 646      if (!extract_error.Success()) {647        err = Status::FromErrorStringWithFormat(648            "couldn't get the data for variable %s", GetName().AsCString());649        return;650      }651 652      bool actually_write = true;653 654      if (m_original_data) {655        if ((data.GetByteSize() == m_original_data->GetByteSize()) &&656            !memcmp(m_original_data->GetBytes(), data.GetDataStart(),657                    data.GetByteSize())) {658          actually_write = false;659        }660      }661 662      Status set_error;663 664      if (actually_write) {665        valobj_sp->SetData(data, set_error);666 667        if (!set_error.Success()) {668          err = Status::FromErrorStringWithFormat(669              "couldn't write the new contents of %s back into the variable",670              GetName().AsCString());671          return;672        }673      }674 675      Status free_error;676 677      map.Free(m_temporary_allocation, free_error);678 679      if (!free_error.Success()) {680        err = Status::FromErrorStringWithFormat(681            "couldn't free the temporary region for %s: %s",682            GetName().AsCString(), free_error.AsCString());683        return;684      }685 686      m_original_data.reset();687      m_temporary_allocation = LLDB_INVALID_ADDRESS;688      m_temporary_allocation_size = 0;689    }690  }691 692  void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,693                 Log *log) override {694    StreamString dump_stream;695 696    const lldb::addr_t load_addr = process_address + m_offset;697    dump_stream.Printf("0x%" PRIx64 ": EntityVariable\n", load_addr);698 699    Status err;700 701    lldb::addr_t ptr = LLDB_INVALID_ADDRESS;702 703    {704      dump_stream.Printf("Pointer:\n");705 706      DataBufferHeap data(m_size, 0);707 708      map.ReadMemory(data.GetBytes(), load_addr, m_size, err);709 710      if (!err.Success()) {711        dump_stream.Printf("  <could not be read>\n");712      } else {713        DataExtractor extractor(data.GetBytes(), data.GetByteSize(),714                                map.GetByteOrder(), map.GetAddressByteSize());715 716        DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,717                     load_addr);718 719        lldb::offset_t offset = 0;720 721        ptr = extractor.GetAddress(&offset);722 723        dump_stream.PutChar('\n');724      }725    }726 727    if (m_temporary_allocation == LLDB_INVALID_ADDRESS) {728      dump_stream.Printf("Points to process memory:\n");729    } else {730      dump_stream.Printf("Temporary allocation:\n");731    }732 733    if (ptr == LLDB_INVALID_ADDRESS) {734      dump_stream.Printf("  <could not be be found>\n");735    } else {736      DataBufferHeap data(m_temporary_allocation_size, 0);737 738      map.ReadMemory(data.GetBytes(), m_temporary_allocation,739                     m_temporary_allocation_size, err);740 741      if (!err.Success()) {742        dump_stream.Printf("  <could not be read>\n");743      } else {744        DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,745                     load_addr);746 747        dump_stream.PutChar('\n');748      }749    }750 751    log->PutString(dump_stream.GetString());752  }753 754  void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {755    if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {756      Status free_error;757 758      map.Free(m_temporary_allocation, free_error);759 760      m_temporary_allocation = LLDB_INVALID_ADDRESS;761      m_temporary_allocation_size = 0;762    }763  }764 765private:766  virtual ConstString GetName() const = 0;767 768  /// Creates and returns ValueObject tied to this variable769  /// and prepares Entity for materialization.770  ///771  /// Called each time the Materializer (de)materializes a772  /// variable. We re-create the ValueObject based on the773  /// current ExecutionContextScope since clients such as774  /// conditional breakpoints may materialize the same775  /// EntityVariable multiple times with different frames.776  ///777  /// Each subsequent use of the EntityVariableBase interface778  /// will query the newly created ValueObject until this779  /// function is called again.780  virtual lldb::ValueObjectSP781  SetupValueObject(ExecutionContextScope *scope) = 0;782 783  /// Returns size in bytes of the type associated with this variable784  ///785  /// \returns On success, returns byte size of the type associated786  ///          with this variable. Returns std::nullopt otherwise.787  virtual llvm::Expected<uint64_t>788  GetByteSize(ExecutionContextScope *scope) const = 0;789 790  /// Returns 'true' if the location expression associated with this variable791  /// is valid.792  virtual bool LocationExpressionIsValid() const = 0;793 794  /// Returns alignment of the type associated with this variable in bits.795  ///796  /// \returns On success, returns alignment in bits for the type associated797  ///          with this variable. Returns std::nullopt otherwise.798  virtual std::optional<size_t>799  GetTypeBitAlign(ExecutionContextScope *scope) const = 0;800 801protected:802  bool m_is_reference = false;803  lldb::addr_t m_temporary_allocation = LLDB_INVALID_ADDRESS;804  size_t m_temporary_allocation_size = 0;805  lldb::DataBufferSP m_original_data;806};807 808/// Represents an Entity constructed from a VariableSP.809///810/// This class is used for materialization of variables for which811/// the user has a VariableSP on hand. The ValueObject is then812/// derived from the associated DWARF location expression when needed813/// by the Materializer.814class EntityVariable : public EntityVariableBase {815public:816  EntityVariable(lldb::VariableSP &variable_sp) : m_variable_sp(variable_sp) {817    m_is_reference =818        m_variable_sp->GetType()->GetForwardCompilerType().IsReferenceType();819  }820 821  ConstString GetName() const override { return m_variable_sp->GetName(); }822 823  lldb::ValueObjectSP SetupValueObject(ExecutionContextScope *scope) override {824    assert(m_variable_sp != nullptr);825    return ValueObjectVariable::Create(scope, m_variable_sp);826  }827 828  llvm::Expected<uint64_t>829  GetByteSize(ExecutionContextScope *scope) const override {830    return m_variable_sp->GetType()->GetByteSize(scope);831  }832 833  bool LocationExpressionIsValid() const override {834    return m_variable_sp->LocationExpressionList().IsValid();835  }836 837  std::optional<size_t>838  GetTypeBitAlign(ExecutionContextScope *scope) const override {839    return m_variable_sp->GetType()->GetLayoutCompilerType().GetTypeBitAlign(840        scope);841  }842 843private:844  lldb::VariableSP m_variable_sp; ///< Variable that this entity is based on.845};846 847/// Represents an Entity constructed from a VariableSP.848///849/// This class is used for materialization of variables for850/// which the user does not have a VariableSP available (e.g.,851/// when materializing ivars).852class EntityValueObject : public EntityVariableBase {853public:854  EntityValueObject(ConstString name, ValueObjectProviderTy provider)855      : m_name(name), m_valobj_provider(std::move(provider)) {856    assert(m_valobj_provider);857  }858 859  ConstString GetName() const override { return m_name; }860 861  lldb::ValueObjectSP SetupValueObject(ExecutionContextScope *scope) override {862    m_valobj_sp =863        m_valobj_provider(GetName(), scope->CalculateStackFrame().get());864 865    if (m_valobj_sp)866      m_is_reference = m_valobj_sp->GetCompilerType().IsReferenceType();867 868    return m_valobj_sp;869  }870 871  llvm::Expected<uint64_t>872  GetByteSize(ExecutionContextScope *scope) const override {873    if (m_valobj_sp)874      return m_valobj_sp->GetCompilerType().GetByteSize(scope);875 876    return llvm::createStringError("no value object");877  }878 879  bool LocationExpressionIsValid() const override {880    if (m_valobj_sp)881      return m_valobj_sp->GetError().Success();882 883    return false;884  }885 886  std::optional<size_t>887  GetTypeBitAlign(ExecutionContextScope *scope) const override {888    if (m_valobj_sp)889      return m_valobj_sp->GetCompilerType().GetTypeBitAlign(scope);890 891    return {};892  }893 894private:895  ConstString m_name;896  lldb::ValueObjectSP m_valobj_sp;897  ValueObjectProviderTy m_valobj_provider;898};899 900uint32_t Materializer::AddVariable(lldb::VariableSP &variable_sp, Status &err) {901  EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());902  *iter = std::make_unique<EntityVariable>(variable_sp);903  uint32_t ret = AddStructMember(**iter);904  (*iter)->SetOffset(ret);905  return ret;906}907 908uint32_t Materializer::AddValueObject(ConstString name,909                                      ValueObjectProviderTy valobj_provider,910                                      Status &err) {911  assert(valobj_provider);912  EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());913  *iter = std::make_unique<EntityValueObject>(name, std::move(valobj_provider));914  uint32_t ret = AddStructMember(**iter);915  (*iter)->SetOffset(ret);916  return ret;917}918 919class EntityResultVariable : public Materializer::Entity {920public:921  EntityResultVariable(const CompilerType &type, bool is_program_reference,922                       bool keep_in_memory,923                       Materializer::PersistentVariableDelegate *delegate)924      : Entity(), m_type(type), m_is_program_reference(is_program_reference),925        m_keep_in_memory(keep_in_memory), m_delegate(delegate) {926    // Hard-coding to maximum size of a pointer since all results are927    // materialized by reference928    m_size = g_default_var_byte_size;929    m_alignment = g_default_var_alignment;930  }931 932  void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,933                   lldb::addr_t process_address, Status &err) override {934    if (!m_is_program_reference) {935      if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {936        err = Status::FromErrorString(937            "Trying to create a temporary region for the result "938            "but one exists");939        return;940      }941 942      const lldb::addr_t load_addr = process_address + m_offset;943 944      ExecutionContextScope *exe_scope = frame_sp.get();945      if (!exe_scope)946        exe_scope = map.GetBestExecutionContextScope();947 948      auto byte_size_or_err = m_type.GetByteSize(exe_scope);949      if (!byte_size_or_err) {950        err = Status::FromError(byte_size_or_err.takeError());951        return;952      }953      auto byte_size = *byte_size_or_err;954 955      std::optional<size_t> opt_bit_align = m_type.GetTypeBitAlign(exe_scope);956      if (!opt_bit_align) {957        err = Status::FromErrorStringWithFormat(958            "can't get the alignment of type  \"%s\"",959            m_type.GetTypeName().AsCString());960        return;961      }962 963      size_t byte_align = (*opt_bit_align + 7) / 8;964 965      const bool zero_memory = true;966      if (auto address_or_error = map.Malloc(967              byte_size, byte_align,968              lldb::ePermissionsReadable | lldb::ePermissionsWritable,969              IRMemoryMap::eAllocationPolicyMirror, zero_memory)) {970        m_temporary_allocation = *address_or_error;971      } else {972        err = Status::FromErrorStringWithFormat(973            "couldn't allocate a temporary region for the result: %s",974            toString(address_or_error.takeError()).c_str());975        return;976      }977 978      m_temporary_allocation_size = byte_size;979 980      Status pointer_write_error;981 982      map.WritePointerToMemory(load_addr, m_temporary_allocation,983                               pointer_write_error);984 985      if (!pointer_write_error.Success()) {986        err = Status::FromErrorStringWithFormat(987            "couldn't write the address of the "988            "temporary region for the result: %s",989            pointer_write_error.AsCString());990      }991    }992  }993 994  void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,995                     lldb::addr_t process_address, lldb::addr_t frame_top,996                     lldb::addr_t frame_bottom, Status &err) override {997    err.Clear();998 999    ExecutionContextScope *exe_scope = frame_sp.get();1000    if (!exe_scope)1001      exe_scope = map.GetBestExecutionContextScope();1002 1003    if (!exe_scope) {1004      err = Status::FromErrorString(1005          "Couldn't dematerialize a result variable: invalid "1006          "execution context scope");1007      return;1008    }1009 1010    lldb::addr_t address;1011    Status read_error;1012    const lldb::addr_t load_addr = process_address + m_offset;1013 1014    map.ReadPointerFromMemory(&address, load_addr, read_error);1015 1016    if (!read_error.Success()) {1017      err = Status::FromErrorString(1018          "Couldn't dematerialize a result variable: couldn't "1019          "read its address");1020      return;1021    }1022 1023    lldb::TargetSP target_sp = exe_scope->CalculateTarget();1024 1025    if (!target_sp) {1026      err = Status::FromErrorString(1027          "Couldn't dematerialize a result variable: no target");1028      return;1029    }1030 1031    auto type_system_or_err =1032        target_sp->GetScratchTypeSystemForLanguage(m_type.GetMinimumLanguage());1033 1034    if (auto error = type_system_or_err.takeError()) {1035      err = Status::FromErrorStringWithFormat(1036          "Couldn't dematerialize a result variable: "1037          "couldn't get the corresponding type "1038          "system: %s",1039          llvm::toString(std::move(error)).c_str());1040      return;1041    }1042    auto ts = *type_system_or_err;1043    if (!ts) {1044      err = Status::FromErrorStringWithFormat(1045          "Couldn't dematerialize a result variable: "1046          "couldn't corresponding type system is "1047          "no longer live.");1048      return;1049    }1050    PersistentExpressionState *persistent_state =1051        ts->GetPersistentExpressionState();1052 1053    if (!persistent_state) {1054      err = Status::FromErrorString(1055          "Couldn't dematerialize a result variable: "1056          "corresponding type system doesn't handle persistent "1057          "variables");1058      return;1059    }1060 1061    ConstString name = m_delegate1062                           ? m_delegate->GetName()1063                           : persistent_state->GetNextPersistentVariableName();1064 1065    lldb::ExpressionVariableSP ret = persistent_state->CreatePersistentVariable(1066        exe_scope, name, m_type, map.GetByteOrder(), map.GetAddressByteSize());1067 1068    if (!ret) {1069      err = Status::FromErrorStringWithFormat(1070          "couldn't dematerialize a result variable: "1071          "failed to make persistent variable %s",1072          name.AsCString());1073      return;1074    }1075 1076    lldb::ProcessSP process_sp =1077        map.GetBestExecutionContextScope()->CalculateProcess();1078 1079    if (m_delegate) {1080      m_delegate->DidDematerialize(ret);1081    }1082 1083    bool can_persist = m_is_program_reference &&1084                       !(address >= frame_bottom && address < frame_top);1085 1086    if (can_persist && m_keep_in_memory) {1087      ret->m_live_sp = ValueObjectConstResult::Create(exe_scope, m_type, name,1088                                                      address, eAddressTypeLoad,1089                                                      map.GetAddressByteSize());1090    }1091 1092    ret->ValueUpdated();1093 1094    const size_t pvar_byte_size =1095        llvm::expectedToOptional(ret->GetByteSize()).value_or(0);1096    uint8_t *pvar_data = ret->GetValueBytes();1097 1098    map.ReadMemory(pvar_data, address, pvar_byte_size, read_error);1099 1100    if (!read_error.Success()) {1101      err = Status::FromErrorString(1102          "Couldn't dematerialize a result variable: couldn't read its memory");1103      return;1104    }1105 1106    if (!can_persist || !m_keep_in_memory) {1107      ret->m_flags |= ExpressionVariable::EVNeedsAllocation;1108 1109      if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {1110        Status free_error;1111        map.Free(m_temporary_allocation, free_error);1112      }1113    } else {1114      ret->m_flags |= m_is_program_reference1115                          ? ExpressionVariable::EVIsProgramReference1116                          : ExpressionVariable::EVIsLLDBAllocated;1117    }1118 1119    m_temporary_allocation = LLDB_INVALID_ADDRESS;1120    m_temporary_allocation_size = 0;1121  }1122 1123  void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,1124                 Log *log) override {1125    StreamString dump_stream;1126 1127    const lldb::addr_t load_addr = process_address + m_offset;1128 1129    dump_stream.Printf("0x%" PRIx64 ": EntityResultVariable\n", load_addr);1130 1131    Status err;1132 1133    lldb::addr_t ptr = LLDB_INVALID_ADDRESS;1134 1135    {1136      dump_stream.Printf("Pointer:\n");1137 1138      DataBufferHeap data(m_size, 0);1139 1140      map.ReadMemory(data.GetBytes(), load_addr, m_size, err);1141 1142      if (!err.Success()) {1143        dump_stream.Printf("  <could not be read>\n");1144      } else {1145        DataExtractor extractor(data.GetBytes(), data.GetByteSize(),1146                                map.GetByteOrder(), map.GetAddressByteSize());1147 1148        DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,1149                     load_addr);1150 1151        lldb::offset_t offset = 0;1152 1153        ptr = extractor.GetAddress(&offset);1154 1155        dump_stream.PutChar('\n');1156      }1157    }1158 1159    if (m_temporary_allocation == LLDB_INVALID_ADDRESS) {1160      dump_stream.Printf("Points to process memory:\n");1161    } else {1162      dump_stream.Printf("Temporary allocation:\n");1163    }1164 1165    if (ptr == LLDB_INVALID_ADDRESS) {1166      dump_stream.Printf("  <could not be be found>\n");1167    } else {1168      DataBufferHeap data(m_temporary_allocation_size, 0);1169 1170      map.ReadMemory(data.GetBytes(), m_temporary_allocation,1171                     m_temporary_allocation_size, err);1172 1173      if (!err.Success()) {1174        dump_stream.Printf("  <could not be read>\n");1175      } else {1176        DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,1177                     load_addr);1178 1179        dump_stream.PutChar('\n');1180      }1181    }1182 1183    log->PutString(dump_stream.GetString());1184  }1185 1186  void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {1187    if (!m_keep_in_memory && m_temporary_allocation != LLDB_INVALID_ADDRESS) {1188      Status free_error;1189 1190      map.Free(m_temporary_allocation, free_error);1191    }1192 1193    m_temporary_allocation = LLDB_INVALID_ADDRESS;1194    m_temporary_allocation_size = 0;1195  }1196 1197private:1198  CompilerType m_type;1199  /// This is used both to control whether this result entity can (and should)1200  /// track the value in inferior memory, as well as to control whether LLDB1201  /// needs to allocate memory for the variable during materialization.1202  bool m_is_program_reference;1203  bool m_keep_in_memory;1204 1205  lldb::addr_t m_temporary_allocation = LLDB_INVALID_ADDRESS;1206  size_t m_temporary_allocation_size = 0;1207  Materializer::PersistentVariableDelegate *m_delegate;1208};1209 1210uint32_t Materializer::AddResultVariable(const CompilerType &type,1211                                         bool is_program_reference,1212                                         bool keep_in_memory,1213                                         PersistentVariableDelegate *delegate,1214                                         Status &err) {1215  EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());1216  *iter = std::make_unique<EntityResultVariable>(type, is_program_reference,1217                                                 keep_in_memory, delegate);1218  uint32_t ret = AddStructMember(**iter);1219  (*iter)->SetOffset(ret);1220  return ret;1221}1222 1223class EntitySymbol : public Materializer::Entity {1224public:1225  EntitySymbol(const Symbol &symbol) : Entity(), m_symbol(symbol) {1226    // Hard-coding to maximum size of a symbol1227    m_size = g_default_var_byte_size;1228    m_alignment = g_default_var_alignment;1229  }1230 1231  void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,1232                   lldb::addr_t process_address, Status &err) override {1233    Log *log = GetLog(LLDBLog::Expressions);1234 1235    const lldb::addr_t load_addr = process_address + m_offset;1236 1237    if (log) {1238      LLDB_LOGF(log,1239                "EntitySymbol::Materialize [address = 0x%" PRIx641240                ", m_symbol = %s]",1241                (uint64_t)load_addr, m_symbol.GetName().AsCString());1242    }1243 1244    const Address sym_address = m_symbol.GetAddress();1245 1246    ExecutionContextScope *exe_scope = frame_sp.get();1247    if (!exe_scope)1248      exe_scope = map.GetBestExecutionContextScope();1249 1250    lldb::TargetSP target_sp;1251 1252    if (exe_scope)1253      target_sp = map.GetBestExecutionContextScope()->CalculateTarget();1254 1255    if (!target_sp) {1256      err = Status::FromErrorStringWithFormat(1257          "couldn't resolve symbol %s because there is no target",1258          m_symbol.GetName().AsCString());1259      return;1260    }1261 1262    lldb::addr_t resolved_address = sym_address.GetLoadAddress(target_sp.get());1263 1264    if (resolved_address == LLDB_INVALID_ADDRESS)1265      resolved_address = sym_address.GetFileAddress();1266 1267    Status pointer_write_error;1268 1269    map.WritePointerToMemory(load_addr, resolved_address, pointer_write_error);1270 1271    if (!pointer_write_error.Success()) {1272      err = Status::FromErrorStringWithFormat(1273          "couldn't write the address of symbol %s: %s",1274          m_symbol.GetName().AsCString(), pointer_write_error.AsCString());1275      return;1276    }1277  }1278 1279  void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,1280                     lldb::addr_t process_address, lldb::addr_t frame_top,1281                     lldb::addr_t frame_bottom, Status &err) override {1282    Log *log = GetLog(LLDBLog::Expressions);1283 1284    const lldb::addr_t load_addr = process_address + m_offset;1285 1286    if (log) {1287      LLDB_LOGF(log,1288                "EntitySymbol::Dematerialize [address = 0x%" PRIx641289                ", m_symbol = %s]",1290                (uint64_t)load_addr, m_symbol.GetName().AsCString());1291    }1292 1293    // no work needs to be done1294  }1295 1296  void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,1297                 Log *log) override {1298    StreamString dump_stream;1299 1300    Status err;1301 1302    const lldb::addr_t load_addr = process_address + m_offset;1303 1304    dump_stream.Printf("0x%" PRIx64 ": EntitySymbol (%s)\n", load_addr,1305                       m_symbol.GetName().AsCString());1306 1307    {1308      dump_stream.Printf("Pointer:\n");1309 1310      DataBufferHeap data(m_size, 0);1311 1312      map.ReadMemory(data.GetBytes(), load_addr, m_size, err);1313 1314      if (!err.Success()) {1315        dump_stream.Printf("  <could not be read>\n");1316      } else {1317        DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,1318                     load_addr);1319 1320        dump_stream.PutChar('\n');1321      }1322    }1323 1324    log->PutString(dump_stream.GetString());1325  }1326 1327  void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {}1328 1329private:1330  Symbol m_symbol;1331};1332 1333uint32_t Materializer::AddSymbol(const Symbol &symbol_sp, Status &err) {1334  EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());1335  *iter = std::make_unique<EntitySymbol>(symbol_sp);1336  uint32_t ret = AddStructMember(**iter);1337  (*iter)->SetOffset(ret);1338  return ret;1339}1340 1341class EntityRegister : public Materializer::Entity {1342public:1343  EntityRegister(const RegisterInfo &register_info)1344      : Entity(), m_register_info(register_info) {1345    // Hard-coding alignment conservatively1346    m_size = m_register_info.byte_size;1347    m_alignment = m_register_info.byte_size;1348  }1349 1350  void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,1351                   lldb::addr_t process_address, Status &err) override {1352    Log *log = GetLog(LLDBLog::Expressions);1353 1354    const lldb::addr_t load_addr = process_address + m_offset;1355 1356    if (log) {1357      LLDB_LOGF(log,1358                "EntityRegister::Materialize [address = 0x%" PRIx641359                ", m_register_info = %s]",1360                (uint64_t)load_addr, m_register_info.name);1361    }1362 1363    RegisterValue reg_value;1364 1365    if (!frame_sp.get()) {1366      err = Status::FromErrorStringWithFormat(1367          "couldn't materialize register %s without a stack frame",1368          m_register_info.name);1369      return;1370    }1371 1372    lldb::RegisterContextSP reg_context_sp = frame_sp->GetRegisterContext();1373 1374    if (!reg_context_sp->ReadRegister(&m_register_info, reg_value)) {1375      err = Status::FromErrorStringWithFormat(1376          "couldn't read the value of register %s", m_register_info.name);1377      return;1378    }1379 1380    if (reg_value.GetByteSize() != m_register_info.byte_size) {1381      err = Status::FromErrorStringWithFormat(1382          "data for register %s had size %llu but we expected %llu",1383          m_register_info.name, (unsigned long long)reg_value.GetByteSize(),1384          (unsigned long long)m_register_info.byte_size);1385      return;1386    }1387 1388    lldb_private::DataBufferHeap buf(reg_value.GetByteSize(), 0);1389    reg_value.GetAsMemoryData(m_register_info, buf.GetBytes(),1390                              buf.GetByteSize(), map.GetByteOrder(), err);1391    if (!err.Success())1392      return;1393 1394    m_register_contents = std::make_shared<DataBufferHeap>(buf);1395 1396    Status write_error;1397 1398    map.WriteMemory(load_addr, buf.GetBytes(), reg_value.GetByteSize(),1399                    write_error);1400 1401    if (!write_error.Success()) {1402      err = Status::FromErrorStringWithFormat(1403          "couldn't write the contents of register %s: %s",1404          m_register_info.name, write_error.AsCString());1405      return;1406    }1407  }1408 1409  void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,1410                     lldb::addr_t process_address, lldb::addr_t frame_top,1411                     lldb::addr_t frame_bottom, Status &err) override {1412    Log *log = GetLog(LLDBLog::Expressions);1413 1414    const lldb::addr_t load_addr = process_address + m_offset;1415 1416    if (log) {1417      LLDB_LOGF(log,1418                "EntityRegister::Dematerialize [address = 0x%" PRIx641419                ", m_register_info = %s]",1420                (uint64_t)load_addr, m_register_info.name);1421    }1422 1423    Status extract_error;1424 1425    DataExtractor register_data;1426 1427    if (!frame_sp.get()) {1428      err = Status::FromErrorStringWithFormat(1429          "couldn't dematerialize register %s without a stack frame",1430          m_register_info.name);1431      return;1432    }1433 1434    lldb::RegisterContextSP reg_context_sp = frame_sp->GetRegisterContext();1435 1436    map.GetMemoryData(register_data, load_addr, m_register_info.byte_size,1437                      extract_error);1438 1439    if (!extract_error.Success()) {1440      err = Status::FromErrorStringWithFormat(1441          "couldn't get the data for register %s: %s", m_register_info.name,1442          extract_error.AsCString());1443      return;1444    }1445 1446    if (!memcmp(register_data.GetDataStart(), m_register_contents->GetBytes(),1447                register_data.GetByteSize())) {1448      // No write required, and in particular we avoid errors if the register1449      // wasn't writable1450 1451      m_register_contents.reset();1452      return;1453    }1454 1455    m_register_contents.reset();1456 1457    RegisterValue register_value(register_data.GetData(),1458                                 register_data.GetByteOrder());1459 1460    if (!reg_context_sp->WriteRegister(&m_register_info, register_value)) {1461      err = Status::FromErrorStringWithFormat(1462          "couldn't write the value of register %s", m_register_info.name);1463      return;1464    }1465  }1466 1467  void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,1468                 Log *log) override {1469    StreamString dump_stream;1470 1471    Status err;1472 1473    const lldb::addr_t load_addr = process_address + m_offset;1474 1475    dump_stream.Printf("0x%" PRIx64 ": EntityRegister (%s)\n", load_addr,1476                       m_register_info.name);1477 1478    {1479      dump_stream.Printf("Value:\n");1480 1481      DataBufferHeap data(m_size, 0);1482 1483      map.ReadMemory(data.GetBytes(), load_addr, m_size, err);1484 1485      if (!err.Success()) {1486        dump_stream.Printf("  <could not be read>\n");1487      } else {1488        DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,1489                     load_addr);1490 1491        dump_stream.PutChar('\n');1492      }1493    }1494 1495    log->PutString(dump_stream.GetString());1496  }1497 1498  void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {}1499 1500private:1501  RegisterInfo m_register_info;1502  lldb::DataBufferSP m_register_contents;1503};1504 1505uint32_t Materializer::AddRegister(const RegisterInfo &register_info,1506                                   Status &err) {1507  EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());1508  *iter = std::make_unique<EntityRegister>(register_info);1509  uint32_t ret = AddStructMember(**iter);1510  (*iter)->SetOffset(ret);1511  return ret;1512}1513 1514Materializer::~Materializer() {1515  DematerializerSP dematerializer_sp = m_dematerializer_wp.lock();1516 1517  if (dematerializer_sp)1518    dematerializer_sp->Wipe();1519}1520 1521Materializer::DematerializerSP1522Materializer::Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,1523                          lldb::addr_t process_address, Status &error) {1524  ExecutionContextScope *exe_scope = frame_sp.get();1525  if (!exe_scope)1526    exe_scope = map.GetBestExecutionContextScope();1527 1528  DematerializerSP dematerializer_sp = m_dematerializer_wp.lock();1529 1530  if (dematerializer_sp) {1531    error =1532        Status::FromErrorString("Couldn't materialize: already materialized");1533  }1534 1535  DematerializerSP ret(1536      new Dematerializer(*this, frame_sp, map, process_address));1537 1538  if (!exe_scope) {1539    error =1540        Status::FromErrorString("Couldn't materialize: target doesn't exist");1541  }1542 1543  for (EntityUP &entity_up : m_entities) {1544    entity_up->Materialize(frame_sp, map, process_address, error);1545 1546    if (!error.Success())1547      return DematerializerSP();1548  }1549 1550  if (Log *log = GetLog(LLDBLog::Expressions)) {1551    LLDB_LOGF(1552        log,1553        "Materializer::Materialize (frame_sp = %p, process_address = 0x%" PRIx641554        ") materialized:",1555        static_cast<void *>(frame_sp.get()), process_address);1556    for (EntityUP &entity_up : m_entities)1557      entity_up->DumpToLog(map, process_address, log);1558  }1559 1560  m_dematerializer_wp = ret;1561 1562  return ret;1563}1564 1565void Materializer::Dematerializer::Dematerialize(Status &error,1566                                                 lldb::addr_t frame_bottom,1567                                                 lldb::addr_t frame_top) {1568  lldb::StackFrameSP frame_sp;1569 1570  lldb::ThreadSP thread_sp = m_thread_wp.lock();1571  if (thread_sp)1572    frame_sp = thread_sp->GetFrameWithStackID(m_stack_id);1573 1574  ExecutionContextScope *exe_scope = frame_sp.get();1575  if (!exe_scope)1576    exe_scope = m_map->GetBestExecutionContextScope();1577 1578  if (!IsValid()) {1579    error = Status::FromErrorString(1580        "Couldn't dematerialize: invalid dematerializer");1581  }1582 1583  if (!exe_scope) {1584    error = Status::FromErrorString("Couldn't dematerialize: target is gone");1585  } else {1586    if (Log *log = GetLog(LLDBLog::Expressions)) {1587      LLDB_LOGF(log,1588                "Materializer::Dematerialize (frame_sp = %p, process_address "1589                "= 0x%" PRIx64 ") about to dematerialize:",1590                static_cast<void *>(frame_sp.get()), m_process_address);1591      for (EntityUP &entity_up : m_materializer->m_entities)1592        entity_up->DumpToLog(*m_map, m_process_address, log);1593    }1594 1595    for (EntityUP &entity_up : m_materializer->m_entities) {1596      entity_up->Dematerialize(frame_sp, *m_map, m_process_address, frame_top,1597                               frame_bottom, error);1598 1599      if (!error.Success())1600        break;1601    }1602  }1603 1604  Wipe();1605}1606 1607void Materializer::Dematerializer::Wipe() {1608  if (!IsValid())1609    return;1610 1611  for (EntityUP &entity_up : m_materializer->m_entities) {1612    entity_up->Wipe(*m_map, m_process_address);1613  }1614 1615  m_materializer = nullptr;1616  m_map = nullptr;1617  m_process_address = LLDB_INVALID_ADDRESS;1618}1619 1620Materializer::PersistentVariableDelegate::PersistentVariableDelegate() =1621    default;1622Materializer::PersistentVariableDelegate::~PersistentVariableDelegate() =1623    default;1624