1254721Semaste//===-- Materializer.cpp ----------------------------------------*- C++ -*-===// 2254721Semaste// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6254721Semaste// 7254721Semaste//===----------------------------------------------------------------------===// 8254721Semaste 9314564Sdim#include "lldb/Expression/Materializer.h" 10321369Sdim#include "lldb/Core/DumpDataExtractor.h" 11254721Semaste#include "lldb/Core/ValueObjectConstResult.h" 12254721Semaste#include "lldb/Core/ValueObjectVariable.h" 13296417Sdim#include "lldb/Expression/ExpressionVariable.h" 14254721Semaste#include "lldb/Symbol/Symbol.h" 15254721Semaste#include "lldb/Symbol/Type.h" 16254721Semaste#include "lldb/Symbol/Variable.h" 17254721Semaste#include "lldb/Target/ExecutionContext.h" 18254721Semaste#include "lldb/Target/RegisterContext.h" 19254721Semaste#include "lldb/Target/StackFrame.h" 20254721Semaste#include "lldb/Target/Target.h" 21254721Semaste#include "lldb/Target/Thread.h" 22321369Sdim#include "lldb/Utility/Log.h" 23344779Sdim#include "lldb/Utility/RegisterValue.h" 24254721Semaste 25353358Sdim#include <memory> 26353358Sdim 27254721Semasteusing namespace lldb_private; 28254721Semaste 29314564Sdimuint32_t Materializer::AddStructMember(Entity &entity) { 30314564Sdim uint32_t size = entity.GetSize(); 31314564Sdim uint32_t alignment = entity.GetAlignment(); 32309124Sdim 33314564Sdim uint32_t ret; 34309124Sdim 35314564Sdim if (m_current_offset == 0) 36314564Sdim m_struct_alignment = alignment; 37309124Sdim 38314564Sdim if (m_current_offset % alignment) 39314564Sdim m_current_offset += (alignment - (m_current_offset % alignment)); 40309124Sdim 41314564Sdim ret = m_current_offset; 42309124Sdim 43314564Sdim m_current_offset += size; 44309124Sdim 45314564Sdim return ret; 46254721Semaste} 47254721Semaste 48314564Sdimclass EntityPersistentVariable : public Materializer::Entity { 49254721Semastepublic: 50314564Sdim EntityPersistentVariable(lldb::ExpressionVariableSP &persistent_variable_sp, 51314564Sdim Materializer::PersistentVariableDelegate *delegate) 52314564Sdim : Entity(), m_persistent_variable_sp(persistent_variable_sp), 53314564Sdim m_delegate(delegate) { 54314564Sdim // Hard-coding to maximum size of a pointer since persistent variables are 55314564Sdim // materialized by reference 56314564Sdim m_size = 8; 57314564Sdim m_alignment = 8; 58314564Sdim } 59309124Sdim 60321369Sdim void MakeAllocation(IRMemoryMap &map, Status &err) { 61314564Sdim Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); 62254721Semaste 63341825Sdim // Allocate a spare memory area to store the persistent variable's 64341825Sdim // contents. 65309124Sdim 66321369Sdim Status allocate_error; 67314564Sdim const bool zero_memory = false; 68309124Sdim 69314564Sdim lldb::addr_t mem = map.Malloc( 70314564Sdim m_persistent_variable_sp->GetByteSize(), 8, 71314564Sdim lldb::ePermissionsReadable | lldb::ePermissionsWritable, 72314564Sdim IRMemoryMap::eAllocationPolicyMirror, zero_memory, allocate_error); 73309124Sdim 74314564Sdim if (!allocate_error.Success()) { 75314564Sdim err.SetErrorStringWithFormat( 76314564Sdim "couldn't allocate a memory area to store %s: %s", 77314564Sdim m_persistent_variable_sp->GetName().GetCString(), 78314564Sdim allocate_error.AsCString()); 79314564Sdim return; 80314564Sdim } 81309124Sdim 82360784Sdim LLDB_LOGF(log, "Allocated %s (0x%" PRIx64 ") successfully", 83360784Sdim m_persistent_variable_sp->GetName().GetCString(), mem); 84309124Sdim 85314564Sdim // Put the location of the spare memory into the live data of the 86314564Sdim // ValueObject. 87309124Sdim 88314564Sdim m_persistent_variable_sp->m_live_sp = ValueObjectConstResult::Create( 89314564Sdim map.GetBestExecutionContextScope(), 90314564Sdim m_persistent_variable_sp->GetCompilerType(), 91314564Sdim m_persistent_variable_sp->GetName(), mem, eAddressTypeLoad, 92314564Sdim map.GetAddressByteSize()); 93309124Sdim 94314564Sdim // Clear the flag if the variable will never be deallocated. 95309124Sdim 96314564Sdim if (m_persistent_variable_sp->m_flags & 97314564Sdim ExpressionVariable::EVKeepInTarget) { 98321369Sdim Status leak_error; 99314564Sdim map.Leak(mem, leak_error); 100314564Sdim m_persistent_variable_sp->m_flags &= 101314564Sdim ~ExpressionVariable::EVNeedsAllocation; 102314564Sdim } 103309124Sdim 104314564Sdim // Write the contents of the variable to the area. 105309124Sdim 106321369Sdim Status write_error; 107309124Sdim 108314564Sdim map.WriteMemory(mem, m_persistent_variable_sp->GetValueBytes(), 109314564Sdim m_persistent_variable_sp->GetByteSize(), write_error); 110309124Sdim 111314564Sdim if (!write_error.Success()) { 112314564Sdim err.SetErrorStringWithFormat( 113314564Sdim "couldn't write %s to the target: %s", 114314564Sdim m_persistent_variable_sp->GetName().AsCString(), 115314564Sdim write_error.AsCString()); 116314564Sdim return; 117254721Semaste } 118314564Sdim } 119309124Sdim 120321369Sdim void DestroyAllocation(IRMemoryMap &map, Status &err) { 121321369Sdim Status deallocate_error; 122309124Sdim 123314564Sdim map.Free((lldb::addr_t)m_persistent_variable_sp->m_live_sp->GetValue() 124314564Sdim .GetScalar() 125314564Sdim .ULongLong(), 126314564Sdim deallocate_error); 127309124Sdim 128314564Sdim m_persistent_variable_sp->m_live_sp.reset(); 129309124Sdim 130314564Sdim if (!deallocate_error.Success()) { 131314564Sdim err.SetErrorStringWithFormat( 132314564Sdim "couldn't deallocate memory for %s: %s", 133314564Sdim m_persistent_variable_sp->GetName().GetCString(), 134314564Sdim deallocate_error.AsCString()); 135254721Semaste } 136314564Sdim } 137309124Sdim 138314564Sdim void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 139321369Sdim lldb::addr_t process_address, Status &err) override { 140314564Sdim Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); 141254721Semaste 142314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 143309124Sdim 144314564Sdim if (log) { 145360784Sdim LLDB_LOGF(log, 146360784Sdim "EntityPersistentVariable::Materialize [address = 0x%" PRIx64 147360784Sdim ", m_name = %s, m_flags = 0x%hx]", 148360784Sdim (uint64_t)load_addr, 149360784Sdim m_persistent_variable_sp->GetName().AsCString(), 150360784Sdim m_persistent_variable_sp->m_flags); 151314564Sdim } 152309124Sdim 153314564Sdim if (m_persistent_variable_sp->m_flags & 154314564Sdim ExpressionVariable::EVNeedsAllocation) { 155314564Sdim MakeAllocation(map, err); 156314564Sdim m_persistent_variable_sp->m_flags |= 157314564Sdim ExpressionVariable::EVIsLLDBAllocated; 158309124Sdim 159314564Sdim if (!err.Success()) 160314564Sdim return; 161314564Sdim } 162309124Sdim 163314564Sdim if ((m_persistent_variable_sp->m_flags & 164314564Sdim ExpressionVariable::EVIsProgramReference && 165314564Sdim m_persistent_variable_sp->m_live_sp) || 166314564Sdim m_persistent_variable_sp->m_flags & 167314564Sdim ExpressionVariable::EVIsLLDBAllocated) { 168321369Sdim Status write_error; 169309124Sdim 170314564Sdim map.WriteScalarToMemory( 171314564Sdim load_addr, 172314564Sdim m_persistent_variable_sp->m_live_sp->GetValue().GetScalar(), 173314564Sdim map.GetAddressByteSize(), write_error); 174309124Sdim 175314564Sdim if (!write_error.Success()) { 176314564Sdim err.SetErrorStringWithFormat( 177314564Sdim "couldn't write the location of %s to memory: %s", 178314564Sdim m_persistent_variable_sp->GetName().AsCString(), 179314564Sdim write_error.AsCString()); 180314564Sdim } 181314564Sdim } else { 182314564Sdim err.SetErrorStringWithFormat( 183314564Sdim "no materialization happened for persistent variable %s", 184314564Sdim m_persistent_variable_sp->GetName().AsCString()); 185314564Sdim return; 186254721Semaste } 187314564Sdim } 188309124Sdim 189314564Sdim void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 190314564Sdim lldb::addr_t process_address, lldb::addr_t frame_top, 191321369Sdim lldb::addr_t frame_bottom, Status &err) override { 192314564Sdim Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); 193309124Sdim 194314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 195254721Semaste 196314564Sdim if (log) { 197360784Sdim LLDB_LOGF(log, 198360784Sdim "EntityPersistentVariable::Dematerialize [address = 0x%" PRIx64 199360784Sdim ", m_name = %s, m_flags = 0x%hx]", 200360784Sdim (uint64_t)process_address + m_offset, 201360784Sdim m_persistent_variable_sp->GetName().AsCString(), 202360784Sdim m_persistent_variable_sp->m_flags); 203314564Sdim } 204309124Sdim 205314564Sdim if (m_delegate) { 206314564Sdim m_delegate->DidDematerialize(m_persistent_variable_sp); 207314564Sdim } 208296417Sdim 209314564Sdim if ((m_persistent_variable_sp->m_flags & 210314564Sdim ExpressionVariable::EVIsLLDBAllocated) || 211314564Sdim (m_persistent_variable_sp->m_flags & 212314564Sdim ExpressionVariable::EVIsProgramReference)) { 213314564Sdim if (m_persistent_variable_sp->m_flags & 214314564Sdim ExpressionVariable::EVIsProgramReference && 215314564Sdim !m_persistent_variable_sp->m_live_sp) { 216314564Sdim // If the reference comes from the program, then the 217341825Sdim // ClangExpressionVariable's live variable data hasn't been set up yet. 218341825Sdim // Do this now. 219309124Sdim 220314564Sdim lldb::addr_t location; 221321369Sdim Status read_error; 222309124Sdim 223314564Sdim map.ReadPointerFromMemory(&location, load_addr, read_error); 224309124Sdim 225314564Sdim if (!read_error.Success()) { 226314564Sdim err.SetErrorStringWithFormat( 227314564Sdim "couldn't read the address of program-allocated variable %s: %s", 228314564Sdim m_persistent_variable_sp->GetName().GetCString(), 229314564Sdim read_error.AsCString()); 230314564Sdim return; 231314564Sdim } 232309124Sdim 233314564Sdim m_persistent_variable_sp->m_live_sp = ValueObjectConstResult::Create( 234314564Sdim map.GetBestExecutionContextScope(), 235314564Sdim m_persistent_variable_sp.get()->GetCompilerType(), 236314564Sdim m_persistent_variable_sp->GetName(), location, eAddressTypeLoad, 237314564Sdim m_persistent_variable_sp->GetByteSize()); 238309124Sdim 239314564Sdim if (frame_top != LLDB_INVALID_ADDRESS && 240314564Sdim frame_bottom != LLDB_INVALID_ADDRESS && location >= frame_bottom && 241314564Sdim location <= frame_top) { 242314564Sdim // If the variable is resident in the stack frame created by the 243341825Sdim // expression, then it cannot be relied upon to stay around. We 244341825Sdim // treat it as needing reallocation. 245314564Sdim m_persistent_variable_sp->m_flags |= 246314564Sdim ExpressionVariable::EVIsLLDBAllocated; 247314564Sdim m_persistent_variable_sp->m_flags |= 248314564Sdim ExpressionVariable::EVNeedsAllocation; 249314564Sdim m_persistent_variable_sp->m_flags |= 250314564Sdim ExpressionVariable::EVNeedsFreezeDry; 251314564Sdim m_persistent_variable_sp->m_flags &= 252314564Sdim ~ExpressionVariable::EVIsProgramReference; 253314564Sdim } 254314564Sdim } 255309124Sdim 256314564Sdim lldb::addr_t mem = m_persistent_variable_sp->m_live_sp->GetValue() 257314564Sdim .GetScalar() 258314564Sdim .ULongLong(); 259309124Sdim 260314564Sdim if (!m_persistent_variable_sp->m_live_sp) { 261314564Sdim err.SetErrorStringWithFormat( 262314564Sdim "couldn't find the memory area used to store %s", 263314564Sdim m_persistent_variable_sp->GetName().GetCString()); 264314564Sdim return; 265314564Sdim } 266309124Sdim 267314564Sdim if (m_persistent_variable_sp->m_live_sp->GetValue() 268314564Sdim .GetValueAddressType() != eAddressTypeLoad) { 269314564Sdim err.SetErrorStringWithFormat( 270314564Sdim "the address of the memory area for %s is in an incorrect format", 271314564Sdim m_persistent_variable_sp->GetName().GetCString()); 272314564Sdim return; 273314564Sdim } 274309124Sdim 275314564Sdim if (m_persistent_variable_sp->m_flags & 276314564Sdim ExpressionVariable::EVNeedsFreezeDry || 277314564Sdim m_persistent_variable_sp->m_flags & 278314564Sdim ExpressionVariable::EVKeepInTarget) { 279360784Sdim LLDB_LOGF(log, "Dematerializing %s from 0x%" PRIx64 " (size = %llu)", 280360784Sdim m_persistent_variable_sp->GetName().GetCString(), 281360784Sdim (uint64_t)mem, 282360784Sdim (unsigned long long)m_persistent_variable_sp->GetByteSize()); 283309124Sdim 284314564Sdim // Read the contents of the spare memory area 285309124Sdim 286314564Sdim m_persistent_variable_sp->ValueUpdated(); 287309124Sdim 288321369Sdim Status read_error; 289309124Sdim 290314564Sdim map.ReadMemory(m_persistent_variable_sp->GetValueBytes(), mem, 291314564Sdim m_persistent_variable_sp->GetByteSize(), read_error); 292309124Sdim 293314564Sdim if (!read_error.Success()) { 294314564Sdim err.SetErrorStringWithFormat( 295314564Sdim "couldn't read the contents of %s from memory: %s", 296314564Sdim m_persistent_variable_sp->GetName().GetCString(), 297314564Sdim read_error.AsCString()); 298314564Sdim return; 299254721Semaste } 300309124Sdim 301314564Sdim m_persistent_variable_sp->m_flags &= 302314564Sdim ~ExpressionVariable::EVNeedsFreezeDry; 303314564Sdim } 304314564Sdim } else { 305314564Sdim err.SetErrorStringWithFormat( 306314564Sdim "no dematerialization happened for persistent variable %s", 307314564Sdim m_persistent_variable_sp->GetName().AsCString()); 308314564Sdim return; 309314564Sdim } 310309124Sdim 311314564Sdim lldb::ProcessSP process_sp = 312314564Sdim map.GetBestExecutionContextScope()->CalculateProcess(); 313314564Sdim if (!process_sp || !process_sp->CanJIT()) { 314314564Sdim // Allocations are not persistent so persistent variables cannot stay 315314564Sdim // materialized. 316254721Semaste 317314564Sdim m_persistent_variable_sp->m_flags |= 318314564Sdim ExpressionVariable::EVNeedsAllocation; 319314564Sdim 320314564Sdim DestroyAllocation(map, err); 321314564Sdim if (!err.Success()) 322314564Sdim return; 323314564Sdim } else if (m_persistent_variable_sp->m_flags & 324314564Sdim ExpressionVariable::EVNeedsAllocation && 325314564Sdim !(m_persistent_variable_sp->m_flags & 326314564Sdim ExpressionVariable::EVKeepInTarget)) { 327314564Sdim DestroyAllocation(map, err); 328314564Sdim if (!err.Success()) 329314564Sdim return; 330254721Semaste } 331314564Sdim } 332309124Sdim 333314564Sdim void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address, 334314564Sdim Log *log) override { 335314564Sdim StreamString dump_stream; 336309124Sdim 337321369Sdim Status err; 338309124Sdim 339314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 340254721Semaste 341314564Sdim dump_stream.Printf("0x%" PRIx64 ": EntityPersistentVariable (%s)\n", 342314564Sdim load_addr, 343314564Sdim m_persistent_variable_sp->GetName().AsCString()); 344309124Sdim 345314564Sdim { 346314564Sdim dump_stream.Printf("Pointer:\n"); 347309124Sdim 348314564Sdim DataBufferHeap data(m_size, 0); 349309124Sdim 350314564Sdim map.ReadMemory(data.GetBytes(), load_addr, m_size, err); 351309124Sdim 352314564Sdim if (!err.Success()) { 353314564Sdim dump_stream.Printf(" <could not be read>\n"); 354314564Sdim } else { 355321369Sdim DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, 356321369Sdim load_addr); 357309124Sdim 358314564Sdim dump_stream.PutChar('\n'); 359314564Sdim } 360314564Sdim } 361309124Sdim 362314564Sdim { 363314564Sdim dump_stream.Printf("Target:\n"); 364309124Sdim 365314564Sdim lldb::addr_t target_address; 366309124Sdim 367314564Sdim map.ReadPointerFromMemory(&target_address, load_addr, err); 368309124Sdim 369314564Sdim if (!err.Success()) { 370314564Sdim dump_stream.Printf(" <could not be read>\n"); 371314564Sdim } else { 372314564Sdim DataBufferHeap data(m_persistent_variable_sp->GetByteSize(), 0); 373309124Sdim 374314564Sdim map.ReadMemory(data.GetBytes(), target_address, 375314564Sdim m_persistent_variable_sp->GetByteSize(), err); 376309124Sdim 377314564Sdim if (!err.Success()) { 378314564Sdim dump_stream.Printf(" <could not be read>\n"); 379314564Sdim } else { 380321369Sdim DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, 381321369Sdim target_address); 382309124Sdim 383314564Sdim dump_stream.PutChar('\n'); 384254721Semaste } 385314564Sdim } 386254721Semaste } 387309124Sdim 388314564Sdim log->PutString(dump_stream.GetString()); 389314564Sdim } 390296417Sdim 391314564Sdim void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {} 392314564Sdim 393254721Semasteprivate: 394314564Sdim lldb::ExpressionVariableSP m_persistent_variable_sp; 395314564Sdim Materializer::PersistentVariableDelegate *m_delegate; 396254721Semaste}; 397254721Semaste 398314564Sdimuint32_t Materializer::AddPersistentVariable( 399314564Sdim lldb::ExpressionVariableSP &persistent_variable_sp, 400321369Sdim PersistentVariableDelegate *delegate, Status &err) { 401314564Sdim EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP()); 402314564Sdim iter->reset(new EntityPersistentVariable(persistent_variable_sp, delegate)); 403314564Sdim uint32_t ret = AddStructMember(**iter); 404314564Sdim (*iter)->SetOffset(ret); 405314564Sdim return ret; 406254721Semaste} 407254721Semaste 408314564Sdimclass EntityVariable : public Materializer::Entity { 409254721Semastepublic: 410314564Sdim EntityVariable(lldb::VariableSP &variable_sp) 411314564Sdim : Entity(), m_variable_sp(variable_sp), m_is_reference(false), 412254721Semaste m_temporary_allocation(LLDB_INVALID_ADDRESS), 413314564Sdim m_temporary_allocation_size(0) { 414314564Sdim // Hard-coding to maximum size of a pointer since all variables are 415314564Sdim // materialized by reference 416314564Sdim m_size = 8; 417314564Sdim m_alignment = 8; 418314564Sdim m_is_reference = 419314564Sdim m_variable_sp->GetType()->GetForwardCompilerType().IsReferenceType(); 420314564Sdim } 421314564Sdim 422314564Sdim void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 423321369Sdim lldb::addr_t process_address, Status &err) override { 424314564Sdim Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); 425314564Sdim 426314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 427314564Sdim if (log) { 428360784Sdim LLDB_LOGF(log, 429360784Sdim "EntityVariable::Materialize [address = 0x%" PRIx64 430360784Sdim ", m_variable_sp = %s]", 431360784Sdim (uint64_t)load_addr, m_variable_sp->GetName().AsCString()); 432254721Semaste } 433309124Sdim 434314564Sdim ExecutionContextScope *scope = frame_sp.get(); 435309124Sdim 436314564Sdim if (!scope) 437314564Sdim scope = map.GetBestExecutionContextScope(); 438309124Sdim 439314564Sdim lldb::ValueObjectSP valobj_sp = 440314564Sdim ValueObjectVariable::Create(scope, m_variable_sp); 441309124Sdim 442314564Sdim if (!valobj_sp) { 443314564Sdim err.SetErrorStringWithFormat( 444314564Sdim "couldn't get a value object for variable %s", 445314564Sdim m_variable_sp->GetName().AsCString()); 446314564Sdim return; 447314564Sdim } 448309124Sdim 449321369Sdim Status valobj_error = valobj_sp->GetError(); 450309124Sdim 451314564Sdim if (valobj_error.Fail()) { 452314564Sdim err.SetErrorStringWithFormat("couldn't get the value of variable %s: %s", 453314564Sdim m_variable_sp->GetName().AsCString(), 454314564Sdim valobj_error.AsCString()); 455314564Sdim return; 456314564Sdim } 457309124Sdim 458314564Sdim if (m_is_reference) { 459314564Sdim DataExtractor valobj_extractor; 460321369Sdim Status extract_error; 461314564Sdim valobj_sp->GetData(valobj_extractor, extract_error); 462309124Sdim 463314564Sdim if (!extract_error.Success()) { 464314564Sdim err.SetErrorStringWithFormat( 465314564Sdim "couldn't read contents of reference variable %s: %s", 466314564Sdim m_variable_sp->GetName().AsCString(), extract_error.AsCString()); 467314564Sdim return; 468314564Sdim } 469309124Sdim 470314564Sdim lldb::offset_t offset = 0; 471314564Sdim lldb::addr_t reference_addr = valobj_extractor.GetAddress(&offset); 472309124Sdim 473321369Sdim Status write_error; 474314564Sdim map.WritePointerToMemory(load_addr, reference_addr, write_error); 475309124Sdim 476314564Sdim if (!write_error.Success()) { 477314564Sdim err.SetErrorStringWithFormat("couldn't write the contents of reference " 478314564Sdim "variable %s to memory: %s", 479314564Sdim m_variable_sp->GetName().AsCString(), 480314564Sdim write_error.AsCString()); 481314564Sdim return; 482314564Sdim } 483314564Sdim } else { 484314564Sdim AddressType address_type = eAddressTypeInvalid; 485314564Sdim const bool scalar_is_load_address = false; 486314564Sdim lldb::addr_t addr_of_valobj = 487314564Sdim valobj_sp->GetAddressOf(scalar_is_load_address, &address_type); 488314564Sdim if (addr_of_valobj != LLDB_INVALID_ADDRESS) { 489321369Sdim Status write_error; 490314564Sdim map.WritePointerToMemory(load_addr, addr_of_valobj, write_error); 491309124Sdim 492314564Sdim if (!write_error.Success()) { 493314564Sdim err.SetErrorStringWithFormat( 494314564Sdim "couldn't write the address of variable %s to memory: %s", 495314564Sdim m_variable_sp->GetName().AsCString(), write_error.AsCString()); 496314564Sdim return; 497314564Sdim } 498314564Sdim } else { 499314564Sdim DataExtractor data; 500321369Sdim Status extract_error; 501314564Sdim valobj_sp->GetData(data, extract_error); 502314564Sdim if (!extract_error.Success()) { 503314564Sdim err.SetErrorStringWithFormat("couldn't get the value of %s: %s", 504314564Sdim m_variable_sp->GetName().AsCString(), 505314564Sdim extract_error.AsCString()); 506314564Sdim return; 507314564Sdim } 508309124Sdim 509314564Sdim if (m_temporary_allocation != LLDB_INVALID_ADDRESS) { 510314564Sdim err.SetErrorStringWithFormat( 511314564Sdim "trying to create a temporary region for %s but one exists", 512314564Sdim m_variable_sp->GetName().AsCString()); 513314564Sdim return; 514254721Semaste } 515309124Sdim 516314564Sdim if (data.GetByteSize() < m_variable_sp->GetType()->GetByteSize()) { 517314564Sdim if (data.GetByteSize() == 0 && 518344779Sdim !m_variable_sp->LocationExpression().IsValid()) { 519314564Sdim err.SetErrorStringWithFormat("the variable '%s' has no location, " 520314564Sdim "it may have been optimized out", 521314564Sdim m_variable_sp->GetName().AsCString()); 522314564Sdim } else { 523314564Sdim err.SetErrorStringWithFormat( 524314564Sdim "size of variable %s (%" PRIu64 525314564Sdim ") is larger than the ValueObject's size (%" PRIu64 ")", 526314564Sdim m_variable_sp->GetName().AsCString(), 527353358Sdim m_variable_sp->GetType()->GetByteSize().getValueOr(0), 528353358Sdim data.GetByteSize()); 529314564Sdim } 530314564Sdim return; 531314564Sdim } 532309124Sdim 533360784Sdim llvm::Optional<size_t> opt_bit_align = 534360784Sdim m_variable_sp->GetType()->GetLayoutCompilerType().GetTypeBitAlign(scope); 535360784Sdim if (!opt_bit_align) { 536360784Sdim err.SetErrorStringWithFormat("can't get the type alignment for %s", 537360784Sdim m_variable_sp->GetName().AsCString()); 538360784Sdim return; 539360784Sdim } 540309124Sdim 541360784Sdim size_t byte_align = (*opt_bit_align + 7) / 8; 542309124Sdim 543321369Sdim Status alloc_error; 544314564Sdim const bool zero_memory = false; 545309124Sdim 546314564Sdim m_temporary_allocation = map.Malloc( 547314564Sdim data.GetByteSize(), byte_align, 548314564Sdim lldb::ePermissionsReadable | lldb::ePermissionsWritable, 549314564Sdim IRMemoryMap::eAllocationPolicyMirror, zero_memory, alloc_error); 550309124Sdim 551314564Sdim m_temporary_allocation_size = data.GetByteSize(); 552296417Sdim 553353358Sdim m_original_data = std::make_shared<DataBufferHeap>(data.GetDataStart(), 554353358Sdim data.GetByteSize()); 555309124Sdim 556314564Sdim if (!alloc_error.Success()) { 557314564Sdim err.SetErrorStringWithFormat( 558314564Sdim "couldn't allocate a temporary region for %s: %s", 559314564Sdim m_variable_sp->GetName().AsCString(), alloc_error.AsCString()); 560314564Sdim return; 561314564Sdim } 562309124Sdim 563321369Sdim Status write_error; 564309124Sdim 565314564Sdim map.WriteMemory(m_temporary_allocation, data.GetDataStart(), 566314564Sdim data.GetByteSize(), write_error); 567309124Sdim 568314564Sdim if (!write_error.Success()) { 569314564Sdim err.SetErrorStringWithFormat( 570314564Sdim "couldn't write to the temporary region for %s: %s", 571314564Sdim m_variable_sp->GetName().AsCString(), write_error.AsCString()); 572314564Sdim return; 573314564Sdim } 574309124Sdim 575321369Sdim Status pointer_write_error; 576309124Sdim 577314564Sdim map.WritePointerToMemory(load_addr, m_temporary_allocation, 578314564Sdim pointer_write_error); 579309124Sdim 580314564Sdim if (!pointer_write_error.Success()) { 581314564Sdim err.SetErrorStringWithFormat( 582314564Sdim "couldn't write the address of the temporary region for %s: %s", 583314564Sdim m_variable_sp->GetName().AsCString(), 584314564Sdim pointer_write_error.AsCString()); 585254721Semaste } 586314564Sdim } 587254721Semaste } 588314564Sdim } 589309124Sdim 590314564Sdim void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 591314564Sdim lldb::addr_t process_address, lldb::addr_t frame_top, 592321369Sdim lldb::addr_t frame_bottom, Status &err) override { 593314564Sdim Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); 594254721Semaste 595314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 596314564Sdim if (log) { 597360784Sdim LLDB_LOGF(log, 598360784Sdim "EntityVariable::Dematerialize [address = 0x%" PRIx64 599360784Sdim ", m_variable_sp = %s]", 600360784Sdim (uint64_t)load_addr, m_variable_sp->GetName().AsCString()); 601314564Sdim } 602309124Sdim 603314564Sdim if (m_temporary_allocation != LLDB_INVALID_ADDRESS) { 604314564Sdim ExecutionContextScope *scope = frame_sp.get(); 605309124Sdim 606314564Sdim if (!scope) 607314564Sdim scope = map.GetBestExecutionContextScope(); 608309124Sdim 609314564Sdim lldb::ValueObjectSP valobj_sp = 610314564Sdim ValueObjectVariable::Create(scope, m_variable_sp); 611309124Sdim 612314564Sdim if (!valobj_sp) { 613314564Sdim err.SetErrorStringWithFormat( 614314564Sdim "couldn't get a value object for variable %s", 615314564Sdim m_variable_sp->GetName().AsCString()); 616314564Sdim return; 617314564Sdim } 618309124Sdim 619314564Sdim lldb_private::DataExtractor data; 620309124Sdim 621321369Sdim Status extract_error; 622309124Sdim 623314564Sdim map.GetMemoryData(data, m_temporary_allocation, valobj_sp->GetByteSize(), 624314564Sdim extract_error); 625309124Sdim 626314564Sdim if (!extract_error.Success()) { 627314564Sdim err.SetErrorStringWithFormat("couldn't get the data for variable %s", 628314564Sdim m_variable_sp->GetName().AsCString()); 629314564Sdim return; 630314564Sdim } 631309124Sdim 632314564Sdim bool actually_write = true; 633309124Sdim 634314564Sdim if (m_original_data) { 635314564Sdim if ((data.GetByteSize() == m_original_data->GetByteSize()) && 636314564Sdim !memcmp(m_original_data->GetBytes(), data.GetDataStart(), 637314564Sdim data.GetByteSize())) { 638314564Sdim actually_write = false; 639314564Sdim } 640314564Sdim } 641309124Sdim 642321369Sdim Status set_error; 643309124Sdim 644314564Sdim if (actually_write) { 645314564Sdim valobj_sp->SetData(data, set_error); 646309124Sdim 647314564Sdim if (!set_error.Success()) { 648314564Sdim err.SetErrorStringWithFormat( 649314564Sdim "couldn't write the new contents of %s back into the variable", 650314564Sdim m_variable_sp->GetName().AsCString()); 651314564Sdim return; 652314564Sdim } 653314564Sdim } 654309124Sdim 655321369Sdim Status free_error; 656309124Sdim 657314564Sdim map.Free(m_temporary_allocation, free_error); 658309124Sdim 659314564Sdim if (!free_error.Success()) { 660314564Sdim err.SetErrorStringWithFormat( 661314564Sdim "couldn't free the temporary region for %s: %s", 662314564Sdim m_variable_sp->GetName().AsCString(), free_error.AsCString()); 663314564Sdim return; 664314564Sdim } 665309124Sdim 666314564Sdim m_original_data.reset(); 667314564Sdim m_temporary_allocation = LLDB_INVALID_ADDRESS; 668314564Sdim m_temporary_allocation_size = 0; 669254721Semaste } 670314564Sdim } 671309124Sdim 672314564Sdim void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address, 673314564Sdim Log *log) override { 674314564Sdim StreamString dump_stream; 675254721Semaste 676314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 677314564Sdim dump_stream.Printf("0x%" PRIx64 ": EntityVariable\n", load_addr); 678309124Sdim 679321369Sdim Status err; 680309124Sdim 681314564Sdim lldb::addr_t ptr = LLDB_INVALID_ADDRESS; 682309124Sdim 683314564Sdim { 684314564Sdim dump_stream.Printf("Pointer:\n"); 685309124Sdim 686314564Sdim DataBufferHeap data(m_size, 0); 687309124Sdim 688314564Sdim map.ReadMemory(data.GetBytes(), load_addr, m_size, err); 689309124Sdim 690314564Sdim if (!err.Success()) { 691314564Sdim dump_stream.Printf(" <could not be read>\n"); 692314564Sdim } else { 693314564Sdim DataExtractor extractor(data.GetBytes(), data.GetByteSize(), 694314564Sdim map.GetByteOrder(), map.GetAddressByteSize()); 695309124Sdim 696321369Sdim DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, 697321369Sdim load_addr); 698309124Sdim 699314564Sdim lldb::offset_t offset; 700309124Sdim 701314564Sdim ptr = extractor.GetPointer(&offset); 702309124Sdim 703314564Sdim dump_stream.PutChar('\n'); 704314564Sdim } 705314564Sdim } 706309124Sdim 707314564Sdim if (m_temporary_allocation == LLDB_INVALID_ADDRESS) { 708314564Sdim dump_stream.Printf("Points to process memory:\n"); 709314564Sdim } else { 710314564Sdim dump_stream.Printf("Temporary allocation:\n"); 711314564Sdim } 712309124Sdim 713314564Sdim if (ptr == LLDB_INVALID_ADDRESS) { 714314564Sdim dump_stream.Printf(" <could not be be found>\n"); 715314564Sdim } else { 716314564Sdim DataBufferHeap data(m_temporary_allocation_size, 0); 717309124Sdim 718314564Sdim map.ReadMemory(data.GetBytes(), m_temporary_allocation, 719314564Sdim m_temporary_allocation_size, err); 720309124Sdim 721314564Sdim if (!err.Success()) { 722314564Sdim dump_stream.Printf(" <could not be read>\n"); 723314564Sdim } else { 724321369Sdim DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, 725321369Sdim load_addr); 726309124Sdim 727314564Sdim dump_stream.PutChar('\n'); 728314564Sdim } 729254721Semaste } 730309124Sdim 731314564Sdim log->PutString(dump_stream.GetString()); 732314564Sdim } 733309124Sdim 734314564Sdim void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override { 735314564Sdim if (m_temporary_allocation != LLDB_INVALID_ADDRESS) { 736321369Sdim Status free_error; 737309124Sdim 738314564Sdim map.Free(m_temporary_allocation, free_error); 739254721Semaste 740314564Sdim m_temporary_allocation = LLDB_INVALID_ADDRESS; 741314564Sdim m_temporary_allocation_size = 0; 742254721Semaste } 743314564Sdim } 744296417Sdim 745254721Semasteprivate: 746314564Sdim lldb::VariableSP m_variable_sp; 747314564Sdim bool m_is_reference; 748314564Sdim lldb::addr_t m_temporary_allocation; 749314564Sdim size_t m_temporary_allocation_size; 750314564Sdim lldb::DataBufferSP m_original_data; 751254721Semaste}; 752254721Semaste 753321369Sdimuint32_t Materializer::AddVariable(lldb::VariableSP &variable_sp, Status &err) { 754314564Sdim EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP()); 755314564Sdim iter->reset(new EntityVariable(variable_sp)); 756314564Sdim uint32_t ret = AddStructMember(**iter); 757314564Sdim (*iter)->SetOffset(ret); 758314564Sdim return ret; 759254721Semaste} 760254721Semaste 761314564Sdimclass EntityResultVariable : public Materializer::Entity { 762254721Semastepublic: 763314564Sdim EntityResultVariable(const CompilerType &type, bool is_program_reference, 764314564Sdim bool keep_in_memory, 765314564Sdim Materializer::PersistentVariableDelegate *delegate) 766314564Sdim : Entity(), m_type(type), m_is_program_reference(is_program_reference), 767254721Semaste m_keep_in_memory(keep_in_memory), 768254721Semaste m_temporary_allocation(LLDB_INVALID_ADDRESS), 769314564Sdim m_temporary_allocation_size(0), m_delegate(delegate) { 770314564Sdim // Hard-coding to maximum size of a pointer since all results are 771314564Sdim // materialized by reference 772314564Sdim m_size = 8; 773314564Sdim m_alignment = 8; 774314564Sdim } 775309124Sdim 776314564Sdim void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 777321369Sdim lldb::addr_t process_address, Status &err) override { 778314564Sdim if (!m_is_program_reference) { 779314564Sdim if (m_temporary_allocation != LLDB_INVALID_ADDRESS) { 780314564Sdim err.SetErrorString("Trying to create a temporary region for the result " 781314564Sdim "but one exists"); 782314564Sdim return; 783314564Sdim } 784309124Sdim 785314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 786254721Semaste 787314564Sdim ExecutionContextScope *exe_scope = map.GetBestExecutionContextScope(); 788309124Sdim 789344779Sdim llvm::Optional<uint64_t> byte_size = m_type.GetByteSize(exe_scope); 790344779Sdim if (!byte_size) { 791344779Sdim err.SetErrorString("can't get size of type"); 792344779Sdim return; 793344779Sdim } 794309124Sdim 795360784Sdim llvm::Optional<size_t> opt_bit_align = m_type.GetTypeBitAlign(exe_scope); 796360784Sdim if (!opt_bit_align) { 797360784Sdim err.SetErrorStringWithFormat("can't get the type alignment"); 798360784Sdim return; 799360784Sdim } 800296417Sdim 801360784Sdim size_t byte_align = (*opt_bit_align + 7) / 8; 802360784Sdim 803321369Sdim Status alloc_error; 804314564Sdim const bool zero_memory = true; 805309124Sdim 806314564Sdim m_temporary_allocation = map.Malloc( 807344779Sdim *byte_size, byte_align, 808314564Sdim lldb::ePermissionsReadable | lldb::ePermissionsWritable, 809314564Sdim IRMemoryMap::eAllocationPolicyMirror, zero_memory, alloc_error); 810344779Sdim m_temporary_allocation_size = *byte_size; 811309124Sdim 812314564Sdim if (!alloc_error.Success()) { 813314564Sdim err.SetErrorStringWithFormat( 814314564Sdim "couldn't allocate a temporary region for the result: %s", 815314564Sdim alloc_error.AsCString()); 816314564Sdim return; 817314564Sdim } 818309124Sdim 819321369Sdim Status pointer_write_error; 820309124Sdim 821314564Sdim map.WritePointerToMemory(load_addr, m_temporary_allocation, 822314564Sdim pointer_write_error); 823314564Sdim 824314564Sdim if (!pointer_write_error.Success()) { 825314564Sdim err.SetErrorStringWithFormat("couldn't write the address of the " 826314564Sdim "temporary region for the result: %s", 827314564Sdim pointer_write_error.AsCString()); 828314564Sdim } 829254721Semaste } 830314564Sdim } 831309124Sdim 832314564Sdim void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 833314564Sdim lldb::addr_t process_address, lldb::addr_t frame_top, 834321369Sdim lldb::addr_t frame_bottom, Status &err) override { 835314564Sdim err.Clear(); 836309124Sdim 837314564Sdim ExecutionContextScope *exe_scope = map.GetBestExecutionContextScope(); 838309124Sdim 839314564Sdim if (!exe_scope) { 840314564Sdim err.SetErrorString("Couldn't dematerialize a result variable: invalid " 841314564Sdim "execution context scope"); 842314564Sdim return; 843314564Sdim } 844309124Sdim 845314564Sdim lldb::addr_t address; 846321369Sdim Status read_error; 847314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 848309124Sdim 849314564Sdim map.ReadPointerFromMemory(&address, load_addr, read_error); 850309124Sdim 851314564Sdim if (!read_error.Success()) { 852314564Sdim err.SetErrorString("Couldn't dematerialize a result variable: couldn't " 853314564Sdim "read its address"); 854314564Sdim return; 855314564Sdim } 856309124Sdim 857314564Sdim lldb::TargetSP target_sp = exe_scope->CalculateTarget(); 858309124Sdim 859314564Sdim if (!target_sp) { 860314564Sdim err.SetErrorString("Couldn't dematerialize a result variable: no target"); 861314564Sdim return; 862314564Sdim } 863309124Sdim 864360784Sdim auto type_system_or_err = 865360784Sdim target_sp->GetScratchTypeSystemForLanguage(m_type.GetMinimumLanguage()); 866309124Sdim 867360784Sdim if (auto error = type_system_or_err.takeError()) { 868314564Sdim err.SetErrorStringWithFormat("Couldn't dematerialize a result variable: " 869314564Sdim "couldn't get the corresponding type " 870314564Sdim "system: %s", 871360784Sdim llvm::toString(std::move(error)).c_str()); 872314564Sdim return; 873314564Sdim } 874314564Sdim PersistentExpressionState *persistent_state = 875360784Sdim type_system_or_err->GetPersistentExpressionState(); 876309124Sdim 877314564Sdim if (!persistent_state) { 878314564Sdim err.SetErrorString("Couldn't dematerialize a result variable: " 879314564Sdim "corresponding type system doesn't handle persistent " 880314564Sdim "variables"); 881314564Sdim return; 882314564Sdim } 883309124Sdim 884341825Sdim ConstString name = 885341825Sdim m_delegate 886341825Sdim ? m_delegate->GetName() 887341825Sdim : persistent_state->GetNextPersistentVariableName( 888341825Sdim *target_sp, persistent_state->GetPersistentVariablePrefix()); 889309124Sdim 890314564Sdim lldb::ExpressionVariableSP ret = persistent_state->CreatePersistentVariable( 891314564Sdim exe_scope, name, m_type, map.GetByteOrder(), map.GetAddressByteSize()); 892309124Sdim 893314564Sdim if (!ret) { 894314564Sdim err.SetErrorStringWithFormat("couldn't dematerialize a result variable: " 895314564Sdim "failed to make persistent variable %s", 896314564Sdim name.AsCString()); 897314564Sdim return; 898314564Sdim } 899309124Sdim 900314564Sdim lldb::ProcessSP process_sp = 901314564Sdim map.GetBestExecutionContextScope()->CalculateProcess(); 902309124Sdim 903314564Sdim if (m_delegate) { 904314564Sdim m_delegate->DidDematerialize(ret); 905314564Sdim } 906309124Sdim 907314564Sdim bool can_persist = 908314564Sdim (m_is_program_reference && process_sp && process_sp->CanJIT() && 909314564Sdim !(address >= frame_bottom && address < frame_top)); 910254721Semaste 911314564Sdim if (can_persist && m_keep_in_memory) { 912314564Sdim ret->m_live_sp = ValueObjectConstResult::Create(exe_scope, m_type, name, 913314564Sdim address, eAddressTypeLoad, 914314564Sdim map.GetAddressByteSize()); 915314564Sdim } 916309124Sdim 917314564Sdim ret->ValueUpdated(); 918309124Sdim 919314564Sdim const size_t pvar_byte_size = ret->GetByteSize(); 920314564Sdim uint8_t *pvar_data = ret->GetValueBytes(); 921309124Sdim 922314564Sdim map.ReadMemory(pvar_data, address, pvar_byte_size, read_error); 923309124Sdim 924314564Sdim if (!read_error.Success()) { 925314564Sdim err.SetErrorString( 926314564Sdim "Couldn't dematerialize a result variable: couldn't read its memory"); 927314564Sdim return; 928314564Sdim } 929309124Sdim 930314564Sdim if (!can_persist || !m_keep_in_memory) { 931314564Sdim ret->m_flags |= ExpressionVariable::EVNeedsAllocation; 932309124Sdim 933314564Sdim if (m_temporary_allocation != LLDB_INVALID_ADDRESS) { 934321369Sdim Status free_error; 935314564Sdim map.Free(m_temporary_allocation, free_error); 936314564Sdim } 937314564Sdim } else { 938314564Sdim ret->m_flags |= ExpressionVariable::EVIsLLDBAllocated; 939254721Semaste } 940309124Sdim 941314564Sdim m_temporary_allocation = LLDB_INVALID_ADDRESS; 942314564Sdim m_temporary_allocation_size = 0; 943314564Sdim } 944309124Sdim 945314564Sdim void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address, 946314564Sdim Log *log) override { 947314564Sdim StreamString dump_stream; 948254721Semaste 949314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 950309124Sdim 951314564Sdim dump_stream.Printf("0x%" PRIx64 ": EntityResultVariable\n", load_addr); 952309124Sdim 953321369Sdim Status err; 954309124Sdim 955314564Sdim lldb::addr_t ptr = LLDB_INVALID_ADDRESS; 956309124Sdim 957314564Sdim { 958314564Sdim dump_stream.Printf("Pointer:\n"); 959309124Sdim 960314564Sdim DataBufferHeap data(m_size, 0); 961309124Sdim 962314564Sdim map.ReadMemory(data.GetBytes(), load_addr, m_size, err); 963309124Sdim 964314564Sdim if (!err.Success()) { 965314564Sdim dump_stream.Printf(" <could not be read>\n"); 966314564Sdim } else { 967314564Sdim DataExtractor extractor(data.GetBytes(), data.GetByteSize(), 968314564Sdim map.GetByteOrder(), map.GetAddressByteSize()); 969309124Sdim 970321369Sdim DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, 971321369Sdim load_addr); 972309124Sdim 973314564Sdim lldb::offset_t offset; 974309124Sdim 975314564Sdim ptr = extractor.GetPointer(&offset); 976309124Sdim 977314564Sdim dump_stream.PutChar('\n'); 978314564Sdim } 979314564Sdim } 980309124Sdim 981314564Sdim if (m_temporary_allocation == LLDB_INVALID_ADDRESS) { 982314564Sdim dump_stream.Printf("Points to process memory:\n"); 983314564Sdim } else { 984314564Sdim dump_stream.Printf("Temporary allocation:\n"); 985314564Sdim } 986309124Sdim 987314564Sdim if (ptr == LLDB_INVALID_ADDRESS) { 988314564Sdim dump_stream.Printf(" <could not be be found>\n"); 989314564Sdim } else { 990314564Sdim DataBufferHeap data(m_temporary_allocation_size, 0); 991309124Sdim 992314564Sdim map.ReadMemory(data.GetBytes(), m_temporary_allocation, 993314564Sdim m_temporary_allocation_size, err); 994309124Sdim 995314564Sdim if (!err.Success()) { 996314564Sdim dump_stream.Printf(" <could not be read>\n"); 997314564Sdim } else { 998321369Sdim DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, 999321369Sdim load_addr); 1000309124Sdim 1001314564Sdim dump_stream.PutChar('\n'); 1002314564Sdim } 1003254721Semaste } 1004309124Sdim 1005314564Sdim log->PutString(dump_stream.GetString()); 1006314564Sdim } 1007309124Sdim 1008314564Sdim void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override { 1009314564Sdim if (!m_keep_in_memory && m_temporary_allocation != LLDB_INVALID_ADDRESS) { 1010321369Sdim Status free_error; 1011309124Sdim 1012314564Sdim map.Free(m_temporary_allocation, free_error); 1013254721Semaste } 1014296417Sdim 1015314564Sdim m_temporary_allocation = LLDB_INVALID_ADDRESS; 1016314564Sdim m_temporary_allocation_size = 0; 1017314564Sdim } 1018314564Sdim 1019254721Semasteprivate: 1020314564Sdim CompilerType m_type; 1021314564Sdim bool m_is_program_reference; 1022314564Sdim bool m_keep_in_memory; 1023309124Sdim 1024314564Sdim lldb::addr_t m_temporary_allocation; 1025314564Sdim size_t m_temporary_allocation_size; 1026314564Sdim Materializer::PersistentVariableDelegate *m_delegate; 1027254721Semaste}; 1028254721Semaste 1029314564Sdimuint32_t Materializer::AddResultVariable(const CompilerType &type, 1030314564Sdim bool is_program_reference, 1031314564Sdim bool keep_in_memory, 1032314564Sdim PersistentVariableDelegate *delegate, 1033321369Sdim Status &err) { 1034314564Sdim EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP()); 1035314564Sdim iter->reset(new EntityResultVariable(type, is_program_reference, 1036314564Sdim keep_in_memory, delegate)); 1037314564Sdim uint32_t ret = AddStructMember(**iter); 1038314564Sdim (*iter)->SetOffset(ret); 1039314564Sdim return ret; 1040254721Semaste} 1041254721Semaste 1042314564Sdimclass EntitySymbol : public Materializer::Entity { 1043254721Semastepublic: 1044314564Sdim EntitySymbol(const Symbol &symbol) : Entity(), m_symbol(symbol) { 1045314564Sdim // Hard-coding to maximum size of a symbol 1046314564Sdim m_size = 8; 1047314564Sdim m_alignment = 8; 1048314564Sdim } 1049309124Sdim 1050314564Sdim void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 1051321369Sdim lldb::addr_t process_address, Status &err) override { 1052314564Sdim Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); 1053254721Semaste 1054314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 1055254721Semaste 1056314564Sdim if (log) { 1057360784Sdim LLDB_LOGF(log, 1058360784Sdim "EntitySymbol::Materialize [address = 0x%" PRIx64 1059360784Sdim ", m_symbol = %s]", 1060360784Sdim (uint64_t)load_addr, m_symbol.GetName().AsCString()); 1061314564Sdim } 1062309124Sdim 1063314564Sdim const Address sym_address = m_symbol.GetAddress(); 1064254721Semaste 1065314564Sdim ExecutionContextScope *exe_scope = map.GetBestExecutionContextScope(); 1066309124Sdim 1067314564Sdim lldb::TargetSP target_sp; 1068309124Sdim 1069314564Sdim if (exe_scope) 1070314564Sdim target_sp = map.GetBestExecutionContextScope()->CalculateTarget(); 1071309124Sdim 1072314564Sdim if (!target_sp) { 1073314564Sdim err.SetErrorStringWithFormat( 1074314564Sdim "couldn't resolve symbol %s because there is no target", 1075314564Sdim m_symbol.GetName().AsCString()); 1076314564Sdim return; 1077314564Sdim } 1078309124Sdim 1079314564Sdim lldb::addr_t resolved_address = sym_address.GetLoadAddress(target_sp.get()); 1080309124Sdim 1081314564Sdim if (resolved_address == LLDB_INVALID_ADDRESS) 1082314564Sdim resolved_address = sym_address.GetFileAddress(); 1083309124Sdim 1084321369Sdim Status pointer_write_error; 1085309124Sdim 1086314564Sdim map.WritePointerToMemory(load_addr, resolved_address, pointer_write_error); 1087309124Sdim 1088314564Sdim if (!pointer_write_error.Success()) { 1089314564Sdim err.SetErrorStringWithFormat( 1090314564Sdim "couldn't write the address of symbol %s: %s", 1091314564Sdim m_symbol.GetName().AsCString(), pointer_write_error.AsCString()); 1092314564Sdim return; 1093254721Semaste } 1094314564Sdim } 1095309124Sdim 1096314564Sdim void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 1097314564Sdim lldb::addr_t process_address, lldb::addr_t frame_top, 1098321369Sdim lldb::addr_t frame_bottom, Status &err) override { 1099314564Sdim Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); 1100254721Semaste 1101314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 1102254721Semaste 1103314564Sdim if (log) { 1104360784Sdim LLDB_LOGF(log, 1105360784Sdim "EntitySymbol::Dematerialize [address = 0x%" PRIx64 1106360784Sdim ", m_symbol = %s]", 1107360784Sdim (uint64_t)load_addr, m_symbol.GetName().AsCString()); 1108254721Semaste } 1109309124Sdim 1110314564Sdim // no work needs to be done 1111314564Sdim } 1112309124Sdim 1113314564Sdim void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address, 1114314564Sdim Log *log) override { 1115314564Sdim StreamString dump_stream; 1116309124Sdim 1117321369Sdim Status err; 1118254721Semaste 1119314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 1120309124Sdim 1121314564Sdim dump_stream.Printf("0x%" PRIx64 ": EntitySymbol (%s)\n", load_addr, 1122314564Sdim m_symbol.GetName().AsCString()); 1123309124Sdim 1124314564Sdim { 1125314564Sdim dump_stream.Printf("Pointer:\n"); 1126309124Sdim 1127314564Sdim DataBufferHeap data(m_size, 0); 1128309124Sdim 1129314564Sdim map.ReadMemory(data.GetBytes(), load_addr, m_size, err); 1130309124Sdim 1131314564Sdim if (!err.Success()) { 1132314564Sdim dump_stream.Printf(" <could not be read>\n"); 1133314564Sdim } else { 1134321369Sdim DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, 1135321369Sdim load_addr); 1136309124Sdim 1137314564Sdim dump_stream.PutChar('\n'); 1138314564Sdim } 1139254721Semaste } 1140309124Sdim 1141314564Sdim log->PutString(dump_stream.GetString()); 1142314564Sdim } 1143296417Sdim 1144314564Sdim void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {} 1145314564Sdim 1146254721Semasteprivate: 1147314564Sdim Symbol m_symbol; 1148254721Semaste}; 1149254721Semaste 1150321369Sdimuint32_t Materializer::AddSymbol(const Symbol &symbol_sp, Status &err) { 1151314564Sdim EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP()); 1152314564Sdim iter->reset(new EntitySymbol(symbol_sp)); 1153314564Sdim uint32_t ret = AddStructMember(**iter); 1154314564Sdim (*iter)->SetOffset(ret); 1155314564Sdim return ret; 1156254721Semaste} 1157254721Semaste 1158314564Sdimclass EntityRegister : public Materializer::Entity { 1159254721Semastepublic: 1160314564Sdim EntityRegister(const RegisterInfo ®ister_info) 1161314564Sdim : Entity(), m_register_info(register_info) { 1162314564Sdim // Hard-coding alignment conservatively 1163314564Sdim m_size = m_register_info.byte_size; 1164314564Sdim m_alignment = m_register_info.byte_size; 1165314564Sdim } 1166314564Sdim 1167314564Sdim void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 1168321369Sdim lldb::addr_t process_address, Status &err) override { 1169314564Sdim Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); 1170314564Sdim 1171314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 1172314564Sdim 1173314564Sdim if (log) { 1174360784Sdim LLDB_LOGF(log, 1175360784Sdim "EntityRegister::Materialize [address = 0x%" PRIx64 1176360784Sdim ", m_register_info = %s]", 1177360784Sdim (uint64_t)load_addr, m_register_info.name); 1178254721Semaste } 1179309124Sdim 1180314564Sdim RegisterValue reg_value; 1181309124Sdim 1182314564Sdim if (!frame_sp.get()) { 1183314564Sdim err.SetErrorStringWithFormat( 1184314564Sdim "couldn't materialize register %s without a stack frame", 1185314564Sdim m_register_info.name); 1186314564Sdim return; 1187314564Sdim } 1188254721Semaste 1189314564Sdim lldb::RegisterContextSP reg_context_sp = frame_sp->GetRegisterContext(); 1190254721Semaste 1191314564Sdim if (!reg_context_sp->ReadRegister(&m_register_info, reg_value)) { 1192314564Sdim err.SetErrorStringWithFormat("couldn't read the value of register %s", 1193314564Sdim m_register_info.name); 1194314564Sdim return; 1195314564Sdim } 1196309124Sdim 1197314564Sdim DataExtractor register_data; 1198309124Sdim 1199314564Sdim if (!reg_value.GetData(register_data)) { 1200314564Sdim err.SetErrorStringWithFormat("couldn't get the data for register %s", 1201314564Sdim m_register_info.name); 1202314564Sdim return; 1203314564Sdim } 1204309124Sdim 1205314564Sdim if (register_data.GetByteSize() != m_register_info.byte_size) { 1206314564Sdim err.SetErrorStringWithFormat( 1207314564Sdim "data for register %s had size %llu but we expected %llu", 1208314564Sdim m_register_info.name, (unsigned long long)register_data.GetByteSize(), 1209314564Sdim (unsigned long long)m_register_info.byte_size); 1210314564Sdim return; 1211314564Sdim } 1212309124Sdim 1213353358Sdim m_register_contents = std::make_shared<DataBufferHeap>( 1214353358Sdim register_data.GetDataStart(), register_data.GetByteSize()); 1215309124Sdim 1216321369Sdim Status write_error; 1217309124Sdim 1218314564Sdim map.WriteMemory(load_addr, register_data.GetDataStart(), 1219314564Sdim register_data.GetByteSize(), write_error); 1220309124Sdim 1221314564Sdim if (!write_error.Success()) { 1222314564Sdim err.SetErrorStringWithFormat( 1223314564Sdim "couldn't write the contents of register %s: %s", 1224314564Sdim m_register_info.name, write_error.AsCString()); 1225314564Sdim return; 1226254721Semaste } 1227314564Sdim } 1228309124Sdim 1229314564Sdim void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 1230314564Sdim lldb::addr_t process_address, lldb::addr_t frame_top, 1231321369Sdim lldb::addr_t frame_bottom, Status &err) override { 1232314564Sdim Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); 1233309124Sdim 1234314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 1235254721Semaste 1236314564Sdim if (log) { 1237360784Sdim LLDB_LOGF(log, 1238360784Sdim "EntityRegister::Dematerialize [address = 0x%" PRIx64 1239360784Sdim ", m_register_info = %s]", 1240360784Sdim (uint64_t)load_addr, m_register_info.name); 1241314564Sdim } 1242309124Sdim 1243321369Sdim Status extract_error; 1244309124Sdim 1245314564Sdim DataExtractor register_data; 1246309124Sdim 1247314564Sdim if (!frame_sp.get()) { 1248314564Sdim err.SetErrorStringWithFormat( 1249314564Sdim "couldn't dematerialize register %s without a stack frame", 1250314564Sdim m_register_info.name); 1251314564Sdim return; 1252314564Sdim } 1253309124Sdim 1254314564Sdim lldb::RegisterContextSP reg_context_sp = frame_sp->GetRegisterContext(); 1255309124Sdim 1256314564Sdim map.GetMemoryData(register_data, load_addr, m_register_info.byte_size, 1257314564Sdim extract_error); 1258309124Sdim 1259314564Sdim if (!extract_error.Success()) { 1260314564Sdim err.SetErrorStringWithFormat("couldn't get the data for register %s: %s", 1261314564Sdim m_register_info.name, 1262314564Sdim extract_error.AsCString()); 1263314564Sdim return; 1264314564Sdim } 1265309124Sdim 1266314564Sdim if (!memcmp(register_data.GetDataStart(), m_register_contents->GetBytes(), 1267314564Sdim register_data.GetByteSize())) { 1268314564Sdim // No write required, and in particular we avoid errors if the register 1269314564Sdim // wasn't writable 1270309124Sdim 1271314564Sdim m_register_contents.reset(); 1272314564Sdim return; 1273314564Sdim } 1274309124Sdim 1275314564Sdim m_register_contents.reset(); 1276309124Sdim 1277314564Sdim RegisterValue register_value( 1278314564Sdim const_cast<uint8_t *>(register_data.GetDataStart()), 1279314564Sdim register_data.GetByteSize(), register_data.GetByteOrder()); 1280309124Sdim 1281314564Sdim if (!reg_context_sp->WriteRegister(&m_register_info, register_value)) { 1282314564Sdim err.SetErrorStringWithFormat("couldn't write the value of register %s", 1283314564Sdim m_register_info.name); 1284314564Sdim return; 1285254721Semaste } 1286314564Sdim } 1287309124Sdim 1288314564Sdim void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address, 1289314564Sdim Log *log) override { 1290314564Sdim StreamString dump_stream; 1291309124Sdim 1292321369Sdim Status err; 1293309124Sdim 1294314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 1295254721Semaste 1296314564Sdim dump_stream.Printf("0x%" PRIx64 ": EntityRegister (%s)\n", load_addr, 1297314564Sdim m_register_info.name); 1298309124Sdim 1299314564Sdim { 1300314564Sdim dump_stream.Printf("Value:\n"); 1301309124Sdim 1302314564Sdim DataBufferHeap data(m_size, 0); 1303309124Sdim 1304314564Sdim map.ReadMemory(data.GetBytes(), load_addr, m_size, err); 1305309124Sdim 1306314564Sdim if (!err.Success()) { 1307314564Sdim dump_stream.Printf(" <could not be read>\n"); 1308314564Sdim } else { 1309321369Sdim DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, 1310321369Sdim load_addr); 1311309124Sdim 1312314564Sdim dump_stream.PutChar('\n'); 1313314564Sdim } 1314314564Sdim } 1315309124Sdim 1316314564Sdim log->PutString(dump_stream.GetString()); 1317314564Sdim } 1318309124Sdim 1319314564Sdim void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {} 1320309124Sdim 1321254721Semasteprivate: 1322314564Sdim RegisterInfo m_register_info; 1323314564Sdim lldb::DataBufferSP m_register_contents; 1324254721Semaste}; 1325254721Semaste 1326314564Sdimuint32_t Materializer::AddRegister(const RegisterInfo ®ister_info, 1327321369Sdim Status &err) { 1328314564Sdim EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP()); 1329314564Sdim iter->reset(new EntityRegister(register_info)); 1330314564Sdim uint32_t ret = AddStructMember(**iter); 1331314564Sdim (*iter)->SetOffset(ret); 1332314564Sdim return ret; 1333254721Semaste} 1334254721Semaste 1335314564SdimMaterializer::Materializer() 1336314564Sdim : m_dematerializer_wp(), m_current_offset(0), m_struct_alignment(8) {} 1337254721Semaste 1338314564SdimMaterializer::~Materializer() { 1339314564Sdim DematerializerSP dematerializer_sp = m_dematerializer_wp.lock(); 1340309124Sdim 1341314564Sdim if (dematerializer_sp) 1342314564Sdim dematerializer_sp->Wipe(); 1343254721Semaste} 1344254721Semaste 1345254721SemasteMaterializer::DematerializerSP 1346314564SdimMaterializer::Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 1347321369Sdim lldb::addr_t process_address, Status &error) { 1348314564Sdim ExecutionContextScope *exe_scope = frame_sp.get(); 1349276479Sdim 1350314564Sdim if (!exe_scope) 1351314564Sdim exe_scope = map.GetBestExecutionContextScope(); 1352276479Sdim 1353314564Sdim DematerializerSP dematerializer_sp = m_dematerializer_wp.lock(); 1354276479Sdim 1355314564Sdim if (dematerializer_sp) { 1356314564Sdim error.SetErrorToGenericError(); 1357314564Sdim error.SetErrorString("Couldn't materialize: already materialized"); 1358314564Sdim } 1359276479Sdim 1360314564Sdim DematerializerSP ret( 1361314564Sdim new Dematerializer(*this, frame_sp, map, process_address)); 1362276479Sdim 1363314564Sdim if (!exe_scope) { 1364314564Sdim error.SetErrorToGenericError(); 1365314564Sdim error.SetErrorString("Couldn't materialize: target doesn't exist"); 1366314564Sdim } 1367276479Sdim 1368314564Sdim for (EntityUP &entity_up : m_entities) { 1369314564Sdim entity_up->Materialize(frame_sp, map, process_address, error); 1370276479Sdim 1371314564Sdim if (!error.Success()) 1372314564Sdim return DematerializerSP(); 1373314564Sdim } 1374276479Sdim 1375314564Sdim if (Log *log = 1376314564Sdim lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)) { 1377360784Sdim LLDB_LOGF( 1378360784Sdim log, 1379314564Sdim "Materializer::Materialize (frame_sp = %p, process_address = 0x%" PRIx64 1380314564Sdim ") materialized:", 1381314564Sdim static_cast<void *>(frame_sp.get()), process_address); 1382314564Sdim for (EntityUP &entity_up : m_entities) 1383314564Sdim entity_up->DumpToLog(map, process_address, log); 1384314564Sdim } 1385276479Sdim 1386314564Sdim m_dematerializer_wp = ret; 1387276479Sdim 1388314564Sdim return ret; 1389254721Semaste} 1390254721Semaste 1391321369Sdimvoid Materializer::Dematerializer::Dematerialize(Status &error, 1392314564Sdim lldb::addr_t frame_bottom, 1393314564Sdim lldb::addr_t frame_top) { 1394314564Sdim lldb::StackFrameSP frame_sp; 1395254721Semaste 1396314564Sdim lldb::ThreadSP thread_sp = m_thread_wp.lock(); 1397314564Sdim if (thread_sp) 1398314564Sdim frame_sp = thread_sp->GetFrameWithStackID(m_stack_id); 1399276479Sdim 1400314564Sdim ExecutionContextScope *exe_scope = m_map->GetBestExecutionContextScope(); 1401276479Sdim 1402314564Sdim if (!IsValid()) { 1403314564Sdim error.SetErrorToGenericError(); 1404314564Sdim error.SetErrorString("Couldn't dematerialize: invalid dematerializer"); 1405314564Sdim } 1406276479Sdim 1407314564Sdim if (!exe_scope) { 1408314564Sdim error.SetErrorToGenericError(); 1409314564Sdim error.SetErrorString("Couldn't dematerialize: target is gone"); 1410314564Sdim } else { 1411314564Sdim if (Log *log = 1412314564Sdim lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)) { 1413360784Sdim LLDB_LOGF(log, 1414360784Sdim "Materializer::Dematerialize (frame_sp = %p, process_address " 1415360784Sdim "= 0x%" PRIx64 ") about to dematerialize:", 1416360784Sdim static_cast<void *>(frame_sp.get()), m_process_address); 1417314564Sdim for (EntityUP &entity_up : m_materializer->m_entities) 1418314564Sdim entity_up->DumpToLog(*m_map, m_process_address, log); 1419254721Semaste } 1420276479Sdim 1421314564Sdim for (EntityUP &entity_up : m_materializer->m_entities) { 1422314564Sdim entity_up->Dematerialize(frame_sp, *m_map, m_process_address, frame_top, 1423314564Sdim frame_bottom, error); 1424276479Sdim 1425314564Sdim if (!error.Success()) 1426314564Sdim break; 1427254721Semaste } 1428314564Sdim } 1429276479Sdim 1430314564Sdim Wipe(); 1431254721Semaste} 1432254721Semaste 1433314564Sdimvoid Materializer::Dematerializer::Wipe() { 1434314564Sdim if (!IsValid()) 1435314564Sdim return; 1436309124Sdim 1437314564Sdim for (EntityUP &entity_up : m_materializer->m_entities) { 1438314564Sdim entity_up->Wipe(*m_map, m_process_address); 1439314564Sdim } 1440254721Semaste 1441314564Sdim m_materializer = nullptr; 1442314564Sdim m_map = nullptr; 1443314564Sdim m_process_address = LLDB_INVALID_ADDRESS; 1444254721Semaste} 1445296417Sdim 1446314564SdimMaterializer::PersistentVariableDelegate::~PersistentVariableDelegate() = 1447314564Sdim default; 1448