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