Materializer.cpp revision 353358
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/ClangASTContext.h" 15254721Semaste#include "lldb/Symbol/Symbol.h" 16254721Semaste#include "lldb/Symbol/Type.h" 17254721Semaste#include "lldb/Symbol/Variable.h" 18254721Semaste#include "lldb/Target/ExecutionContext.h" 19254721Semaste#include "lldb/Target/RegisterContext.h" 20254721Semaste#include "lldb/Target/StackFrame.h" 21254721Semaste#include "lldb/Target/Target.h" 22254721Semaste#include "lldb/Target/Thread.h" 23321369Sdim#include "lldb/Utility/Log.h" 24344779Sdim#include "lldb/Utility/RegisterValue.h" 25254721Semaste 26353358Sdim#include <memory> 27353358Sdim 28254721Semasteusing namespace lldb_private; 29254721Semaste 30314564Sdimuint32_t Materializer::AddStructMember(Entity &entity) { 31314564Sdim uint32_t size = entity.GetSize(); 32314564Sdim uint32_t alignment = entity.GetAlignment(); 33309124Sdim 34314564Sdim uint32_t ret; 35309124Sdim 36314564Sdim if (m_current_offset == 0) 37314564Sdim m_struct_alignment = alignment; 38309124Sdim 39314564Sdim if (m_current_offset % alignment) 40314564Sdim m_current_offset += (alignment - (m_current_offset % alignment)); 41309124Sdim 42314564Sdim ret = m_current_offset; 43309124Sdim 44314564Sdim m_current_offset += size; 45309124Sdim 46314564Sdim return ret; 47254721Semaste} 48254721Semaste 49314564Sdimvoid Materializer::Entity::SetSizeAndAlignmentFromType(CompilerType &type) { 50344779Sdim if (llvm::Optional<uint64_t> size = type.GetByteSize(nullptr)) 51344779Sdim m_size = *size; 52309124Sdim 53314564Sdim uint32_t bit_alignment = type.GetTypeBitAlign(); 54309124Sdim 55314564Sdim if (bit_alignment % 8) { 56314564Sdim bit_alignment += 8; 57314564Sdim bit_alignment &= ~((uint32_t)0x111u); 58314564Sdim } 59309124Sdim 60314564Sdim m_alignment = bit_alignment / 8; 61254721Semaste} 62254721Semaste 63314564Sdimclass EntityPersistentVariable : public Materializer::Entity { 64254721Semastepublic: 65314564Sdim EntityPersistentVariable(lldb::ExpressionVariableSP &persistent_variable_sp, 66314564Sdim Materializer::PersistentVariableDelegate *delegate) 67314564Sdim : Entity(), m_persistent_variable_sp(persistent_variable_sp), 68314564Sdim m_delegate(delegate) { 69314564Sdim // Hard-coding to maximum size of a pointer since persistent variables are 70314564Sdim // materialized by reference 71314564Sdim m_size = 8; 72314564Sdim m_alignment = 8; 73314564Sdim } 74309124Sdim 75321369Sdim void MakeAllocation(IRMemoryMap &map, Status &err) { 76314564Sdim Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); 77254721Semaste 78341825Sdim // Allocate a spare memory area to store the persistent variable's 79341825Sdim // contents. 80309124Sdim 81321369Sdim Status allocate_error; 82314564Sdim const bool zero_memory = false; 83309124Sdim 84314564Sdim lldb::addr_t mem = map.Malloc( 85314564Sdim m_persistent_variable_sp->GetByteSize(), 8, 86314564Sdim lldb::ePermissionsReadable | lldb::ePermissionsWritable, 87314564Sdim IRMemoryMap::eAllocationPolicyMirror, zero_memory, allocate_error); 88309124Sdim 89314564Sdim if (!allocate_error.Success()) { 90314564Sdim err.SetErrorStringWithFormat( 91314564Sdim "couldn't allocate a memory area to store %s: %s", 92314564Sdim m_persistent_variable_sp->GetName().GetCString(), 93314564Sdim allocate_error.AsCString()); 94314564Sdim return; 95314564Sdim } 96309124Sdim 97314564Sdim if (log) 98314564Sdim log->Printf("Allocated %s (0x%" PRIx64 ") successfully", 99314564Sdim m_persistent_variable_sp->GetName().GetCString(), mem); 100309124Sdim 101314564Sdim // Put the location of the spare memory into the live data of the 102314564Sdim // ValueObject. 103309124Sdim 104314564Sdim m_persistent_variable_sp->m_live_sp = ValueObjectConstResult::Create( 105314564Sdim map.GetBestExecutionContextScope(), 106314564Sdim m_persistent_variable_sp->GetCompilerType(), 107314564Sdim m_persistent_variable_sp->GetName(), mem, eAddressTypeLoad, 108314564Sdim map.GetAddressByteSize()); 109309124Sdim 110314564Sdim // Clear the flag if the variable will never be deallocated. 111309124Sdim 112314564Sdim if (m_persistent_variable_sp->m_flags & 113314564Sdim ExpressionVariable::EVKeepInTarget) { 114321369Sdim Status leak_error; 115314564Sdim map.Leak(mem, leak_error); 116314564Sdim m_persistent_variable_sp->m_flags &= 117314564Sdim ~ExpressionVariable::EVNeedsAllocation; 118314564Sdim } 119309124Sdim 120314564Sdim // Write the contents of the variable to the area. 121309124Sdim 122321369Sdim Status write_error; 123309124Sdim 124314564Sdim map.WriteMemory(mem, m_persistent_variable_sp->GetValueBytes(), 125314564Sdim m_persistent_variable_sp->GetByteSize(), write_error); 126309124Sdim 127314564Sdim if (!write_error.Success()) { 128314564Sdim err.SetErrorStringWithFormat( 129314564Sdim "couldn't write %s to the target: %s", 130314564Sdim m_persistent_variable_sp->GetName().AsCString(), 131314564Sdim write_error.AsCString()); 132314564Sdim return; 133254721Semaste } 134314564Sdim } 135309124Sdim 136321369Sdim void DestroyAllocation(IRMemoryMap &map, Status &err) { 137321369Sdim Status deallocate_error; 138309124Sdim 139314564Sdim map.Free((lldb::addr_t)m_persistent_variable_sp->m_live_sp->GetValue() 140314564Sdim .GetScalar() 141314564Sdim .ULongLong(), 142314564Sdim deallocate_error); 143309124Sdim 144314564Sdim m_persistent_variable_sp->m_live_sp.reset(); 145309124Sdim 146314564Sdim if (!deallocate_error.Success()) { 147314564Sdim err.SetErrorStringWithFormat( 148314564Sdim "couldn't deallocate memory for %s: %s", 149314564Sdim m_persistent_variable_sp->GetName().GetCString(), 150314564Sdim deallocate_error.AsCString()); 151254721Semaste } 152314564Sdim } 153309124Sdim 154314564Sdim void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 155321369Sdim lldb::addr_t process_address, Status &err) override { 156314564Sdim Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); 157254721Semaste 158314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 159309124Sdim 160314564Sdim if (log) { 161314564Sdim log->Printf("EntityPersistentVariable::Materialize [address = 0x%" PRIx64 162314564Sdim ", m_name = %s, m_flags = 0x%hx]", 163314564Sdim (uint64_t)load_addr, 164314564Sdim m_persistent_variable_sp->GetName().AsCString(), 165314564Sdim m_persistent_variable_sp->m_flags); 166314564Sdim } 167309124Sdim 168314564Sdim if (m_persistent_variable_sp->m_flags & 169314564Sdim ExpressionVariable::EVNeedsAllocation) { 170314564Sdim MakeAllocation(map, err); 171314564Sdim m_persistent_variable_sp->m_flags |= 172314564Sdim ExpressionVariable::EVIsLLDBAllocated; 173309124Sdim 174314564Sdim if (!err.Success()) 175314564Sdim return; 176314564Sdim } 177309124Sdim 178314564Sdim if ((m_persistent_variable_sp->m_flags & 179314564Sdim ExpressionVariable::EVIsProgramReference && 180314564Sdim m_persistent_variable_sp->m_live_sp) || 181314564Sdim m_persistent_variable_sp->m_flags & 182314564Sdim ExpressionVariable::EVIsLLDBAllocated) { 183321369Sdim Status write_error; 184309124Sdim 185314564Sdim map.WriteScalarToMemory( 186314564Sdim load_addr, 187314564Sdim m_persistent_variable_sp->m_live_sp->GetValue().GetScalar(), 188314564Sdim map.GetAddressByteSize(), write_error); 189309124Sdim 190314564Sdim if (!write_error.Success()) { 191314564Sdim err.SetErrorStringWithFormat( 192314564Sdim "couldn't write the location of %s to memory: %s", 193314564Sdim m_persistent_variable_sp->GetName().AsCString(), 194314564Sdim write_error.AsCString()); 195314564Sdim } 196314564Sdim } else { 197314564Sdim err.SetErrorStringWithFormat( 198314564Sdim "no materialization happened for persistent variable %s", 199314564Sdim m_persistent_variable_sp->GetName().AsCString()); 200314564Sdim return; 201254721Semaste } 202314564Sdim } 203309124Sdim 204314564Sdim void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 205314564Sdim lldb::addr_t process_address, lldb::addr_t frame_top, 206321369Sdim lldb::addr_t frame_bottom, Status &err) override { 207314564Sdim Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); 208309124Sdim 209314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 210254721Semaste 211314564Sdim if (log) { 212314564Sdim log->Printf( 213314564Sdim "EntityPersistentVariable::Dematerialize [address = 0x%" PRIx64 214314564Sdim ", m_name = %s, m_flags = 0x%hx]", 215314564Sdim (uint64_t)process_address + m_offset, 216314564Sdim m_persistent_variable_sp->GetName().AsCString(), 217314564Sdim m_persistent_variable_sp->m_flags); 218314564Sdim } 219309124Sdim 220314564Sdim if (m_delegate) { 221314564Sdim m_delegate->DidDematerialize(m_persistent_variable_sp); 222314564Sdim } 223296417Sdim 224314564Sdim if ((m_persistent_variable_sp->m_flags & 225314564Sdim ExpressionVariable::EVIsLLDBAllocated) || 226314564Sdim (m_persistent_variable_sp->m_flags & 227314564Sdim ExpressionVariable::EVIsProgramReference)) { 228314564Sdim if (m_persistent_variable_sp->m_flags & 229314564Sdim ExpressionVariable::EVIsProgramReference && 230314564Sdim !m_persistent_variable_sp->m_live_sp) { 231314564Sdim // If the reference comes from the program, then the 232341825Sdim // ClangExpressionVariable's live variable data hasn't been set up yet. 233341825Sdim // Do this now. 234309124Sdim 235314564Sdim lldb::addr_t location; 236321369Sdim Status read_error; 237309124Sdim 238314564Sdim map.ReadPointerFromMemory(&location, load_addr, read_error); 239309124Sdim 240314564Sdim if (!read_error.Success()) { 241314564Sdim err.SetErrorStringWithFormat( 242314564Sdim "couldn't read the address of program-allocated variable %s: %s", 243314564Sdim m_persistent_variable_sp->GetName().GetCString(), 244314564Sdim read_error.AsCString()); 245314564Sdim return; 246314564Sdim } 247309124Sdim 248314564Sdim m_persistent_variable_sp->m_live_sp = ValueObjectConstResult::Create( 249314564Sdim map.GetBestExecutionContextScope(), 250314564Sdim m_persistent_variable_sp.get()->GetCompilerType(), 251314564Sdim m_persistent_variable_sp->GetName(), location, eAddressTypeLoad, 252314564Sdim m_persistent_variable_sp->GetByteSize()); 253309124Sdim 254314564Sdim if (frame_top != LLDB_INVALID_ADDRESS && 255314564Sdim frame_bottom != LLDB_INVALID_ADDRESS && location >= frame_bottom && 256314564Sdim location <= frame_top) { 257314564Sdim // If the variable is resident in the stack frame created by the 258341825Sdim // expression, then it cannot be relied upon to stay around. We 259341825Sdim // treat it as needing reallocation. 260314564Sdim m_persistent_variable_sp->m_flags |= 261314564Sdim ExpressionVariable::EVIsLLDBAllocated; 262314564Sdim m_persistent_variable_sp->m_flags |= 263314564Sdim ExpressionVariable::EVNeedsAllocation; 264314564Sdim m_persistent_variable_sp->m_flags |= 265314564Sdim ExpressionVariable::EVNeedsFreezeDry; 266314564Sdim m_persistent_variable_sp->m_flags &= 267314564Sdim ~ExpressionVariable::EVIsProgramReference; 268314564Sdim } 269314564Sdim } 270309124Sdim 271314564Sdim lldb::addr_t mem = m_persistent_variable_sp->m_live_sp->GetValue() 272314564Sdim .GetScalar() 273314564Sdim .ULongLong(); 274309124Sdim 275314564Sdim if (!m_persistent_variable_sp->m_live_sp) { 276314564Sdim err.SetErrorStringWithFormat( 277314564Sdim "couldn't find the memory area used to store %s", 278314564Sdim m_persistent_variable_sp->GetName().GetCString()); 279314564Sdim return; 280314564Sdim } 281309124Sdim 282314564Sdim if (m_persistent_variable_sp->m_live_sp->GetValue() 283314564Sdim .GetValueAddressType() != eAddressTypeLoad) { 284314564Sdim err.SetErrorStringWithFormat( 285314564Sdim "the address of the memory area for %s is in an incorrect format", 286314564Sdim m_persistent_variable_sp->GetName().GetCString()); 287314564Sdim return; 288314564Sdim } 289309124Sdim 290314564Sdim if (m_persistent_variable_sp->m_flags & 291314564Sdim ExpressionVariable::EVNeedsFreezeDry || 292314564Sdim m_persistent_variable_sp->m_flags & 293314564Sdim ExpressionVariable::EVKeepInTarget) { 294314564Sdim if (log) 295314564Sdim log->Printf( 296314564Sdim "Dematerializing %s from 0x%" PRIx64 " (size = %llu)", 297314564Sdim m_persistent_variable_sp->GetName().GetCString(), (uint64_t)mem, 298314564Sdim (unsigned long long)m_persistent_variable_sp->GetByteSize()); 299309124Sdim 300314564Sdim // Read the contents of the spare memory area 301309124Sdim 302314564Sdim m_persistent_variable_sp->ValueUpdated(); 303309124Sdim 304321369Sdim Status read_error; 305309124Sdim 306314564Sdim map.ReadMemory(m_persistent_variable_sp->GetValueBytes(), mem, 307314564Sdim m_persistent_variable_sp->GetByteSize(), read_error); 308309124Sdim 309314564Sdim if (!read_error.Success()) { 310314564Sdim err.SetErrorStringWithFormat( 311314564Sdim "couldn't read the contents of %s from memory: %s", 312314564Sdim m_persistent_variable_sp->GetName().GetCString(), 313314564Sdim read_error.AsCString()); 314314564Sdim return; 315254721Semaste } 316309124Sdim 317314564Sdim m_persistent_variable_sp->m_flags &= 318314564Sdim ~ExpressionVariable::EVNeedsFreezeDry; 319314564Sdim } 320314564Sdim } else { 321314564Sdim err.SetErrorStringWithFormat( 322314564Sdim "no dematerialization happened for persistent variable %s", 323314564Sdim m_persistent_variable_sp->GetName().AsCString()); 324314564Sdim return; 325314564Sdim } 326309124Sdim 327314564Sdim lldb::ProcessSP process_sp = 328314564Sdim map.GetBestExecutionContextScope()->CalculateProcess(); 329314564Sdim if (!process_sp || !process_sp->CanJIT()) { 330314564Sdim // Allocations are not persistent so persistent variables cannot stay 331314564Sdim // materialized. 332254721Semaste 333314564Sdim m_persistent_variable_sp->m_flags |= 334314564Sdim ExpressionVariable::EVNeedsAllocation; 335314564Sdim 336314564Sdim DestroyAllocation(map, err); 337314564Sdim if (!err.Success()) 338314564Sdim return; 339314564Sdim } else if (m_persistent_variable_sp->m_flags & 340314564Sdim ExpressionVariable::EVNeedsAllocation && 341314564Sdim !(m_persistent_variable_sp->m_flags & 342314564Sdim ExpressionVariable::EVKeepInTarget)) { 343314564Sdim DestroyAllocation(map, err); 344314564Sdim if (!err.Success()) 345314564Sdim return; 346254721Semaste } 347314564Sdim } 348309124Sdim 349314564Sdim void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address, 350314564Sdim Log *log) override { 351314564Sdim StreamString dump_stream; 352309124Sdim 353321369Sdim Status err; 354309124Sdim 355314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 356254721Semaste 357314564Sdim dump_stream.Printf("0x%" PRIx64 ": EntityPersistentVariable (%s)\n", 358314564Sdim load_addr, 359314564Sdim m_persistent_variable_sp->GetName().AsCString()); 360309124Sdim 361314564Sdim { 362314564Sdim dump_stream.Printf("Pointer:\n"); 363309124Sdim 364314564Sdim DataBufferHeap data(m_size, 0); 365309124Sdim 366314564Sdim map.ReadMemory(data.GetBytes(), load_addr, m_size, err); 367309124Sdim 368314564Sdim if (!err.Success()) { 369314564Sdim dump_stream.Printf(" <could not be read>\n"); 370314564Sdim } else { 371321369Sdim DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, 372321369Sdim load_addr); 373309124Sdim 374314564Sdim dump_stream.PutChar('\n'); 375314564Sdim } 376314564Sdim } 377309124Sdim 378314564Sdim { 379314564Sdim dump_stream.Printf("Target:\n"); 380309124Sdim 381314564Sdim lldb::addr_t target_address; 382309124Sdim 383314564Sdim map.ReadPointerFromMemory(&target_address, load_addr, err); 384309124Sdim 385314564Sdim if (!err.Success()) { 386314564Sdim dump_stream.Printf(" <could not be read>\n"); 387314564Sdim } else { 388314564Sdim DataBufferHeap data(m_persistent_variable_sp->GetByteSize(), 0); 389309124Sdim 390314564Sdim map.ReadMemory(data.GetBytes(), target_address, 391314564Sdim m_persistent_variable_sp->GetByteSize(), err); 392309124Sdim 393314564Sdim if (!err.Success()) { 394314564Sdim dump_stream.Printf(" <could not be read>\n"); 395314564Sdim } else { 396321369Sdim DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, 397321369Sdim target_address); 398309124Sdim 399314564Sdim dump_stream.PutChar('\n'); 400254721Semaste } 401314564Sdim } 402254721Semaste } 403309124Sdim 404314564Sdim log->PutString(dump_stream.GetString()); 405314564Sdim } 406296417Sdim 407314564Sdim void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {} 408314564Sdim 409254721Semasteprivate: 410314564Sdim lldb::ExpressionVariableSP m_persistent_variable_sp; 411314564Sdim Materializer::PersistentVariableDelegate *m_delegate; 412254721Semaste}; 413254721Semaste 414314564Sdimuint32_t Materializer::AddPersistentVariable( 415314564Sdim lldb::ExpressionVariableSP &persistent_variable_sp, 416321369Sdim PersistentVariableDelegate *delegate, Status &err) { 417314564Sdim EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP()); 418314564Sdim iter->reset(new EntityPersistentVariable(persistent_variable_sp, delegate)); 419314564Sdim uint32_t ret = AddStructMember(**iter); 420314564Sdim (*iter)->SetOffset(ret); 421314564Sdim return ret; 422254721Semaste} 423254721Semaste 424314564Sdimclass EntityVariable : public Materializer::Entity { 425254721Semastepublic: 426314564Sdim EntityVariable(lldb::VariableSP &variable_sp) 427314564Sdim : Entity(), m_variable_sp(variable_sp), m_is_reference(false), 428254721Semaste m_temporary_allocation(LLDB_INVALID_ADDRESS), 429314564Sdim m_temporary_allocation_size(0) { 430314564Sdim // Hard-coding to maximum size of a pointer since all variables are 431314564Sdim // materialized by reference 432314564Sdim m_size = 8; 433314564Sdim m_alignment = 8; 434314564Sdim m_is_reference = 435314564Sdim m_variable_sp->GetType()->GetForwardCompilerType().IsReferenceType(); 436314564Sdim } 437314564Sdim 438314564Sdim void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 439321369Sdim lldb::addr_t process_address, Status &err) override { 440314564Sdim Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); 441314564Sdim 442314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 443314564Sdim if (log) { 444314564Sdim log->Printf("EntityVariable::Materialize [address = 0x%" PRIx64 445314564Sdim ", m_variable_sp = %s]", 446314564Sdim (uint64_t)load_addr, m_variable_sp->GetName().AsCString()); 447254721Semaste } 448309124Sdim 449314564Sdim ExecutionContextScope *scope = frame_sp.get(); 450309124Sdim 451314564Sdim if (!scope) 452314564Sdim scope = map.GetBestExecutionContextScope(); 453309124Sdim 454314564Sdim lldb::ValueObjectSP valobj_sp = 455314564Sdim ValueObjectVariable::Create(scope, m_variable_sp); 456309124Sdim 457314564Sdim if (!valobj_sp) { 458314564Sdim err.SetErrorStringWithFormat( 459314564Sdim "couldn't get a value object for variable %s", 460314564Sdim m_variable_sp->GetName().AsCString()); 461314564Sdim return; 462314564Sdim } 463309124Sdim 464321369Sdim Status valobj_error = valobj_sp->GetError(); 465309124Sdim 466314564Sdim if (valobj_error.Fail()) { 467314564Sdim err.SetErrorStringWithFormat("couldn't get the value of variable %s: %s", 468314564Sdim m_variable_sp->GetName().AsCString(), 469314564Sdim valobj_error.AsCString()); 470314564Sdim return; 471314564Sdim } 472309124Sdim 473314564Sdim if (m_is_reference) { 474314564Sdim DataExtractor valobj_extractor; 475321369Sdim Status extract_error; 476314564Sdim valobj_sp->GetData(valobj_extractor, extract_error); 477309124Sdim 478314564Sdim if (!extract_error.Success()) { 479314564Sdim err.SetErrorStringWithFormat( 480314564Sdim "couldn't read contents of reference variable %s: %s", 481314564Sdim m_variable_sp->GetName().AsCString(), extract_error.AsCString()); 482314564Sdim return; 483314564Sdim } 484309124Sdim 485314564Sdim lldb::offset_t offset = 0; 486314564Sdim lldb::addr_t reference_addr = valobj_extractor.GetAddress(&offset); 487309124Sdim 488321369Sdim Status write_error; 489314564Sdim map.WritePointerToMemory(load_addr, reference_addr, write_error); 490309124Sdim 491314564Sdim if (!write_error.Success()) { 492314564Sdim err.SetErrorStringWithFormat("couldn't write the contents of reference " 493314564Sdim "variable %s to memory: %s", 494314564Sdim m_variable_sp->GetName().AsCString(), 495314564Sdim write_error.AsCString()); 496314564Sdim return; 497314564Sdim } 498314564Sdim } else { 499314564Sdim AddressType address_type = eAddressTypeInvalid; 500314564Sdim const bool scalar_is_load_address = false; 501314564Sdim lldb::addr_t addr_of_valobj = 502314564Sdim valobj_sp->GetAddressOf(scalar_is_load_address, &address_type); 503314564Sdim if (addr_of_valobj != LLDB_INVALID_ADDRESS) { 504321369Sdim Status write_error; 505314564Sdim map.WritePointerToMemory(load_addr, addr_of_valobj, write_error); 506309124Sdim 507314564Sdim if (!write_error.Success()) { 508314564Sdim err.SetErrorStringWithFormat( 509314564Sdim "couldn't write the address of variable %s to memory: %s", 510314564Sdim m_variable_sp->GetName().AsCString(), write_error.AsCString()); 511314564Sdim return; 512314564Sdim } 513314564Sdim } else { 514314564Sdim DataExtractor data; 515321369Sdim Status extract_error; 516314564Sdim valobj_sp->GetData(data, extract_error); 517314564Sdim if (!extract_error.Success()) { 518314564Sdim err.SetErrorStringWithFormat("couldn't get the value of %s: %s", 519314564Sdim m_variable_sp->GetName().AsCString(), 520314564Sdim extract_error.AsCString()); 521314564Sdim return; 522314564Sdim } 523309124Sdim 524314564Sdim if (m_temporary_allocation != LLDB_INVALID_ADDRESS) { 525314564Sdim err.SetErrorStringWithFormat( 526314564Sdim "trying to create a temporary region for %s but one exists", 527314564Sdim m_variable_sp->GetName().AsCString()); 528314564Sdim return; 529254721Semaste } 530309124Sdim 531314564Sdim if (data.GetByteSize() < m_variable_sp->GetType()->GetByteSize()) { 532314564Sdim if (data.GetByteSize() == 0 && 533344779Sdim !m_variable_sp->LocationExpression().IsValid()) { 534314564Sdim err.SetErrorStringWithFormat("the variable '%s' has no location, " 535314564Sdim "it may have been optimized out", 536314564Sdim m_variable_sp->GetName().AsCString()); 537314564Sdim } else { 538314564Sdim err.SetErrorStringWithFormat( 539314564Sdim "size of variable %s (%" PRIu64 540314564Sdim ") is larger than the ValueObject's size (%" PRIu64 ")", 541314564Sdim m_variable_sp->GetName().AsCString(), 542353358Sdim m_variable_sp->GetType()->GetByteSize().getValueOr(0), 543353358Sdim data.GetByteSize()); 544314564Sdim } 545314564Sdim return; 546314564Sdim } 547309124Sdim 548314564Sdim size_t bit_align = 549314564Sdim m_variable_sp->GetType()->GetLayoutCompilerType().GetTypeBitAlign(); 550314564Sdim size_t byte_align = (bit_align + 7) / 8; 551309124Sdim 552314564Sdim if (!byte_align) 553314564Sdim byte_align = 1; 554309124Sdim 555321369Sdim Status alloc_error; 556314564Sdim const bool zero_memory = false; 557309124Sdim 558314564Sdim m_temporary_allocation = map.Malloc( 559314564Sdim data.GetByteSize(), byte_align, 560314564Sdim lldb::ePermissionsReadable | lldb::ePermissionsWritable, 561314564Sdim IRMemoryMap::eAllocationPolicyMirror, zero_memory, alloc_error); 562309124Sdim 563314564Sdim m_temporary_allocation_size = data.GetByteSize(); 564296417Sdim 565353358Sdim m_original_data = std::make_shared<DataBufferHeap>(data.GetDataStart(), 566353358Sdim data.GetByteSize()); 567309124Sdim 568314564Sdim if (!alloc_error.Success()) { 569314564Sdim err.SetErrorStringWithFormat( 570314564Sdim "couldn't allocate a temporary region for %s: %s", 571314564Sdim m_variable_sp->GetName().AsCString(), alloc_error.AsCString()); 572314564Sdim return; 573314564Sdim } 574309124Sdim 575321369Sdim Status write_error; 576309124Sdim 577314564Sdim map.WriteMemory(m_temporary_allocation, data.GetDataStart(), 578314564Sdim data.GetByteSize(), write_error); 579309124Sdim 580314564Sdim if (!write_error.Success()) { 581314564Sdim err.SetErrorStringWithFormat( 582314564Sdim "couldn't write to the temporary region for %s: %s", 583314564Sdim m_variable_sp->GetName().AsCString(), write_error.AsCString()); 584314564Sdim return; 585314564Sdim } 586309124Sdim 587321369Sdim Status pointer_write_error; 588309124Sdim 589314564Sdim map.WritePointerToMemory(load_addr, m_temporary_allocation, 590314564Sdim pointer_write_error); 591309124Sdim 592314564Sdim if (!pointer_write_error.Success()) { 593314564Sdim err.SetErrorStringWithFormat( 594314564Sdim "couldn't write the address of the temporary region for %s: %s", 595314564Sdim m_variable_sp->GetName().AsCString(), 596314564Sdim pointer_write_error.AsCString()); 597254721Semaste } 598314564Sdim } 599254721Semaste } 600314564Sdim } 601309124Sdim 602314564Sdim void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 603314564Sdim lldb::addr_t process_address, lldb::addr_t frame_top, 604321369Sdim lldb::addr_t frame_bottom, Status &err) override { 605314564Sdim Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); 606254721Semaste 607314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 608314564Sdim if (log) { 609314564Sdim log->Printf("EntityVariable::Dematerialize [address = 0x%" PRIx64 610314564Sdim ", m_variable_sp = %s]", 611314564Sdim (uint64_t)load_addr, m_variable_sp->GetName().AsCString()); 612314564Sdim } 613309124Sdim 614314564Sdim if (m_temporary_allocation != LLDB_INVALID_ADDRESS) { 615314564Sdim ExecutionContextScope *scope = frame_sp.get(); 616309124Sdim 617314564Sdim if (!scope) 618314564Sdim scope = map.GetBestExecutionContextScope(); 619309124Sdim 620314564Sdim lldb::ValueObjectSP valobj_sp = 621314564Sdim ValueObjectVariable::Create(scope, m_variable_sp); 622309124Sdim 623314564Sdim if (!valobj_sp) { 624314564Sdim err.SetErrorStringWithFormat( 625314564Sdim "couldn't get a value object for variable %s", 626314564Sdim m_variable_sp->GetName().AsCString()); 627314564Sdim return; 628314564Sdim } 629309124Sdim 630314564Sdim lldb_private::DataExtractor data; 631309124Sdim 632321369Sdim Status extract_error; 633309124Sdim 634314564Sdim map.GetMemoryData(data, m_temporary_allocation, valobj_sp->GetByteSize(), 635314564Sdim extract_error); 636309124Sdim 637314564Sdim if (!extract_error.Success()) { 638314564Sdim err.SetErrorStringWithFormat("couldn't get the data for variable %s", 639314564Sdim m_variable_sp->GetName().AsCString()); 640314564Sdim return; 641314564Sdim } 642309124Sdim 643314564Sdim bool actually_write = true; 644309124Sdim 645314564Sdim if (m_original_data) { 646314564Sdim if ((data.GetByteSize() == m_original_data->GetByteSize()) && 647314564Sdim !memcmp(m_original_data->GetBytes(), data.GetDataStart(), 648314564Sdim data.GetByteSize())) { 649314564Sdim actually_write = false; 650314564Sdim } 651314564Sdim } 652309124Sdim 653321369Sdim Status set_error; 654309124Sdim 655314564Sdim if (actually_write) { 656314564Sdim valobj_sp->SetData(data, set_error); 657309124Sdim 658314564Sdim if (!set_error.Success()) { 659314564Sdim err.SetErrorStringWithFormat( 660314564Sdim "couldn't write the new contents of %s back into the variable", 661314564Sdim m_variable_sp->GetName().AsCString()); 662314564Sdim return; 663314564Sdim } 664314564Sdim } 665309124Sdim 666321369Sdim Status free_error; 667309124Sdim 668314564Sdim map.Free(m_temporary_allocation, free_error); 669309124Sdim 670314564Sdim if (!free_error.Success()) { 671314564Sdim err.SetErrorStringWithFormat( 672314564Sdim "couldn't free the temporary region for %s: %s", 673314564Sdim m_variable_sp->GetName().AsCString(), free_error.AsCString()); 674314564Sdim return; 675314564Sdim } 676309124Sdim 677314564Sdim m_original_data.reset(); 678314564Sdim m_temporary_allocation = LLDB_INVALID_ADDRESS; 679314564Sdim m_temporary_allocation_size = 0; 680254721Semaste } 681314564Sdim } 682309124Sdim 683314564Sdim void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address, 684314564Sdim Log *log) override { 685314564Sdim StreamString dump_stream; 686254721Semaste 687314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 688314564Sdim dump_stream.Printf("0x%" PRIx64 ": EntityVariable\n", load_addr); 689309124Sdim 690321369Sdim Status err; 691309124Sdim 692314564Sdim lldb::addr_t ptr = LLDB_INVALID_ADDRESS; 693309124Sdim 694314564Sdim { 695314564Sdim dump_stream.Printf("Pointer:\n"); 696309124Sdim 697314564Sdim DataBufferHeap data(m_size, 0); 698309124Sdim 699314564Sdim map.ReadMemory(data.GetBytes(), load_addr, m_size, err); 700309124Sdim 701314564Sdim if (!err.Success()) { 702314564Sdim dump_stream.Printf(" <could not be read>\n"); 703314564Sdim } else { 704314564Sdim DataExtractor extractor(data.GetBytes(), data.GetByteSize(), 705314564Sdim map.GetByteOrder(), map.GetAddressByteSize()); 706309124Sdim 707321369Sdim DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, 708321369Sdim load_addr); 709309124Sdim 710314564Sdim lldb::offset_t offset; 711309124Sdim 712314564Sdim ptr = extractor.GetPointer(&offset); 713309124Sdim 714314564Sdim dump_stream.PutChar('\n'); 715314564Sdim } 716314564Sdim } 717309124Sdim 718314564Sdim if (m_temporary_allocation == LLDB_INVALID_ADDRESS) { 719314564Sdim dump_stream.Printf("Points to process memory:\n"); 720314564Sdim } else { 721314564Sdim dump_stream.Printf("Temporary allocation:\n"); 722314564Sdim } 723309124Sdim 724314564Sdim if (ptr == LLDB_INVALID_ADDRESS) { 725314564Sdim dump_stream.Printf(" <could not be be found>\n"); 726314564Sdim } else { 727314564Sdim DataBufferHeap data(m_temporary_allocation_size, 0); 728309124Sdim 729314564Sdim map.ReadMemory(data.GetBytes(), m_temporary_allocation, 730314564Sdim m_temporary_allocation_size, err); 731309124Sdim 732314564Sdim if (!err.Success()) { 733314564Sdim dump_stream.Printf(" <could not be read>\n"); 734314564Sdim } else { 735321369Sdim DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, 736321369Sdim load_addr); 737309124Sdim 738314564Sdim dump_stream.PutChar('\n'); 739314564Sdim } 740254721Semaste } 741309124Sdim 742314564Sdim log->PutString(dump_stream.GetString()); 743314564Sdim } 744309124Sdim 745314564Sdim void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override { 746314564Sdim if (m_temporary_allocation != LLDB_INVALID_ADDRESS) { 747321369Sdim Status free_error; 748309124Sdim 749314564Sdim map.Free(m_temporary_allocation, free_error); 750254721Semaste 751314564Sdim m_temporary_allocation = LLDB_INVALID_ADDRESS; 752314564Sdim m_temporary_allocation_size = 0; 753254721Semaste } 754314564Sdim } 755296417Sdim 756254721Semasteprivate: 757314564Sdim lldb::VariableSP m_variable_sp; 758314564Sdim bool m_is_reference; 759314564Sdim lldb::addr_t m_temporary_allocation; 760314564Sdim size_t m_temporary_allocation_size; 761314564Sdim lldb::DataBufferSP m_original_data; 762254721Semaste}; 763254721Semaste 764321369Sdimuint32_t Materializer::AddVariable(lldb::VariableSP &variable_sp, Status &err) { 765314564Sdim EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP()); 766314564Sdim iter->reset(new EntityVariable(variable_sp)); 767314564Sdim uint32_t ret = AddStructMember(**iter); 768314564Sdim (*iter)->SetOffset(ret); 769314564Sdim return ret; 770254721Semaste} 771254721Semaste 772314564Sdimclass EntityResultVariable : public Materializer::Entity { 773254721Semastepublic: 774314564Sdim EntityResultVariable(const CompilerType &type, bool is_program_reference, 775314564Sdim bool keep_in_memory, 776314564Sdim Materializer::PersistentVariableDelegate *delegate) 777314564Sdim : Entity(), m_type(type), m_is_program_reference(is_program_reference), 778254721Semaste m_keep_in_memory(keep_in_memory), 779254721Semaste m_temporary_allocation(LLDB_INVALID_ADDRESS), 780314564Sdim m_temporary_allocation_size(0), m_delegate(delegate) { 781314564Sdim // Hard-coding to maximum size of a pointer since all results are 782314564Sdim // materialized by reference 783314564Sdim m_size = 8; 784314564Sdim m_alignment = 8; 785314564Sdim } 786309124Sdim 787314564Sdim void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 788321369Sdim lldb::addr_t process_address, Status &err) override { 789314564Sdim if (!m_is_program_reference) { 790314564Sdim if (m_temporary_allocation != LLDB_INVALID_ADDRESS) { 791314564Sdim err.SetErrorString("Trying to create a temporary region for the result " 792314564Sdim "but one exists"); 793314564Sdim return; 794314564Sdim } 795309124Sdim 796314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 797254721Semaste 798314564Sdim ExecutionContextScope *exe_scope = map.GetBestExecutionContextScope(); 799309124Sdim 800344779Sdim llvm::Optional<uint64_t> byte_size = m_type.GetByteSize(exe_scope); 801344779Sdim if (!byte_size) { 802344779Sdim err.SetErrorString("can't get size of type"); 803344779Sdim return; 804344779Sdim } 805314564Sdim size_t bit_align = m_type.GetTypeBitAlign(); 806314564Sdim size_t byte_align = (bit_align + 7) / 8; 807309124Sdim 808314564Sdim if (!byte_align) 809314564Sdim byte_align = 1; 810296417Sdim 811321369Sdim Status alloc_error; 812314564Sdim const bool zero_memory = true; 813309124Sdim 814314564Sdim m_temporary_allocation = map.Malloc( 815344779Sdim *byte_size, byte_align, 816314564Sdim lldb::ePermissionsReadable | lldb::ePermissionsWritable, 817314564Sdim IRMemoryMap::eAllocationPolicyMirror, zero_memory, alloc_error); 818344779Sdim m_temporary_allocation_size = *byte_size; 819309124Sdim 820314564Sdim if (!alloc_error.Success()) { 821314564Sdim err.SetErrorStringWithFormat( 822314564Sdim "couldn't allocate a temporary region for the result: %s", 823314564Sdim alloc_error.AsCString()); 824314564Sdim return; 825314564Sdim } 826309124Sdim 827321369Sdim Status pointer_write_error; 828309124Sdim 829314564Sdim map.WritePointerToMemory(load_addr, m_temporary_allocation, 830314564Sdim pointer_write_error); 831314564Sdim 832314564Sdim if (!pointer_write_error.Success()) { 833314564Sdim err.SetErrorStringWithFormat("couldn't write the address of the " 834314564Sdim "temporary region for the result: %s", 835314564Sdim pointer_write_error.AsCString()); 836314564Sdim } 837254721Semaste } 838314564Sdim } 839309124Sdim 840314564Sdim void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 841314564Sdim lldb::addr_t process_address, lldb::addr_t frame_top, 842321369Sdim lldb::addr_t frame_bottom, Status &err) override { 843314564Sdim err.Clear(); 844309124Sdim 845314564Sdim ExecutionContextScope *exe_scope = map.GetBestExecutionContextScope(); 846309124Sdim 847314564Sdim if (!exe_scope) { 848314564Sdim err.SetErrorString("Couldn't dematerialize a result variable: invalid " 849314564Sdim "execution context scope"); 850314564Sdim return; 851314564Sdim } 852309124Sdim 853314564Sdim lldb::addr_t address; 854321369Sdim Status read_error; 855314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 856309124Sdim 857314564Sdim map.ReadPointerFromMemory(&address, load_addr, read_error); 858309124Sdim 859314564Sdim if (!read_error.Success()) { 860314564Sdim err.SetErrorString("Couldn't dematerialize a result variable: couldn't " 861314564Sdim "read its address"); 862314564Sdim return; 863314564Sdim } 864309124Sdim 865314564Sdim lldb::TargetSP target_sp = exe_scope->CalculateTarget(); 866309124Sdim 867314564Sdim if (!target_sp) { 868314564Sdim err.SetErrorString("Couldn't dematerialize a result variable: no target"); 869314564Sdim return; 870314564Sdim } 871309124Sdim 872321369Sdim Status type_system_error; 873314564Sdim TypeSystem *type_system = target_sp->GetScratchTypeSystemForLanguage( 874314564Sdim &type_system_error, m_type.GetMinimumLanguage()); 875309124Sdim 876314564Sdim if (!type_system) { 877314564Sdim err.SetErrorStringWithFormat("Couldn't dematerialize a result variable: " 878314564Sdim "couldn't get the corresponding type " 879314564Sdim "system: %s", 880314564Sdim type_system_error.AsCString()); 881314564Sdim return; 882314564Sdim } 883309124Sdim 884314564Sdim PersistentExpressionState *persistent_state = 885314564Sdim type_system->GetPersistentExpressionState(); 886309124Sdim 887314564Sdim if (!persistent_state) { 888314564Sdim err.SetErrorString("Couldn't dematerialize a result variable: " 889314564Sdim "corresponding type system doesn't handle persistent " 890314564Sdim "variables"); 891314564Sdim return; 892314564Sdim } 893309124Sdim 894341825Sdim ConstString name = 895341825Sdim m_delegate 896341825Sdim ? m_delegate->GetName() 897341825Sdim : persistent_state->GetNextPersistentVariableName( 898341825Sdim *target_sp, persistent_state->GetPersistentVariablePrefix()); 899309124Sdim 900314564Sdim lldb::ExpressionVariableSP ret = persistent_state->CreatePersistentVariable( 901314564Sdim exe_scope, name, m_type, map.GetByteOrder(), map.GetAddressByteSize()); 902309124Sdim 903314564Sdim if (!ret) { 904314564Sdim err.SetErrorStringWithFormat("couldn't dematerialize a result variable: " 905314564Sdim "failed to make persistent variable %s", 906314564Sdim name.AsCString()); 907314564Sdim return; 908314564Sdim } 909309124Sdim 910314564Sdim lldb::ProcessSP process_sp = 911314564Sdim map.GetBestExecutionContextScope()->CalculateProcess(); 912309124Sdim 913314564Sdim if (m_delegate) { 914314564Sdim m_delegate->DidDematerialize(ret); 915314564Sdim } 916309124Sdim 917314564Sdim bool can_persist = 918314564Sdim (m_is_program_reference && process_sp && process_sp->CanJIT() && 919314564Sdim !(address >= frame_bottom && address < frame_top)); 920254721Semaste 921314564Sdim if (can_persist && m_keep_in_memory) { 922314564Sdim ret->m_live_sp = ValueObjectConstResult::Create(exe_scope, m_type, name, 923314564Sdim address, eAddressTypeLoad, 924314564Sdim map.GetAddressByteSize()); 925314564Sdim } 926309124Sdim 927314564Sdim ret->ValueUpdated(); 928309124Sdim 929314564Sdim const size_t pvar_byte_size = ret->GetByteSize(); 930314564Sdim uint8_t *pvar_data = ret->GetValueBytes(); 931309124Sdim 932314564Sdim map.ReadMemory(pvar_data, address, pvar_byte_size, read_error); 933309124Sdim 934314564Sdim if (!read_error.Success()) { 935314564Sdim err.SetErrorString( 936314564Sdim "Couldn't dematerialize a result variable: couldn't read its memory"); 937314564Sdim return; 938314564Sdim } 939309124Sdim 940314564Sdim if (!can_persist || !m_keep_in_memory) { 941314564Sdim ret->m_flags |= ExpressionVariable::EVNeedsAllocation; 942309124Sdim 943314564Sdim if (m_temporary_allocation != LLDB_INVALID_ADDRESS) { 944321369Sdim Status free_error; 945314564Sdim map.Free(m_temporary_allocation, free_error); 946314564Sdim } 947314564Sdim } else { 948314564Sdim ret->m_flags |= ExpressionVariable::EVIsLLDBAllocated; 949254721Semaste } 950309124Sdim 951314564Sdim m_temporary_allocation = LLDB_INVALID_ADDRESS; 952314564Sdim m_temporary_allocation_size = 0; 953314564Sdim } 954309124Sdim 955314564Sdim void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address, 956314564Sdim Log *log) override { 957314564Sdim StreamString dump_stream; 958254721Semaste 959314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 960309124Sdim 961314564Sdim dump_stream.Printf("0x%" PRIx64 ": EntityResultVariable\n", load_addr); 962309124Sdim 963321369Sdim Status err; 964309124Sdim 965314564Sdim lldb::addr_t ptr = LLDB_INVALID_ADDRESS; 966309124Sdim 967314564Sdim { 968314564Sdim dump_stream.Printf("Pointer:\n"); 969309124Sdim 970314564Sdim DataBufferHeap data(m_size, 0); 971309124Sdim 972314564Sdim map.ReadMemory(data.GetBytes(), load_addr, m_size, err); 973309124Sdim 974314564Sdim if (!err.Success()) { 975314564Sdim dump_stream.Printf(" <could not be read>\n"); 976314564Sdim } else { 977314564Sdim DataExtractor extractor(data.GetBytes(), data.GetByteSize(), 978314564Sdim map.GetByteOrder(), map.GetAddressByteSize()); 979309124Sdim 980321369Sdim DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, 981321369Sdim load_addr); 982309124Sdim 983314564Sdim lldb::offset_t offset; 984309124Sdim 985314564Sdim ptr = extractor.GetPointer(&offset); 986309124Sdim 987314564Sdim dump_stream.PutChar('\n'); 988314564Sdim } 989314564Sdim } 990309124Sdim 991314564Sdim if (m_temporary_allocation == LLDB_INVALID_ADDRESS) { 992314564Sdim dump_stream.Printf("Points to process memory:\n"); 993314564Sdim } else { 994314564Sdim dump_stream.Printf("Temporary allocation:\n"); 995314564Sdim } 996309124Sdim 997314564Sdim if (ptr == LLDB_INVALID_ADDRESS) { 998314564Sdim dump_stream.Printf(" <could not be be found>\n"); 999314564Sdim } else { 1000314564Sdim DataBufferHeap data(m_temporary_allocation_size, 0); 1001309124Sdim 1002314564Sdim map.ReadMemory(data.GetBytes(), m_temporary_allocation, 1003314564Sdim m_temporary_allocation_size, err); 1004309124Sdim 1005314564Sdim if (!err.Success()) { 1006314564Sdim dump_stream.Printf(" <could not be read>\n"); 1007314564Sdim } else { 1008321369Sdim DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, 1009321369Sdim load_addr); 1010309124Sdim 1011314564Sdim dump_stream.PutChar('\n'); 1012314564Sdim } 1013254721Semaste } 1014309124Sdim 1015314564Sdim log->PutString(dump_stream.GetString()); 1016314564Sdim } 1017309124Sdim 1018314564Sdim void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override { 1019314564Sdim if (!m_keep_in_memory && m_temporary_allocation != LLDB_INVALID_ADDRESS) { 1020321369Sdim Status free_error; 1021309124Sdim 1022314564Sdim map.Free(m_temporary_allocation, free_error); 1023254721Semaste } 1024296417Sdim 1025314564Sdim m_temporary_allocation = LLDB_INVALID_ADDRESS; 1026314564Sdim m_temporary_allocation_size = 0; 1027314564Sdim } 1028314564Sdim 1029254721Semasteprivate: 1030314564Sdim CompilerType m_type; 1031314564Sdim bool m_is_program_reference; 1032314564Sdim bool m_keep_in_memory; 1033309124Sdim 1034314564Sdim lldb::addr_t m_temporary_allocation; 1035314564Sdim size_t m_temporary_allocation_size; 1036314564Sdim Materializer::PersistentVariableDelegate *m_delegate; 1037254721Semaste}; 1038254721Semaste 1039314564Sdimuint32_t Materializer::AddResultVariable(const CompilerType &type, 1040314564Sdim bool is_program_reference, 1041314564Sdim bool keep_in_memory, 1042314564Sdim PersistentVariableDelegate *delegate, 1043321369Sdim Status &err) { 1044314564Sdim EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP()); 1045314564Sdim iter->reset(new EntityResultVariable(type, is_program_reference, 1046314564Sdim keep_in_memory, delegate)); 1047314564Sdim uint32_t ret = AddStructMember(**iter); 1048314564Sdim (*iter)->SetOffset(ret); 1049314564Sdim return ret; 1050254721Semaste} 1051254721Semaste 1052314564Sdimclass EntitySymbol : public Materializer::Entity { 1053254721Semastepublic: 1054314564Sdim EntitySymbol(const Symbol &symbol) : Entity(), m_symbol(symbol) { 1055314564Sdim // Hard-coding to maximum size of a symbol 1056314564Sdim m_size = 8; 1057314564Sdim m_alignment = 8; 1058314564Sdim } 1059309124Sdim 1060314564Sdim void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 1061321369Sdim lldb::addr_t process_address, Status &err) override { 1062314564Sdim Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); 1063254721Semaste 1064314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 1065254721Semaste 1066314564Sdim if (log) { 1067314564Sdim log->Printf("EntitySymbol::Materialize [address = 0x%" PRIx64 1068314564Sdim ", m_symbol = %s]", 1069314564Sdim (uint64_t)load_addr, m_symbol.GetName().AsCString()); 1070314564Sdim } 1071309124Sdim 1072314564Sdim const Address sym_address = m_symbol.GetAddress(); 1073254721Semaste 1074314564Sdim ExecutionContextScope *exe_scope = map.GetBestExecutionContextScope(); 1075309124Sdim 1076314564Sdim lldb::TargetSP target_sp; 1077309124Sdim 1078314564Sdim if (exe_scope) 1079314564Sdim target_sp = map.GetBestExecutionContextScope()->CalculateTarget(); 1080309124Sdim 1081314564Sdim if (!target_sp) { 1082314564Sdim err.SetErrorStringWithFormat( 1083314564Sdim "couldn't resolve symbol %s because there is no target", 1084314564Sdim m_symbol.GetName().AsCString()); 1085314564Sdim return; 1086314564Sdim } 1087309124Sdim 1088314564Sdim lldb::addr_t resolved_address = sym_address.GetLoadAddress(target_sp.get()); 1089309124Sdim 1090314564Sdim if (resolved_address == LLDB_INVALID_ADDRESS) 1091314564Sdim resolved_address = sym_address.GetFileAddress(); 1092309124Sdim 1093321369Sdim Status pointer_write_error; 1094309124Sdim 1095314564Sdim map.WritePointerToMemory(load_addr, resolved_address, pointer_write_error); 1096309124Sdim 1097314564Sdim if (!pointer_write_error.Success()) { 1098314564Sdim err.SetErrorStringWithFormat( 1099314564Sdim "couldn't write the address of symbol %s: %s", 1100314564Sdim m_symbol.GetName().AsCString(), pointer_write_error.AsCString()); 1101314564Sdim return; 1102254721Semaste } 1103314564Sdim } 1104309124Sdim 1105314564Sdim void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 1106314564Sdim lldb::addr_t process_address, lldb::addr_t frame_top, 1107321369Sdim lldb::addr_t frame_bottom, Status &err) override { 1108314564Sdim Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); 1109254721Semaste 1110314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 1111254721Semaste 1112314564Sdim if (log) { 1113314564Sdim log->Printf("EntitySymbol::Dematerialize [address = 0x%" PRIx64 1114314564Sdim ", m_symbol = %s]", 1115314564Sdim (uint64_t)load_addr, m_symbol.GetName().AsCString()); 1116254721Semaste } 1117309124Sdim 1118314564Sdim // no work needs to be done 1119314564Sdim } 1120309124Sdim 1121314564Sdim void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address, 1122314564Sdim Log *log) override { 1123314564Sdim StreamString dump_stream; 1124309124Sdim 1125321369Sdim Status err; 1126254721Semaste 1127314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 1128309124Sdim 1129314564Sdim dump_stream.Printf("0x%" PRIx64 ": EntitySymbol (%s)\n", load_addr, 1130314564Sdim m_symbol.GetName().AsCString()); 1131309124Sdim 1132314564Sdim { 1133314564Sdim dump_stream.Printf("Pointer:\n"); 1134309124Sdim 1135314564Sdim DataBufferHeap data(m_size, 0); 1136309124Sdim 1137314564Sdim map.ReadMemory(data.GetBytes(), load_addr, m_size, err); 1138309124Sdim 1139314564Sdim if (!err.Success()) { 1140314564Sdim dump_stream.Printf(" <could not be read>\n"); 1141314564Sdim } else { 1142321369Sdim DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, 1143321369Sdim load_addr); 1144309124Sdim 1145314564Sdim dump_stream.PutChar('\n'); 1146314564Sdim } 1147254721Semaste } 1148309124Sdim 1149314564Sdim log->PutString(dump_stream.GetString()); 1150314564Sdim } 1151296417Sdim 1152314564Sdim void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {} 1153314564Sdim 1154254721Semasteprivate: 1155314564Sdim Symbol m_symbol; 1156254721Semaste}; 1157254721Semaste 1158321369Sdimuint32_t Materializer::AddSymbol(const Symbol &symbol_sp, Status &err) { 1159314564Sdim EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP()); 1160314564Sdim iter->reset(new EntitySymbol(symbol_sp)); 1161314564Sdim uint32_t ret = AddStructMember(**iter); 1162314564Sdim (*iter)->SetOffset(ret); 1163314564Sdim return ret; 1164254721Semaste} 1165254721Semaste 1166314564Sdimclass EntityRegister : public Materializer::Entity { 1167254721Semastepublic: 1168314564Sdim EntityRegister(const RegisterInfo ®ister_info) 1169314564Sdim : Entity(), m_register_info(register_info) { 1170314564Sdim // Hard-coding alignment conservatively 1171314564Sdim m_size = m_register_info.byte_size; 1172314564Sdim m_alignment = m_register_info.byte_size; 1173314564Sdim } 1174314564Sdim 1175314564Sdim void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 1176321369Sdim lldb::addr_t process_address, Status &err) override { 1177314564Sdim Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); 1178314564Sdim 1179314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 1180314564Sdim 1181314564Sdim if (log) { 1182314564Sdim log->Printf("EntityRegister::Materialize [address = 0x%" PRIx64 1183314564Sdim ", m_register_info = %s]", 1184314564Sdim (uint64_t)load_addr, m_register_info.name); 1185254721Semaste } 1186309124Sdim 1187314564Sdim RegisterValue reg_value; 1188309124Sdim 1189314564Sdim if (!frame_sp.get()) { 1190314564Sdim err.SetErrorStringWithFormat( 1191314564Sdim "couldn't materialize register %s without a stack frame", 1192314564Sdim m_register_info.name); 1193314564Sdim return; 1194314564Sdim } 1195254721Semaste 1196314564Sdim lldb::RegisterContextSP reg_context_sp = frame_sp->GetRegisterContext(); 1197254721Semaste 1198314564Sdim if (!reg_context_sp->ReadRegister(&m_register_info, reg_value)) { 1199314564Sdim err.SetErrorStringWithFormat("couldn't read the value of register %s", 1200314564Sdim m_register_info.name); 1201314564Sdim return; 1202314564Sdim } 1203309124Sdim 1204314564Sdim DataExtractor register_data; 1205309124Sdim 1206314564Sdim if (!reg_value.GetData(register_data)) { 1207314564Sdim err.SetErrorStringWithFormat("couldn't get the data for register %s", 1208314564Sdim m_register_info.name); 1209314564Sdim return; 1210314564Sdim } 1211309124Sdim 1212314564Sdim if (register_data.GetByteSize() != m_register_info.byte_size) { 1213314564Sdim err.SetErrorStringWithFormat( 1214314564Sdim "data for register %s had size %llu but we expected %llu", 1215314564Sdim m_register_info.name, (unsigned long long)register_data.GetByteSize(), 1216314564Sdim (unsigned long long)m_register_info.byte_size); 1217314564Sdim return; 1218314564Sdim } 1219309124Sdim 1220353358Sdim m_register_contents = std::make_shared<DataBufferHeap>( 1221353358Sdim register_data.GetDataStart(), register_data.GetByteSize()); 1222309124Sdim 1223321369Sdim Status write_error; 1224309124Sdim 1225314564Sdim map.WriteMemory(load_addr, register_data.GetDataStart(), 1226314564Sdim register_data.GetByteSize(), write_error); 1227309124Sdim 1228314564Sdim if (!write_error.Success()) { 1229314564Sdim err.SetErrorStringWithFormat( 1230314564Sdim "couldn't write the contents of register %s: %s", 1231314564Sdim m_register_info.name, write_error.AsCString()); 1232314564Sdim return; 1233254721Semaste } 1234314564Sdim } 1235309124Sdim 1236314564Sdim void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 1237314564Sdim lldb::addr_t process_address, lldb::addr_t frame_top, 1238321369Sdim lldb::addr_t frame_bottom, Status &err) override { 1239314564Sdim Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); 1240309124Sdim 1241314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 1242254721Semaste 1243314564Sdim if (log) { 1244314564Sdim log->Printf("EntityRegister::Dematerialize [address = 0x%" PRIx64 1245314564Sdim ", m_register_info = %s]", 1246314564Sdim (uint64_t)load_addr, m_register_info.name); 1247314564Sdim } 1248309124Sdim 1249321369Sdim Status extract_error; 1250309124Sdim 1251314564Sdim DataExtractor register_data; 1252309124Sdim 1253314564Sdim if (!frame_sp.get()) { 1254314564Sdim err.SetErrorStringWithFormat( 1255314564Sdim "couldn't dematerialize register %s without a stack frame", 1256314564Sdim m_register_info.name); 1257314564Sdim return; 1258314564Sdim } 1259309124Sdim 1260314564Sdim lldb::RegisterContextSP reg_context_sp = frame_sp->GetRegisterContext(); 1261309124Sdim 1262314564Sdim map.GetMemoryData(register_data, load_addr, m_register_info.byte_size, 1263314564Sdim extract_error); 1264309124Sdim 1265314564Sdim if (!extract_error.Success()) { 1266314564Sdim err.SetErrorStringWithFormat("couldn't get the data for register %s: %s", 1267314564Sdim m_register_info.name, 1268314564Sdim extract_error.AsCString()); 1269314564Sdim return; 1270314564Sdim } 1271309124Sdim 1272314564Sdim if (!memcmp(register_data.GetDataStart(), m_register_contents->GetBytes(), 1273314564Sdim register_data.GetByteSize())) { 1274314564Sdim // No write required, and in particular we avoid errors if the register 1275314564Sdim // wasn't writable 1276309124Sdim 1277314564Sdim m_register_contents.reset(); 1278314564Sdim return; 1279314564Sdim } 1280309124Sdim 1281314564Sdim m_register_contents.reset(); 1282309124Sdim 1283314564Sdim RegisterValue register_value( 1284314564Sdim const_cast<uint8_t *>(register_data.GetDataStart()), 1285314564Sdim register_data.GetByteSize(), register_data.GetByteOrder()); 1286309124Sdim 1287314564Sdim if (!reg_context_sp->WriteRegister(&m_register_info, register_value)) { 1288314564Sdim err.SetErrorStringWithFormat("couldn't write the value of register %s", 1289314564Sdim m_register_info.name); 1290314564Sdim return; 1291254721Semaste } 1292314564Sdim } 1293309124Sdim 1294314564Sdim void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address, 1295314564Sdim Log *log) override { 1296314564Sdim StreamString dump_stream; 1297309124Sdim 1298321369Sdim Status err; 1299309124Sdim 1300314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 1301254721Semaste 1302314564Sdim dump_stream.Printf("0x%" PRIx64 ": EntityRegister (%s)\n", load_addr, 1303314564Sdim m_register_info.name); 1304309124Sdim 1305314564Sdim { 1306314564Sdim dump_stream.Printf("Value:\n"); 1307309124Sdim 1308314564Sdim DataBufferHeap data(m_size, 0); 1309309124Sdim 1310314564Sdim map.ReadMemory(data.GetBytes(), load_addr, m_size, err); 1311309124Sdim 1312314564Sdim if (!err.Success()) { 1313314564Sdim dump_stream.Printf(" <could not be read>\n"); 1314314564Sdim } else { 1315321369Sdim DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, 1316321369Sdim load_addr); 1317309124Sdim 1318314564Sdim dump_stream.PutChar('\n'); 1319314564Sdim } 1320314564Sdim } 1321309124Sdim 1322314564Sdim log->PutString(dump_stream.GetString()); 1323314564Sdim } 1324309124Sdim 1325314564Sdim void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {} 1326309124Sdim 1327254721Semasteprivate: 1328314564Sdim RegisterInfo m_register_info; 1329314564Sdim lldb::DataBufferSP m_register_contents; 1330254721Semaste}; 1331254721Semaste 1332314564Sdimuint32_t Materializer::AddRegister(const RegisterInfo ®ister_info, 1333321369Sdim Status &err) { 1334314564Sdim EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP()); 1335314564Sdim iter->reset(new EntityRegister(register_info)); 1336314564Sdim uint32_t ret = AddStructMember(**iter); 1337314564Sdim (*iter)->SetOffset(ret); 1338314564Sdim return ret; 1339254721Semaste} 1340254721Semaste 1341314564SdimMaterializer::Materializer() 1342314564Sdim : m_dematerializer_wp(), m_current_offset(0), m_struct_alignment(8) {} 1343254721Semaste 1344314564SdimMaterializer::~Materializer() { 1345314564Sdim DematerializerSP dematerializer_sp = m_dematerializer_wp.lock(); 1346309124Sdim 1347314564Sdim if (dematerializer_sp) 1348314564Sdim dematerializer_sp->Wipe(); 1349254721Semaste} 1350254721Semaste 1351254721SemasteMaterializer::DematerializerSP 1352314564SdimMaterializer::Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 1353321369Sdim lldb::addr_t process_address, Status &error) { 1354314564Sdim ExecutionContextScope *exe_scope = frame_sp.get(); 1355276479Sdim 1356314564Sdim if (!exe_scope) 1357314564Sdim exe_scope = map.GetBestExecutionContextScope(); 1358276479Sdim 1359314564Sdim DematerializerSP dematerializer_sp = m_dematerializer_wp.lock(); 1360276479Sdim 1361314564Sdim if (dematerializer_sp) { 1362314564Sdim error.SetErrorToGenericError(); 1363314564Sdim error.SetErrorString("Couldn't materialize: already materialized"); 1364314564Sdim } 1365276479Sdim 1366314564Sdim DematerializerSP ret( 1367314564Sdim new Dematerializer(*this, frame_sp, map, process_address)); 1368276479Sdim 1369314564Sdim if (!exe_scope) { 1370314564Sdim error.SetErrorToGenericError(); 1371314564Sdim error.SetErrorString("Couldn't materialize: target doesn't exist"); 1372314564Sdim } 1373276479Sdim 1374314564Sdim for (EntityUP &entity_up : m_entities) { 1375314564Sdim entity_up->Materialize(frame_sp, map, process_address, error); 1376276479Sdim 1377314564Sdim if (!error.Success()) 1378314564Sdim return DematerializerSP(); 1379314564Sdim } 1380276479Sdim 1381314564Sdim if (Log *log = 1382314564Sdim lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)) { 1383314564Sdim log->Printf( 1384314564Sdim "Materializer::Materialize (frame_sp = %p, process_address = 0x%" PRIx64 1385314564Sdim ") materialized:", 1386314564Sdim static_cast<void *>(frame_sp.get()), process_address); 1387314564Sdim for (EntityUP &entity_up : m_entities) 1388314564Sdim entity_up->DumpToLog(map, process_address, log); 1389314564Sdim } 1390276479Sdim 1391314564Sdim m_dematerializer_wp = ret; 1392276479Sdim 1393314564Sdim return ret; 1394254721Semaste} 1395254721Semaste 1396321369Sdimvoid Materializer::Dematerializer::Dematerialize(Status &error, 1397314564Sdim lldb::addr_t frame_bottom, 1398314564Sdim lldb::addr_t frame_top) { 1399314564Sdim lldb::StackFrameSP frame_sp; 1400254721Semaste 1401314564Sdim lldb::ThreadSP thread_sp = m_thread_wp.lock(); 1402314564Sdim if (thread_sp) 1403314564Sdim frame_sp = thread_sp->GetFrameWithStackID(m_stack_id); 1404276479Sdim 1405314564Sdim ExecutionContextScope *exe_scope = m_map->GetBestExecutionContextScope(); 1406276479Sdim 1407314564Sdim if (!IsValid()) { 1408314564Sdim error.SetErrorToGenericError(); 1409314564Sdim error.SetErrorString("Couldn't dematerialize: invalid dematerializer"); 1410314564Sdim } 1411276479Sdim 1412314564Sdim if (!exe_scope) { 1413314564Sdim error.SetErrorToGenericError(); 1414314564Sdim error.SetErrorString("Couldn't dematerialize: target is gone"); 1415314564Sdim } else { 1416314564Sdim if (Log *log = 1417314564Sdim lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)) { 1418314564Sdim log->Printf("Materializer::Dematerialize (frame_sp = %p, process_address " 1419314564Sdim "= 0x%" PRIx64 ") about to dematerialize:", 1420314564Sdim static_cast<void *>(frame_sp.get()), m_process_address); 1421314564Sdim for (EntityUP &entity_up : m_materializer->m_entities) 1422314564Sdim entity_up->DumpToLog(*m_map, m_process_address, log); 1423254721Semaste } 1424276479Sdim 1425314564Sdim for (EntityUP &entity_up : m_materializer->m_entities) { 1426314564Sdim entity_up->Dematerialize(frame_sp, *m_map, m_process_address, frame_top, 1427314564Sdim frame_bottom, error); 1428276479Sdim 1429314564Sdim if (!error.Success()) 1430314564Sdim break; 1431254721Semaste } 1432314564Sdim } 1433276479Sdim 1434314564Sdim Wipe(); 1435254721Semaste} 1436254721Semaste 1437314564Sdimvoid Materializer::Dematerializer::Wipe() { 1438314564Sdim if (!IsValid()) 1439314564Sdim return; 1440309124Sdim 1441314564Sdim for (EntityUP &entity_up : m_materializer->m_entities) { 1442314564Sdim entity_up->Wipe(*m_map, m_process_address); 1443314564Sdim } 1444254721Semaste 1445314564Sdim m_materializer = nullptr; 1446314564Sdim m_map = nullptr; 1447314564Sdim m_process_address = LLDB_INVALID_ADDRESS; 1448254721Semaste} 1449296417Sdim 1450314564SdimMaterializer::PersistentVariableDelegate::~PersistentVariableDelegate() = 1451314564Sdim default; 1452