Materializer.cpp revision 321369
1254721Semaste//===-- Materializer.cpp ----------------------------------------*- C++ -*-===// 2254721Semaste// 3254721Semaste// The LLVM Compiler Infrastructure 4254721Semaste// 5254721Semaste// This file is distributed under the University of Illinois Open Source 6254721Semaste// License. See LICENSE.TXT for details. 7254721Semaste// 8254721Semaste//===----------------------------------------------------------------------===// 9254721Semaste 10296417Sdim// C Includes 11296417Sdim// C++ Includes 12296417Sdim// Other libraries and framework includes 13296417Sdim// Project includes 14314564Sdim#include "lldb/Expression/Materializer.h" 15321369Sdim#include "lldb/Core/DumpDataExtractor.h" 16254721Semaste#include "lldb/Core/RegisterValue.h" 17254721Semaste#include "lldb/Core/ValueObjectConstResult.h" 18254721Semaste#include "lldb/Core/ValueObjectVariable.h" 19296417Sdim#include "lldb/Expression/ExpressionVariable.h" 20254721Semaste#include "lldb/Symbol/ClangASTContext.h" 21254721Semaste#include "lldb/Symbol/Symbol.h" 22254721Semaste#include "lldb/Symbol/Type.h" 23254721Semaste#include "lldb/Symbol/Variable.h" 24254721Semaste#include "lldb/Target/ExecutionContext.h" 25254721Semaste#include "lldb/Target/RegisterContext.h" 26254721Semaste#include "lldb/Target/StackFrame.h" 27254721Semaste#include "lldb/Target/Target.h" 28254721Semaste#include "lldb/Target/Thread.h" 29321369Sdim#include "lldb/Utility/Log.h" 30254721Semaste 31254721Semasteusing namespace lldb_private; 32254721Semaste 33314564Sdimuint32_t Materializer::AddStructMember(Entity &entity) { 34314564Sdim uint32_t size = entity.GetSize(); 35314564Sdim uint32_t alignment = entity.GetAlignment(); 36309124Sdim 37314564Sdim uint32_t ret; 38309124Sdim 39314564Sdim if (m_current_offset == 0) 40314564Sdim m_struct_alignment = alignment; 41309124Sdim 42314564Sdim if (m_current_offset % alignment) 43314564Sdim m_current_offset += (alignment - (m_current_offset % alignment)); 44309124Sdim 45314564Sdim ret = m_current_offset; 46309124Sdim 47314564Sdim m_current_offset += size; 48309124Sdim 49314564Sdim return ret; 50254721Semaste} 51254721Semaste 52314564Sdimvoid Materializer::Entity::SetSizeAndAlignmentFromType(CompilerType &type) { 53314564Sdim m_size = type.GetByteSize(nullptr); 54309124Sdim 55314564Sdim uint32_t bit_alignment = type.GetTypeBitAlign(); 56309124Sdim 57314564Sdim if (bit_alignment % 8) { 58314564Sdim bit_alignment += 8; 59314564Sdim bit_alignment &= ~((uint32_t)0x111u); 60314564Sdim } 61309124Sdim 62314564Sdim m_alignment = bit_alignment / 8; 63254721Semaste} 64254721Semaste 65314564Sdimclass EntityPersistentVariable : public Materializer::Entity { 66254721Semastepublic: 67314564Sdim EntityPersistentVariable(lldb::ExpressionVariableSP &persistent_variable_sp, 68314564Sdim Materializer::PersistentVariableDelegate *delegate) 69314564Sdim : Entity(), m_persistent_variable_sp(persistent_variable_sp), 70314564Sdim m_delegate(delegate) { 71314564Sdim // Hard-coding to maximum size of a pointer since persistent variables are 72314564Sdim // materialized by reference 73314564Sdim m_size = 8; 74314564Sdim m_alignment = 8; 75314564Sdim } 76309124Sdim 77321369Sdim void MakeAllocation(IRMemoryMap &map, Status &err) { 78314564Sdim Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); 79254721Semaste 80314564Sdim // Allocate a spare memory area to store the persistent variable's contents. 81309124Sdim 82321369Sdim Status allocate_error; 83314564Sdim const bool zero_memory = false; 84309124Sdim 85314564Sdim lldb::addr_t mem = map.Malloc( 86314564Sdim m_persistent_variable_sp->GetByteSize(), 8, 87314564Sdim lldb::ePermissionsReadable | lldb::ePermissionsWritable, 88314564Sdim IRMemoryMap::eAllocationPolicyMirror, zero_memory, allocate_error); 89309124Sdim 90314564Sdim if (!allocate_error.Success()) { 91314564Sdim err.SetErrorStringWithFormat( 92314564Sdim "couldn't allocate a memory area to store %s: %s", 93314564Sdim m_persistent_variable_sp->GetName().GetCString(), 94314564Sdim allocate_error.AsCString()); 95314564Sdim return; 96314564Sdim } 97309124Sdim 98314564Sdim if (log) 99314564Sdim log->Printf("Allocated %s (0x%" PRIx64 ") successfully", 100314564Sdim m_persistent_variable_sp->GetName().GetCString(), mem); 101309124Sdim 102314564Sdim // Put the location of the spare memory into the live data of the 103314564Sdim // ValueObject. 104309124Sdim 105314564Sdim m_persistent_variable_sp->m_live_sp = ValueObjectConstResult::Create( 106314564Sdim map.GetBestExecutionContextScope(), 107314564Sdim m_persistent_variable_sp->GetCompilerType(), 108314564Sdim m_persistent_variable_sp->GetName(), mem, eAddressTypeLoad, 109314564Sdim map.GetAddressByteSize()); 110309124Sdim 111314564Sdim // Clear the flag if the variable will never be deallocated. 112309124Sdim 113314564Sdim if (m_persistent_variable_sp->m_flags & 114314564Sdim ExpressionVariable::EVKeepInTarget) { 115321369Sdim Status leak_error; 116314564Sdim map.Leak(mem, leak_error); 117314564Sdim m_persistent_variable_sp->m_flags &= 118314564Sdim ~ExpressionVariable::EVNeedsAllocation; 119314564Sdim } 120309124Sdim 121314564Sdim // Write the contents of the variable to the area. 122309124Sdim 123321369Sdim Status write_error; 124309124Sdim 125314564Sdim map.WriteMemory(mem, m_persistent_variable_sp->GetValueBytes(), 126314564Sdim m_persistent_variable_sp->GetByteSize(), write_error); 127309124Sdim 128314564Sdim if (!write_error.Success()) { 129314564Sdim err.SetErrorStringWithFormat( 130314564Sdim "couldn't write %s to the target: %s", 131314564Sdim m_persistent_variable_sp->GetName().AsCString(), 132314564Sdim write_error.AsCString()); 133314564Sdim return; 134254721Semaste } 135314564Sdim } 136309124Sdim 137321369Sdim void DestroyAllocation(IRMemoryMap &map, Status &err) { 138321369Sdim Status deallocate_error; 139309124Sdim 140314564Sdim map.Free((lldb::addr_t)m_persistent_variable_sp->m_live_sp->GetValue() 141314564Sdim .GetScalar() 142314564Sdim .ULongLong(), 143314564Sdim deallocate_error); 144309124Sdim 145314564Sdim m_persistent_variable_sp->m_live_sp.reset(); 146309124Sdim 147314564Sdim if (!deallocate_error.Success()) { 148314564Sdim err.SetErrorStringWithFormat( 149314564Sdim "couldn't deallocate memory for %s: %s", 150314564Sdim m_persistent_variable_sp->GetName().GetCString(), 151314564Sdim deallocate_error.AsCString()); 152254721Semaste } 153314564Sdim } 154309124Sdim 155314564Sdim void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 156321369Sdim lldb::addr_t process_address, Status &err) override { 157314564Sdim Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); 158254721Semaste 159314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 160309124Sdim 161314564Sdim if (log) { 162314564Sdim log->Printf("EntityPersistentVariable::Materialize [address = 0x%" PRIx64 163314564Sdim ", m_name = %s, m_flags = 0x%hx]", 164314564Sdim (uint64_t)load_addr, 165314564Sdim m_persistent_variable_sp->GetName().AsCString(), 166314564Sdim m_persistent_variable_sp->m_flags); 167314564Sdim } 168309124Sdim 169314564Sdim if (m_persistent_variable_sp->m_flags & 170314564Sdim ExpressionVariable::EVNeedsAllocation) { 171314564Sdim MakeAllocation(map, err); 172314564Sdim m_persistent_variable_sp->m_flags |= 173314564Sdim ExpressionVariable::EVIsLLDBAllocated; 174309124Sdim 175314564Sdim if (!err.Success()) 176314564Sdim return; 177314564Sdim } 178309124Sdim 179314564Sdim if ((m_persistent_variable_sp->m_flags & 180314564Sdim ExpressionVariable::EVIsProgramReference && 181314564Sdim m_persistent_variable_sp->m_live_sp) || 182314564Sdim m_persistent_variable_sp->m_flags & 183314564Sdim ExpressionVariable::EVIsLLDBAllocated) { 184321369Sdim Status write_error; 185309124Sdim 186314564Sdim map.WriteScalarToMemory( 187314564Sdim load_addr, 188314564Sdim m_persistent_variable_sp->m_live_sp->GetValue().GetScalar(), 189314564Sdim map.GetAddressByteSize(), write_error); 190309124Sdim 191314564Sdim if (!write_error.Success()) { 192314564Sdim err.SetErrorStringWithFormat( 193314564Sdim "couldn't write the location of %s to memory: %s", 194314564Sdim m_persistent_variable_sp->GetName().AsCString(), 195314564Sdim write_error.AsCString()); 196314564Sdim } 197314564Sdim } else { 198314564Sdim err.SetErrorStringWithFormat( 199314564Sdim "no materialization happened for persistent variable %s", 200314564Sdim m_persistent_variable_sp->GetName().AsCString()); 201314564Sdim return; 202254721Semaste } 203314564Sdim } 204309124Sdim 205314564Sdim void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 206314564Sdim lldb::addr_t process_address, lldb::addr_t frame_top, 207321369Sdim lldb::addr_t frame_bottom, Status &err) override { 208314564Sdim Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); 209309124Sdim 210314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 211254721Semaste 212314564Sdim if (log) { 213314564Sdim log->Printf( 214314564Sdim "EntityPersistentVariable::Dematerialize [address = 0x%" PRIx64 215314564Sdim ", m_name = %s, m_flags = 0x%hx]", 216314564Sdim (uint64_t)process_address + m_offset, 217314564Sdim m_persistent_variable_sp->GetName().AsCString(), 218314564Sdim m_persistent_variable_sp->m_flags); 219314564Sdim } 220309124Sdim 221314564Sdim if (m_delegate) { 222314564Sdim m_delegate->DidDematerialize(m_persistent_variable_sp); 223314564Sdim } 224296417Sdim 225314564Sdim if ((m_persistent_variable_sp->m_flags & 226314564Sdim ExpressionVariable::EVIsLLDBAllocated) || 227314564Sdim (m_persistent_variable_sp->m_flags & 228314564Sdim ExpressionVariable::EVIsProgramReference)) { 229314564Sdim if (m_persistent_variable_sp->m_flags & 230314564Sdim ExpressionVariable::EVIsProgramReference && 231314564Sdim !m_persistent_variable_sp->m_live_sp) { 232314564Sdim // If the reference comes from the program, then the 233314564Sdim // ClangExpressionVariable's 234314564Sdim // live variable data hasn't been set up yet. Do this now. 235309124Sdim 236314564Sdim lldb::addr_t location; 237321369Sdim Status read_error; 238309124Sdim 239314564Sdim map.ReadPointerFromMemory(&location, load_addr, read_error); 240309124Sdim 241314564Sdim if (!read_error.Success()) { 242314564Sdim err.SetErrorStringWithFormat( 243314564Sdim "couldn't read the address of program-allocated variable %s: %s", 244314564Sdim m_persistent_variable_sp->GetName().GetCString(), 245314564Sdim read_error.AsCString()); 246314564Sdim return; 247314564Sdim } 248309124Sdim 249314564Sdim m_persistent_variable_sp->m_live_sp = ValueObjectConstResult::Create( 250314564Sdim map.GetBestExecutionContextScope(), 251314564Sdim m_persistent_variable_sp.get()->GetCompilerType(), 252314564Sdim m_persistent_variable_sp->GetName(), location, eAddressTypeLoad, 253314564Sdim m_persistent_variable_sp->GetByteSize()); 254309124Sdim 255314564Sdim if (frame_top != LLDB_INVALID_ADDRESS && 256314564Sdim frame_bottom != LLDB_INVALID_ADDRESS && location >= frame_bottom && 257314564Sdim location <= frame_top) { 258314564Sdim // If the variable is resident in the stack frame created by the 259314564Sdim // expression, 260314564Sdim // then it cannot be relied upon to stay around. We treat it as 261314564Sdim // needing 262314564Sdim // reallocation. 263314564Sdim m_persistent_variable_sp->m_flags |= 264314564Sdim ExpressionVariable::EVIsLLDBAllocated; 265314564Sdim m_persistent_variable_sp->m_flags |= 266314564Sdim ExpressionVariable::EVNeedsAllocation; 267314564Sdim m_persistent_variable_sp->m_flags |= 268314564Sdim ExpressionVariable::EVNeedsFreezeDry; 269314564Sdim m_persistent_variable_sp->m_flags &= 270314564Sdim ~ExpressionVariable::EVIsProgramReference; 271314564Sdim } 272314564Sdim } 273309124Sdim 274314564Sdim lldb::addr_t mem = m_persistent_variable_sp->m_live_sp->GetValue() 275314564Sdim .GetScalar() 276314564Sdim .ULongLong(); 277309124Sdim 278314564Sdim if (!m_persistent_variable_sp->m_live_sp) { 279314564Sdim err.SetErrorStringWithFormat( 280314564Sdim "couldn't find the memory area used to store %s", 281314564Sdim m_persistent_variable_sp->GetName().GetCString()); 282314564Sdim return; 283314564Sdim } 284309124Sdim 285314564Sdim if (m_persistent_variable_sp->m_live_sp->GetValue() 286314564Sdim .GetValueAddressType() != eAddressTypeLoad) { 287314564Sdim err.SetErrorStringWithFormat( 288314564Sdim "the address of the memory area for %s is in an incorrect format", 289314564Sdim m_persistent_variable_sp->GetName().GetCString()); 290314564Sdim return; 291314564Sdim } 292309124Sdim 293314564Sdim if (m_persistent_variable_sp->m_flags & 294314564Sdim ExpressionVariable::EVNeedsFreezeDry || 295314564Sdim m_persistent_variable_sp->m_flags & 296314564Sdim ExpressionVariable::EVKeepInTarget) { 297314564Sdim if (log) 298314564Sdim log->Printf( 299314564Sdim "Dematerializing %s from 0x%" PRIx64 " (size = %llu)", 300314564Sdim m_persistent_variable_sp->GetName().GetCString(), (uint64_t)mem, 301314564Sdim (unsigned long long)m_persistent_variable_sp->GetByteSize()); 302309124Sdim 303314564Sdim // Read the contents of the spare memory area 304309124Sdim 305314564Sdim m_persistent_variable_sp->ValueUpdated(); 306309124Sdim 307321369Sdim Status read_error; 308309124Sdim 309314564Sdim map.ReadMemory(m_persistent_variable_sp->GetValueBytes(), mem, 310314564Sdim m_persistent_variable_sp->GetByteSize(), read_error); 311309124Sdim 312314564Sdim if (!read_error.Success()) { 313314564Sdim err.SetErrorStringWithFormat( 314314564Sdim "couldn't read the contents of %s from memory: %s", 315314564Sdim m_persistent_variable_sp->GetName().GetCString(), 316314564Sdim read_error.AsCString()); 317314564Sdim return; 318254721Semaste } 319309124Sdim 320314564Sdim m_persistent_variable_sp->m_flags &= 321314564Sdim ~ExpressionVariable::EVNeedsFreezeDry; 322314564Sdim } 323314564Sdim } else { 324314564Sdim err.SetErrorStringWithFormat( 325314564Sdim "no dematerialization happened for persistent variable %s", 326314564Sdim m_persistent_variable_sp->GetName().AsCString()); 327314564Sdim return; 328314564Sdim } 329309124Sdim 330314564Sdim lldb::ProcessSP process_sp = 331314564Sdim map.GetBestExecutionContextScope()->CalculateProcess(); 332314564Sdim if (!process_sp || !process_sp->CanJIT()) { 333314564Sdim // Allocations are not persistent so persistent variables cannot stay 334314564Sdim // materialized. 335254721Semaste 336314564Sdim m_persistent_variable_sp->m_flags |= 337314564Sdim ExpressionVariable::EVNeedsAllocation; 338314564Sdim 339314564Sdim DestroyAllocation(map, err); 340314564Sdim if (!err.Success()) 341314564Sdim return; 342314564Sdim } else if (m_persistent_variable_sp->m_flags & 343314564Sdim ExpressionVariable::EVNeedsAllocation && 344314564Sdim !(m_persistent_variable_sp->m_flags & 345314564Sdim ExpressionVariable::EVKeepInTarget)) { 346314564Sdim DestroyAllocation(map, err); 347314564Sdim if (!err.Success()) 348314564Sdim return; 349254721Semaste } 350314564Sdim } 351309124Sdim 352314564Sdim void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address, 353314564Sdim Log *log) override { 354314564Sdim StreamString dump_stream; 355309124Sdim 356321369Sdim Status err; 357309124Sdim 358314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 359254721Semaste 360314564Sdim dump_stream.Printf("0x%" PRIx64 ": EntityPersistentVariable (%s)\n", 361314564Sdim load_addr, 362314564Sdim m_persistent_variable_sp->GetName().AsCString()); 363309124Sdim 364314564Sdim { 365314564Sdim dump_stream.Printf("Pointer:\n"); 366309124Sdim 367314564Sdim DataBufferHeap data(m_size, 0); 368309124Sdim 369314564Sdim map.ReadMemory(data.GetBytes(), load_addr, m_size, err); 370309124Sdim 371314564Sdim if (!err.Success()) { 372314564Sdim dump_stream.Printf(" <could not be read>\n"); 373314564Sdim } else { 374321369Sdim DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, 375321369Sdim load_addr); 376309124Sdim 377314564Sdim dump_stream.PutChar('\n'); 378314564Sdim } 379314564Sdim } 380309124Sdim 381314564Sdim { 382314564Sdim dump_stream.Printf("Target:\n"); 383309124Sdim 384314564Sdim lldb::addr_t target_address; 385309124Sdim 386314564Sdim map.ReadPointerFromMemory(&target_address, load_addr, err); 387309124Sdim 388314564Sdim if (!err.Success()) { 389314564Sdim dump_stream.Printf(" <could not be read>\n"); 390314564Sdim } else { 391314564Sdim DataBufferHeap data(m_persistent_variable_sp->GetByteSize(), 0); 392309124Sdim 393314564Sdim map.ReadMemory(data.GetBytes(), target_address, 394314564Sdim m_persistent_variable_sp->GetByteSize(), err); 395309124Sdim 396314564Sdim if (!err.Success()) { 397314564Sdim dump_stream.Printf(" <could not be read>\n"); 398314564Sdim } else { 399321369Sdim DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, 400321369Sdim target_address); 401309124Sdim 402314564Sdim dump_stream.PutChar('\n'); 403254721Semaste } 404314564Sdim } 405254721Semaste } 406309124Sdim 407314564Sdim log->PutString(dump_stream.GetString()); 408314564Sdim } 409296417Sdim 410314564Sdim void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {} 411314564Sdim 412254721Semasteprivate: 413314564Sdim lldb::ExpressionVariableSP m_persistent_variable_sp; 414314564Sdim Materializer::PersistentVariableDelegate *m_delegate; 415254721Semaste}; 416254721Semaste 417314564Sdimuint32_t Materializer::AddPersistentVariable( 418314564Sdim lldb::ExpressionVariableSP &persistent_variable_sp, 419321369Sdim PersistentVariableDelegate *delegate, Status &err) { 420314564Sdim EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP()); 421314564Sdim iter->reset(new EntityPersistentVariable(persistent_variable_sp, delegate)); 422314564Sdim uint32_t ret = AddStructMember(**iter); 423314564Sdim (*iter)->SetOffset(ret); 424314564Sdim return ret; 425254721Semaste} 426254721Semaste 427314564Sdimclass EntityVariable : public Materializer::Entity { 428254721Semastepublic: 429314564Sdim EntityVariable(lldb::VariableSP &variable_sp) 430314564Sdim : Entity(), m_variable_sp(variable_sp), m_is_reference(false), 431254721Semaste m_temporary_allocation(LLDB_INVALID_ADDRESS), 432314564Sdim m_temporary_allocation_size(0) { 433314564Sdim // Hard-coding to maximum size of a pointer since all variables are 434314564Sdim // materialized by reference 435314564Sdim m_size = 8; 436314564Sdim m_alignment = 8; 437314564Sdim m_is_reference = 438314564Sdim m_variable_sp->GetType()->GetForwardCompilerType().IsReferenceType(); 439314564Sdim } 440314564Sdim 441314564Sdim void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 442321369Sdim lldb::addr_t process_address, Status &err) override { 443314564Sdim Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); 444314564Sdim 445314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 446314564Sdim if (log) { 447314564Sdim log->Printf("EntityVariable::Materialize [address = 0x%" PRIx64 448314564Sdim ", m_variable_sp = %s]", 449314564Sdim (uint64_t)load_addr, m_variable_sp->GetName().AsCString()); 450254721Semaste } 451309124Sdim 452314564Sdim ExecutionContextScope *scope = frame_sp.get(); 453309124Sdim 454314564Sdim if (!scope) 455314564Sdim scope = map.GetBestExecutionContextScope(); 456309124Sdim 457314564Sdim lldb::ValueObjectSP valobj_sp = 458314564Sdim ValueObjectVariable::Create(scope, m_variable_sp); 459309124Sdim 460314564Sdim if (!valobj_sp) { 461314564Sdim err.SetErrorStringWithFormat( 462314564Sdim "couldn't get a value object for variable %s", 463314564Sdim m_variable_sp->GetName().AsCString()); 464314564Sdim return; 465314564Sdim } 466309124Sdim 467321369Sdim Status valobj_error = valobj_sp->GetError(); 468309124Sdim 469314564Sdim if (valobj_error.Fail()) { 470314564Sdim err.SetErrorStringWithFormat("couldn't get the value of variable %s: %s", 471314564Sdim m_variable_sp->GetName().AsCString(), 472314564Sdim valobj_error.AsCString()); 473314564Sdim return; 474314564Sdim } 475309124Sdim 476314564Sdim if (m_is_reference) { 477314564Sdim DataExtractor valobj_extractor; 478321369Sdim Status extract_error; 479314564Sdim valobj_sp->GetData(valobj_extractor, extract_error); 480309124Sdim 481314564Sdim if (!extract_error.Success()) { 482314564Sdim err.SetErrorStringWithFormat( 483314564Sdim "couldn't read contents of reference variable %s: %s", 484314564Sdim m_variable_sp->GetName().AsCString(), extract_error.AsCString()); 485314564Sdim return; 486314564Sdim } 487309124Sdim 488314564Sdim lldb::offset_t offset = 0; 489314564Sdim lldb::addr_t reference_addr = valobj_extractor.GetAddress(&offset); 490309124Sdim 491321369Sdim Status write_error; 492314564Sdim map.WritePointerToMemory(load_addr, reference_addr, write_error); 493309124Sdim 494314564Sdim if (!write_error.Success()) { 495314564Sdim err.SetErrorStringWithFormat("couldn't write the contents of reference " 496314564Sdim "variable %s to memory: %s", 497314564Sdim m_variable_sp->GetName().AsCString(), 498314564Sdim write_error.AsCString()); 499314564Sdim return; 500314564Sdim } 501314564Sdim } else { 502314564Sdim AddressType address_type = eAddressTypeInvalid; 503314564Sdim const bool scalar_is_load_address = false; 504314564Sdim lldb::addr_t addr_of_valobj = 505314564Sdim valobj_sp->GetAddressOf(scalar_is_load_address, &address_type); 506314564Sdim if (addr_of_valobj != LLDB_INVALID_ADDRESS) { 507321369Sdim Status write_error; 508314564Sdim map.WritePointerToMemory(load_addr, addr_of_valobj, write_error); 509309124Sdim 510314564Sdim if (!write_error.Success()) { 511314564Sdim err.SetErrorStringWithFormat( 512314564Sdim "couldn't write the address of variable %s to memory: %s", 513314564Sdim m_variable_sp->GetName().AsCString(), write_error.AsCString()); 514314564Sdim return; 515314564Sdim } 516314564Sdim } else { 517314564Sdim DataExtractor data; 518321369Sdim Status extract_error; 519314564Sdim valobj_sp->GetData(data, extract_error); 520314564Sdim if (!extract_error.Success()) { 521314564Sdim err.SetErrorStringWithFormat("couldn't get the value of %s: %s", 522314564Sdim m_variable_sp->GetName().AsCString(), 523314564Sdim extract_error.AsCString()); 524314564Sdim return; 525314564Sdim } 526309124Sdim 527314564Sdim if (m_temporary_allocation != LLDB_INVALID_ADDRESS) { 528314564Sdim err.SetErrorStringWithFormat( 529314564Sdim "trying to create a temporary region for %s but one exists", 530314564Sdim m_variable_sp->GetName().AsCString()); 531314564Sdim return; 532254721Semaste } 533309124Sdim 534314564Sdim if (data.GetByteSize() < m_variable_sp->GetType()->GetByteSize()) { 535314564Sdim if (data.GetByteSize() == 0 && 536314564Sdim m_variable_sp->LocationExpression().IsValid() == false) { 537314564Sdim err.SetErrorStringWithFormat("the variable '%s' has no location, " 538314564Sdim "it may have been optimized out", 539314564Sdim m_variable_sp->GetName().AsCString()); 540314564Sdim } else { 541314564Sdim err.SetErrorStringWithFormat( 542314564Sdim "size of variable %s (%" PRIu64 543314564Sdim ") is larger than the ValueObject's size (%" PRIu64 ")", 544314564Sdim m_variable_sp->GetName().AsCString(), 545314564Sdim m_variable_sp->GetType()->GetByteSize(), data.GetByteSize()); 546314564Sdim } 547314564Sdim return; 548314564Sdim } 549309124Sdim 550314564Sdim size_t bit_align = 551314564Sdim m_variable_sp->GetType()->GetLayoutCompilerType().GetTypeBitAlign(); 552314564Sdim size_t byte_align = (bit_align + 7) / 8; 553309124Sdim 554314564Sdim if (!byte_align) 555314564Sdim byte_align = 1; 556309124Sdim 557321369Sdim Status alloc_error; 558314564Sdim const bool zero_memory = false; 559309124Sdim 560314564Sdim m_temporary_allocation = map.Malloc( 561314564Sdim data.GetByteSize(), byte_align, 562314564Sdim lldb::ePermissionsReadable | lldb::ePermissionsWritable, 563314564Sdim IRMemoryMap::eAllocationPolicyMirror, zero_memory, alloc_error); 564309124Sdim 565314564Sdim m_temporary_allocation_size = data.GetByteSize(); 566296417Sdim 567314564Sdim m_original_data.reset( 568314564Sdim new DataBufferHeap(data.GetDataStart(), data.GetByteSize())); 569309124Sdim 570314564Sdim if (!alloc_error.Success()) { 571314564Sdim err.SetErrorStringWithFormat( 572314564Sdim "couldn't allocate a temporary region for %s: %s", 573314564Sdim m_variable_sp->GetName().AsCString(), alloc_error.AsCString()); 574314564Sdim return; 575314564Sdim } 576309124Sdim 577321369Sdim Status write_error; 578309124Sdim 579314564Sdim map.WriteMemory(m_temporary_allocation, data.GetDataStart(), 580314564Sdim data.GetByteSize(), write_error); 581309124Sdim 582314564Sdim if (!write_error.Success()) { 583314564Sdim err.SetErrorStringWithFormat( 584314564Sdim "couldn't write to the temporary region for %s: %s", 585314564Sdim m_variable_sp->GetName().AsCString(), write_error.AsCString()); 586314564Sdim return; 587314564Sdim } 588309124Sdim 589321369Sdim Status pointer_write_error; 590309124Sdim 591314564Sdim map.WritePointerToMemory(load_addr, m_temporary_allocation, 592314564Sdim pointer_write_error); 593309124Sdim 594314564Sdim if (!pointer_write_error.Success()) { 595314564Sdim err.SetErrorStringWithFormat( 596314564Sdim "couldn't write the address of the temporary region for %s: %s", 597314564Sdim m_variable_sp->GetName().AsCString(), 598314564Sdim pointer_write_error.AsCString()); 599254721Semaste } 600314564Sdim } 601254721Semaste } 602314564Sdim } 603309124Sdim 604314564Sdim void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 605314564Sdim lldb::addr_t process_address, lldb::addr_t frame_top, 606321369Sdim lldb::addr_t frame_bottom, Status &err) override { 607314564Sdim Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); 608254721Semaste 609314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 610314564Sdim if (log) { 611314564Sdim log->Printf("EntityVariable::Dematerialize [address = 0x%" PRIx64 612314564Sdim ", m_variable_sp = %s]", 613314564Sdim (uint64_t)load_addr, m_variable_sp->GetName().AsCString()); 614314564Sdim } 615309124Sdim 616314564Sdim if (m_temporary_allocation != LLDB_INVALID_ADDRESS) { 617314564Sdim ExecutionContextScope *scope = frame_sp.get(); 618309124Sdim 619314564Sdim if (!scope) 620314564Sdim scope = map.GetBestExecutionContextScope(); 621309124Sdim 622314564Sdim lldb::ValueObjectSP valobj_sp = 623314564Sdim ValueObjectVariable::Create(scope, m_variable_sp); 624309124Sdim 625314564Sdim if (!valobj_sp) { 626314564Sdim err.SetErrorStringWithFormat( 627314564Sdim "couldn't get a value object for variable %s", 628314564Sdim m_variable_sp->GetName().AsCString()); 629314564Sdim return; 630314564Sdim } 631309124Sdim 632314564Sdim lldb_private::DataExtractor data; 633309124Sdim 634321369Sdim Status extract_error; 635309124Sdim 636314564Sdim map.GetMemoryData(data, m_temporary_allocation, valobj_sp->GetByteSize(), 637314564Sdim extract_error); 638309124Sdim 639314564Sdim if (!extract_error.Success()) { 640314564Sdim err.SetErrorStringWithFormat("couldn't get the data for variable %s", 641314564Sdim m_variable_sp->GetName().AsCString()); 642314564Sdim return; 643314564Sdim } 644309124Sdim 645314564Sdim bool actually_write = true; 646309124Sdim 647314564Sdim if (m_original_data) { 648314564Sdim if ((data.GetByteSize() == m_original_data->GetByteSize()) && 649314564Sdim !memcmp(m_original_data->GetBytes(), data.GetDataStart(), 650314564Sdim data.GetByteSize())) { 651314564Sdim actually_write = false; 652314564Sdim } 653314564Sdim } 654309124Sdim 655321369Sdim Status set_error; 656309124Sdim 657314564Sdim if (actually_write) { 658314564Sdim valobj_sp->SetData(data, set_error); 659309124Sdim 660314564Sdim if (!set_error.Success()) { 661314564Sdim err.SetErrorStringWithFormat( 662314564Sdim "couldn't write the new contents of %s back into the variable", 663314564Sdim m_variable_sp->GetName().AsCString()); 664314564Sdim return; 665314564Sdim } 666314564Sdim } 667309124Sdim 668321369Sdim Status free_error; 669309124Sdim 670314564Sdim map.Free(m_temporary_allocation, free_error); 671309124Sdim 672314564Sdim if (!free_error.Success()) { 673314564Sdim err.SetErrorStringWithFormat( 674314564Sdim "couldn't free the temporary region for %s: %s", 675314564Sdim m_variable_sp->GetName().AsCString(), free_error.AsCString()); 676314564Sdim return; 677314564Sdim } 678309124Sdim 679314564Sdim m_original_data.reset(); 680314564Sdim m_temporary_allocation = LLDB_INVALID_ADDRESS; 681314564Sdim m_temporary_allocation_size = 0; 682254721Semaste } 683314564Sdim } 684309124Sdim 685314564Sdim void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address, 686314564Sdim Log *log) override { 687314564Sdim StreamString dump_stream; 688254721Semaste 689314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 690314564Sdim dump_stream.Printf("0x%" PRIx64 ": EntityVariable\n", load_addr); 691309124Sdim 692321369Sdim Status err; 693309124Sdim 694314564Sdim lldb::addr_t ptr = LLDB_INVALID_ADDRESS; 695309124Sdim 696314564Sdim { 697314564Sdim dump_stream.Printf("Pointer:\n"); 698309124Sdim 699314564Sdim DataBufferHeap data(m_size, 0); 700309124Sdim 701314564Sdim map.ReadMemory(data.GetBytes(), load_addr, m_size, err); 702309124Sdim 703314564Sdim if (!err.Success()) { 704314564Sdim dump_stream.Printf(" <could not be read>\n"); 705314564Sdim } else { 706314564Sdim DataExtractor extractor(data.GetBytes(), data.GetByteSize(), 707314564Sdim map.GetByteOrder(), map.GetAddressByteSize()); 708309124Sdim 709321369Sdim DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, 710321369Sdim load_addr); 711309124Sdim 712314564Sdim lldb::offset_t offset; 713309124Sdim 714314564Sdim ptr = extractor.GetPointer(&offset); 715309124Sdim 716314564Sdim dump_stream.PutChar('\n'); 717314564Sdim } 718314564Sdim } 719309124Sdim 720314564Sdim if (m_temporary_allocation == LLDB_INVALID_ADDRESS) { 721314564Sdim dump_stream.Printf("Points to process memory:\n"); 722314564Sdim } else { 723314564Sdim dump_stream.Printf("Temporary allocation:\n"); 724314564Sdim } 725309124Sdim 726314564Sdim if (ptr == LLDB_INVALID_ADDRESS) { 727314564Sdim dump_stream.Printf(" <could not be be found>\n"); 728314564Sdim } else { 729314564Sdim DataBufferHeap data(m_temporary_allocation_size, 0); 730309124Sdim 731314564Sdim map.ReadMemory(data.GetBytes(), m_temporary_allocation, 732314564Sdim m_temporary_allocation_size, err); 733309124Sdim 734314564Sdim if (!err.Success()) { 735314564Sdim dump_stream.Printf(" <could not be read>\n"); 736314564Sdim } else { 737321369Sdim DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, 738321369Sdim load_addr); 739309124Sdim 740314564Sdim dump_stream.PutChar('\n'); 741314564Sdim } 742254721Semaste } 743309124Sdim 744314564Sdim log->PutString(dump_stream.GetString()); 745314564Sdim } 746309124Sdim 747314564Sdim void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override { 748314564Sdim if (m_temporary_allocation != LLDB_INVALID_ADDRESS) { 749321369Sdim Status free_error; 750309124Sdim 751314564Sdim map.Free(m_temporary_allocation, free_error); 752254721Semaste 753314564Sdim m_temporary_allocation = LLDB_INVALID_ADDRESS; 754314564Sdim m_temporary_allocation_size = 0; 755254721Semaste } 756314564Sdim } 757296417Sdim 758254721Semasteprivate: 759314564Sdim lldb::VariableSP m_variable_sp; 760314564Sdim bool m_is_reference; 761314564Sdim lldb::addr_t m_temporary_allocation; 762314564Sdim size_t m_temporary_allocation_size; 763314564Sdim lldb::DataBufferSP m_original_data; 764254721Semaste}; 765254721Semaste 766321369Sdimuint32_t Materializer::AddVariable(lldb::VariableSP &variable_sp, Status &err) { 767314564Sdim EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP()); 768314564Sdim iter->reset(new EntityVariable(variable_sp)); 769314564Sdim uint32_t ret = AddStructMember(**iter); 770314564Sdim (*iter)->SetOffset(ret); 771314564Sdim return ret; 772254721Semaste} 773254721Semaste 774314564Sdimclass EntityResultVariable : public Materializer::Entity { 775254721Semastepublic: 776314564Sdim EntityResultVariable(const CompilerType &type, bool is_program_reference, 777314564Sdim bool keep_in_memory, 778314564Sdim Materializer::PersistentVariableDelegate *delegate) 779314564Sdim : Entity(), m_type(type), m_is_program_reference(is_program_reference), 780254721Semaste m_keep_in_memory(keep_in_memory), 781254721Semaste m_temporary_allocation(LLDB_INVALID_ADDRESS), 782314564Sdim m_temporary_allocation_size(0), m_delegate(delegate) { 783314564Sdim // Hard-coding to maximum size of a pointer since all results are 784314564Sdim // materialized by reference 785314564Sdim m_size = 8; 786314564Sdim m_alignment = 8; 787314564Sdim } 788309124Sdim 789314564Sdim void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 790321369Sdim lldb::addr_t process_address, Status &err) override { 791314564Sdim if (!m_is_program_reference) { 792314564Sdim if (m_temporary_allocation != LLDB_INVALID_ADDRESS) { 793314564Sdim err.SetErrorString("Trying to create a temporary region for the result " 794314564Sdim "but one exists"); 795314564Sdim return; 796314564Sdim } 797309124Sdim 798314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 799254721Semaste 800314564Sdim ExecutionContextScope *exe_scope = map.GetBestExecutionContextScope(); 801309124Sdim 802314564Sdim size_t byte_size = m_type.GetByteSize(exe_scope); 803314564Sdim size_t bit_align = m_type.GetTypeBitAlign(); 804314564Sdim size_t byte_align = (bit_align + 7) / 8; 805309124Sdim 806314564Sdim if (!byte_align) 807314564Sdim byte_align = 1; 808296417Sdim 809321369Sdim Status alloc_error; 810314564Sdim const bool zero_memory = true; 811309124Sdim 812314564Sdim m_temporary_allocation = map.Malloc( 813314564Sdim byte_size, byte_align, 814314564Sdim lldb::ePermissionsReadable | lldb::ePermissionsWritable, 815314564Sdim IRMemoryMap::eAllocationPolicyMirror, zero_memory, alloc_error); 816314564Sdim m_temporary_allocation_size = byte_size; 817309124Sdim 818314564Sdim if (!alloc_error.Success()) { 819314564Sdim err.SetErrorStringWithFormat( 820314564Sdim "couldn't allocate a temporary region for the result: %s", 821314564Sdim alloc_error.AsCString()); 822314564Sdim return; 823314564Sdim } 824309124Sdim 825321369Sdim Status pointer_write_error; 826309124Sdim 827314564Sdim map.WritePointerToMemory(load_addr, m_temporary_allocation, 828314564Sdim pointer_write_error); 829314564Sdim 830314564Sdim if (!pointer_write_error.Success()) { 831314564Sdim err.SetErrorStringWithFormat("couldn't write the address of the " 832314564Sdim "temporary region for the result: %s", 833314564Sdim pointer_write_error.AsCString()); 834314564Sdim } 835254721Semaste } 836314564Sdim } 837309124Sdim 838314564Sdim void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 839314564Sdim lldb::addr_t process_address, lldb::addr_t frame_top, 840321369Sdim lldb::addr_t frame_bottom, Status &err) override { 841314564Sdim err.Clear(); 842309124Sdim 843314564Sdim ExecutionContextScope *exe_scope = map.GetBestExecutionContextScope(); 844309124Sdim 845314564Sdim if (!exe_scope) { 846314564Sdim err.SetErrorString("Couldn't dematerialize a result variable: invalid " 847314564Sdim "execution context scope"); 848314564Sdim return; 849314564Sdim } 850309124Sdim 851314564Sdim lldb::addr_t address; 852321369Sdim Status read_error; 853314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 854309124Sdim 855314564Sdim map.ReadPointerFromMemory(&address, load_addr, read_error); 856309124Sdim 857314564Sdim if (!read_error.Success()) { 858314564Sdim err.SetErrorString("Couldn't dematerialize a result variable: couldn't " 859314564Sdim "read its address"); 860314564Sdim return; 861314564Sdim } 862309124Sdim 863314564Sdim lldb::TargetSP target_sp = exe_scope->CalculateTarget(); 864309124Sdim 865314564Sdim if (!target_sp) { 866314564Sdim err.SetErrorString("Couldn't dematerialize a result variable: no target"); 867314564Sdim return; 868314564Sdim } 869309124Sdim 870321369Sdim Status type_system_error; 871314564Sdim TypeSystem *type_system = target_sp->GetScratchTypeSystemForLanguage( 872314564Sdim &type_system_error, m_type.GetMinimumLanguage()); 873309124Sdim 874314564Sdim if (!type_system) { 875314564Sdim err.SetErrorStringWithFormat("Couldn't dematerialize a result variable: " 876314564Sdim "couldn't get the corresponding type " 877314564Sdim "system: %s", 878314564Sdim type_system_error.AsCString()); 879314564Sdim return; 880314564Sdim } 881309124Sdim 882314564Sdim PersistentExpressionState *persistent_state = 883314564Sdim type_system->GetPersistentExpressionState(); 884309124Sdim 885314564Sdim if (!persistent_state) { 886314564Sdim err.SetErrorString("Couldn't dematerialize a result variable: " 887314564Sdim "corresponding type system doesn't handle persistent " 888314564Sdim "variables"); 889314564Sdim return; 890314564Sdim } 891309124Sdim 892314564Sdim ConstString name = m_delegate 893314564Sdim ? m_delegate->GetName() 894314564Sdim : persistent_state->GetNextPersistentVariableName(); 895309124Sdim 896314564Sdim lldb::ExpressionVariableSP ret = persistent_state->CreatePersistentVariable( 897314564Sdim exe_scope, name, m_type, map.GetByteOrder(), map.GetAddressByteSize()); 898309124Sdim 899314564Sdim if (!ret) { 900314564Sdim err.SetErrorStringWithFormat("couldn't dematerialize a result variable: " 901314564Sdim "failed to make persistent variable %s", 902314564Sdim name.AsCString()); 903314564Sdim return; 904314564Sdim } 905309124Sdim 906314564Sdim lldb::ProcessSP process_sp = 907314564Sdim map.GetBestExecutionContextScope()->CalculateProcess(); 908309124Sdim 909314564Sdim if (m_delegate) { 910314564Sdim m_delegate->DidDematerialize(ret); 911314564Sdim } 912309124Sdim 913314564Sdim bool can_persist = 914314564Sdim (m_is_program_reference && process_sp && process_sp->CanJIT() && 915314564Sdim !(address >= frame_bottom && address < frame_top)); 916254721Semaste 917314564Sdim if (can_persist && m_keep_in_memory) { 918314564Sdim ret->m_live_sp = ValueObjectConstResult::Create(exe_scope, m_type, name, 919314564Sdim address, eAddressTypeLoad, 920314564Sdim map.GetAddressByteSize()); 921314564Sdim } 922309124Sdim 923314564Sdim ret->ValueUpdated(); 924309124Sdim 925314564Sdim const size_t pvar_byte_size = ret->GetByteSize(); 926314564Sdim uint8_t *pvar_data = ret->GetValueBytes(); 927309124Sdim 928314564Sdim map.ReadMemory(pvar_data, address, pvar_byte_size, read_error); 929309124Sdim 930314564Sdim if (!read_error.Success()) { 931314564Sdim err.SetErrorString( 932314564Sdim "Couldn't dematerialize a result variable: couldn't read its memory"); 933314564Sdim return; 934314564Sdim } 935309124Sdim 936314564Sdim if (!can_persist || !m_keep_in_memory) { 937314564Sdim ret->m_flags |= ExpressionVariable::EVNeedsAllocation; 938309124Sdim 939314564Sdim if (m_temporary_allocation != LLDB_INVALID_ADDRESS) { 940321369Sdim Status free_error; 941314564Sdim map.Free(m_temporary_allocation, free_error); 942314564Sdim } 943314564Sdim } else { 944314564Sdim ret->m_flags |= ExpressionVariable::EVIsLLDBAllocated; 945254721Semaste } 946309124Sdim 947314564Sdim m_temporary_allocation = LLDB_INVALID_ADDRESS; 948314564Sdim m_temporary_allocation_size = 0; 949314564Sdim } 950309124Sdim 951314564Sdim void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address, 952314564Sdim Log *log) override { 953314564Sdim StreamString dump_stream; 954254721Semaste 955314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 956309124Sdim 957314564Sdim dump_stream.Printf("0x%" PRIx64 ": EntityResultVariable\n", load_addr); 958309124Sdim 959321369Sdim Status err; 960309124Sdim 961314564Sdim lldb::addr_t ptr = LLDB_INVALID_ADDRESS; 962309124Sdim 963314564Sdim { 964314564Sdim dump_stream.Printf("Pointer:\n"); 965309124Sdim 966314564Sdim DataBufferHeap data(m_size, 0); 967309124Sdim 968314564Sdim map.ReadMemory(data.GetBytes(), load_addr, m_size, err); 969309124Sdim 970314564Sdim if (!err.Success()) { 971314564Sdim dump_stream.Printf(" <could not be read>\n"); 972314564Sdim } else { 973314564Sdim DataExtractor extractor(data.GetBytes(), data.GetByteSize(), 974314564Sdim map.GetByteOrder(), map.GetAddressByteSize()); 975309124Sdim 976321369Sdim DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, 977321369Sdim load_addr); 978309124Sdim 979314564Sdim lldb::offset_t offset; 980309124Sdim 981314564Sdim ptr = extractor.GetPointer(&offset); 982309124Sdim 983314564Sdim dump_stream.PutChar('\n'); 984314564Sdim } 985314564Sdim } 986309124Sdim 987314564Sdim if (m_temporary_allocation == LLDB_INVALID_ADDRESS) { 988314564Sdim dump_stream.Printf("Points to process memory:\n"); 989314564Sdim } else { 990314564Sdim dump_stream.Printf("Temporary allocation:\n"); 991314564Sdim } 992309124Sdim 993314564Sdim if (ptr == LLDB_INVALID_ADDRESS) { 994314564Sdim dump_stream.Printf(" <could not be be found>\n"); 995314564Sdim } else { 996314564Sdim DataBufferHeap data(m_temporary_allocation_size, 0); 997309124Sdim 998314564Sdim map.ReadMemory(data.GetBytes(), m_temporary_allocation, 999314564Sdim m_temporary_allocation_size, err); 1000309124Sdim 1001314564Sdim if (!err.Success()) { 1002314564Sdim dump_stream.Printf(" <could not be read>\n"); 1003314564Sdim } else { 1004321369Sdim DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, 1005321369Sdim load_addr); 1006309124Sdim 1007314564Sdim dump_stream.PutChar('\n'); 1008314564Sdim } 1009254721Semaste } 1010309124Sdim 1011314564Sdim log->PutString(dump_stream.GetString()); 1012314564Sdim } 1013309124Sdim 1014314564Sdim void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override { 1015314564Sdim if (!m_keep_in_memory && m_temporary_allocation != LLDB_INVALID_ADDRESS) { 1016321369Sdim Status free_error; 1017309124Sdim 1018314564Sdim map.Free(m_temporary_allocation, free_error); 1019254721Semaste } 1020296417Sdim 1021314564Sdim m_temporary_allocation = LLDB_INVALID_ADDRESS; 1022314564Sdim m_temporary_allocation_size = 0; 1023314564Sdim } 1024314564Sdim 1025254721Semasteprivate: 1026314564Sdim CompilerType m_type; 1027314564Sdim bool m_is_program_reference; 1028314564Sdim bool m_keep_in_memory; 1029309124Sdim 1030314564Sdim lldb::addr_t m_temporary_allocation; 1031314564Sdim size_t m_temporary_allocation_size; 1032314564Sdim Materializer::PersistentVariableDelegate *m_delegate; 1033254721Semaste}; 1034254721Semaste 1035314564Sdimuint32_t Materializer::AddResultVariable(const CompilerType &type, 1036314564Sdim bool is_program_reference, 1037314564Sdim bool keep_in_memory, 1038314564Sdim PersistentVariableDelegate *delegate, 1039321369Sdim Status &err) { 1040314564Sdim EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP()); 1041314564Sdim iter->reset(new EntityResultVariable(type, is_program_reference, 1042314564Sdim keep_in_memory, delegate)); 1043314564Sdim uint32_t ret = AddStructMember(**iter); 1044314564Sdim (*iter)->SetOffset(ret); 1045314564Sdim return ret; 1046254721Semaste} 1047254721Semaste 1048314564Sdimclass EntitySymbol : public Materializer::Entity { 1049254721Semastepublic: 1050314564Sdim EntitySymbol(const Symbol &symbol) : Entity(), m_symbol(symbol) { 1051314564Sdim // Hard-coding to maximum size of a symbol 1052314564Sdim m_size = 8; 1053314564Sdim m_alignment = 8; 1054314564Sdim } 1055309124Sdim 1056314564Sdim void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 1057321369Sdim lldb::addr_t process_address, Status &err) override { 1058314564Sdim Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); 1059254721Semaste 1060314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 1061254721Semaste 1062314564Sdim if (log) { 1063314564Sdim log->Printf("EntitySymbol::Materialize [address = 0x%" PRIx64 1064314564Sdim ", m_symbol = %s]", 1065314564Sdim (uint64_t)load_addr, m_symbol.GetName().AsCString()); 1066314564Sdim } 1067309124Sdim 1068314564Sdim const Address sym_address = m_symbol.GetAddress(); 1069254721Semaste 1070314564Sdim ExecutionContextScope *exe_scope = map.GetBestExecutionContextScope(); 1071309124Sdim 1072314564Sdim lldb::TargetSP target_sp; 1073309124Sdim 1074314564Sdim if (exe_scope) 1075314564Sdim target_sp = map.GetBestExecutionContextScope()->CalculateTarget(); 1076309124Sdim 1077314564Sdim if (!target_sp) { 1078314564Sdim err.SetErrorStringWithFormat( 1079314564Sdim "couldn't resolve symbol %s because there is no target", 1080314564Sdim m_symbol.GetName().AsCString()); 1081314564Sdim return; 1082314564Sdim } 1083309124Sdim 1084314564Sdim lldb::addr_t resolved_address = sym_address.GetLoadAddress(target_sp.get()); 1085309124Sdim 1086314564Sdim if (resolved_address == LLDB_INVALID_ADDRESS) 1087314564Sdim resolved_address = sym_address.GetFileAddress(); 1088309124Sdim 1089321369Sdim Status pointer_write_error; 1090309124Sdim 1091314564Sdim map.WritePointerToMemory(load_addr, resolved_address, pointer_write_error); 1092309124Sdim 1093314564Sdim if (!pointer_write_error.Success()) { 1094314564Sdim err.SetErrorStringWithFormat( 1095314564Sdim "couldn't write the address of symbol %s: %s", 1096314564Sdim m_symbol.GetName().AsCString(), pointer_write_error.AsCString()); 1097314564Sdim return; 1098254721Semaste } 1099314564Sdim } 1100309124Sdim 1101314564Sdim void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 1102314564Sdim lldb::addr_t process_address, lldb::addr_t frame_top, 1103321369Sdim lldb::addr_t frame_bottom, Status &err) override { 1104314564Sdim Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); 1105254721Semaste 1106314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 1107254721Semaste 1108314564Sdim if (log) { 1109314564Sdim log->Printf("EntitySymbol::Dematerialize [address = 0x%" PRIx64 1110314564Sdim ", m_symbol = %s]", 1111314564Sdim (uint64_t)load_addr, m_symbol.GetName().AsCString()); 1112254721Semaste } 1113309124Sdim 1114314564Sdim // no work needs to be done 1115314564Sdim } 1116309124Sdim 1117314564Sdim void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address, 1118314564Sdim Log *log) override { 1119314564Sdim StreamString dump_stream; 1120309124Sdim 1121321369Sdim Status err; 1122254721Semaste 1123314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 1124309124Sdim 1125314564Sdim dump_stream.Printf("0x%" PRIx64 ": EntitySymbol (%s)\n", load_addr, 1126314564Sdim m_symbol.GetName().AsCString()); 1127309124Sdim 1128314564Sdim { 1129314564Sdim dump_stream.Printf("Pointer:\n"); 1130309124Sdim 1131314564Sdim DataBufferHeap data(m_size, 0); 1132309124Sdim 1133314564Sdim map.ReadMemory(data.GetBytes(), load_addr, m_size, err); 1134309124Sdim 1135314564Sdim if (!err.Success()) { 1136314564Sdim dump_stream.Printf(" <could not be read>\n"); 1137314564Sdim } else { 1138321369Sdim DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, 1139321369Sdim load_addr); 1140309124Sdim 1141314564Sdim dump_stream.PutChar('\n'); 1142314564Sdim } 1143254721Semaste } 1144309124Sdim 1145314564Sdim log->PutString(dump_stream.GetString()); 1146314564Sdim } 1147296417Sdim 1148314564Sdim void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {} 1149314564Sdim 1150254721Semasteprivate: 1151314564Sdim Symbol m_symbol; 1152254721Semaste}; 1153254721Semaste 1154321369Sdimuint32_t Materializer::AddSymbol(const Symbol &symbol_sp, Status &err) { 1155314564Sdim EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP()); 1156314564Sdim iter->reset(new EntitySymbol(symbol_sp)); 1157314564Sdim uint32_t ret = AddStructMember(**iter); 1158314564Sdim (*iter)->SetOffset(ret); 1159314564Sdim return ret; 1160254721Semaste} 1161254721Semaste 1162314564Sdimclass EntityRegister : public Materializer::Entity { 1163254721Semastepublic: 1164314564Sdim EntityRegister(const RegisterInfo ®ister_info) 1165314564Sdim : Entity(), m_register_info(register_info) { 1166314564Sdim // Hard-coding alignment conservatively 1167314564Sdim m_size = m_register_info.byte_size; 1168314564Sdim m_alignment = m_register_info.byte_size; 1169314564Sdim } 1170314564Sdim 1171314564Sdim void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 1172321369Sdim lldb::addr_t process_address, Status &err) override { 1173314564Sdim Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); 1174314564Sdim 1175314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 1176314564Sdim 1177314564Sdim if (log) { 1178314564Sdim log->Printf("EntityRegister::Materialize [address = 0x%" PRIx64 1179314564Sdim ", m_register_info = %s]", 1180314564Sdim (uint64_t)load_addr, m_register_info.name); 1181254721Semaste } 1182309124Sdim 1183314564Sdim RegisterValue reg_value; 1184309124Sdim 1185314564Sdim if (!frame_sp.get()) { 1186314564Sdim err.SetErrorStringWithFormat( 1187314564Sdim "couldn't materialize register %s without a stack frame", 1188314564Sdim m_register_info.name); 1189314564Sdim return; 1190314564Sdim } 1191254721Semaste 1192314564Sdim lldb::RegisterContextSP reg_context_sp = frame_sp->GetRegisterContext(); 1193254721Semaste 1194314564Sdim if (!reg_context_sp->ReadRegister(&m_register_info, reg_value)) { 1195314564Sdim err.SetErrorStringWithFormat("couldn't read the value of register %s", 1196314564Sdim m_register_info.name); 1197314564Sdim return; 1198314564Sdim } 1199309124Sdim 1200314564Sdim DataExtractor register_data; 1201309124Sdim 1202314564Sdim if (!reg_value.GetData(register_data)) { 1203314564Sdim err.SetErrorStringWithFormat("couldn't get the data for register %s", 1204314564Sdim m_register_info.name); 1205314564Sdim return; 1206314564Sdim } 1207309124Sdim 1208314564Sdim if (register_data.GetByteSize() != m_register_info.byte_size) { 1209314564Sdim err.SetErrorStringWithFormat( 1210314564Sdim "data for register %s had size %llu but we expected %llu", 1211314564Sdim m_register_info.name, (unsigned long long)register_data.GetByteSize(), 1212314564Sdim (unsigned long long)m_register_info.byte_size); 1213314564Sdim return; 1214314564Sdim } 1215309124Sdim 1216314564Sdim m_register_contents.reset(new DataBufferHeap(register_data.GetDataStart(), 1217314564Sdim register_data.GetByteSize())); 1218309124Sdim 1219321369Sdim Status write_error; 1220309124Sdim 1221314564Sdim map.WriteMemory(load_addr, register_data.GetDataStart(), 1222314564Sdim register_data.GetByteSize(), write_error); 1223309124Sdim 1224314564Sdim if (!write_error.Success()) { 1225314564Sdim err.SetErrorStringWithFormat( 1226314564Sdim "couldn't write the contents of register %s: %s", 1227314564Sdim m_register_info.name, write_error.AsCString()); 1228314564Sdim return; 1229254721Semaste } 1230314564Sdim } 1231309124Sdim 1232314564Sdim void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 1233314564Sdim lldb::addr_t process_address, lldb::addr_t frame_top, 1234321369Sdim lldb::addr_t frame_bottom, Status &err) override { 1235314564Sdim Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); 1236309124Sdim 1237314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 1238254721Semaste 1239314564Sdim if (log) { 1240314564Sdim log->Printf("EntityRegister::Dematerialize [address = 0x%" PRIx64 1241314564Sdim ", m_register_info = %s]", 1242314564Sdim (uint64_t)load_addr, m_register_info.name); 1243314564Sdim } 1244309124Sdim 1245321369Sdim Status extract_error; 1246309124Sdim 1247314564Sdim DataExtractor register_data; 1248309124Sdim 1249314564Sdim if (!frame_sp.get()) { 1250314564Sdim err.SetErrorStringWithFormat( 1251314564Sdim "couldn't dematerialize register %s without a stack frame", 1252314564Sdim m_register_info.name); 1253314564Sdim return; 1254314564Sdim } 1255309124Sdim 1256314564Sdim lldb::RegisterContextSP reg_context_sp = frame_sp->GetRegisterContext(); 1257309124Sdim 1258314564Sdim map.GetMemoryData(register_data, load_addr, m_register_info.byte_size, 1259314564Sdim extract_error); 1260309124Sdim 1261314564Sdim if (!extract_error.Success()) { 1262314564Sdim err.SetErrorStringWithFormat("couldn't get the data for register %s: %s", 1263314564Sdim m_register_info.name, 1264314564Sdim extract_error.AsCString()); 1265314564Sdim return; 1266314564Sdim } 1267309124Sdim 1268314564Sdim if (!memcmp(register_data.GetDataStart(), m_register_contents->GetBytes(), 1269314564Sdim register_data.GetByteSize())) { 1270314564Sdim // No write required, and in particular we avoid errors if the register 1271314564Sdim // wasn't writable 1272309124Sdim 1273314564Sdim m_register_contents.reset(); 1274314564Sdim return; 1275314564Sdim } 1276309124Sdim 1277314564Sdim m_register_contents.reset(); 1278309124Sdim 1279314564Sdim RegisterValue register_value( 1280314564Sdim const_cast<uint8_t *>(register_data.GetDataStart()), 1281314564Sdim register_data.GetByteSize(), register_data.GetByteOrder()); 1282309124Sdim 1283314564Sdim if (!reg_context_sp->WriteRegister(&m_register_info, register_value)) { 1284314564Sdim err.SetErrorStringWithFormat("couldn't write the value of register %s", 1285314564Sdim m_register_info.name); 1286314564Sdim return; 1287254721Semaste } 1288314564Sdim } 1289309124Sdim 1290314564Sdim void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address, 1291314564Sdim Log *log) override { 1292314564Sdim StreamString dump_stream; 1293309124Sdim 1294321369Sdim Status err; 1295309124Sdim 1296314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 1297254721Semaste 1298314564Sdim dump_stream.Printf("0x%" PRIx64 ": EntityRegister (%s)\n", load_addr, 1299314564Sdim m_register_info.name); 1300309124Sdim 1301314564Sdim { 1302314564Sdim dump_stream.Printf("Value:\n"); 1303309124Sdim 1304314564Sdim DataBufferHeap data(m_size, 0); 1305309124Sdim 1306314564Sdim map.ReadMemory(data.GetBytes(), load_addr, m_size, err); 1307309124Sdim 1308314564Sdim if (!err.Success()) { 1309314564Sdim dump_stream.Printf(" <could not be read>\n"); 1310314564Sdim } else { 1311321369Sdim DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, 1312321369Sdim load_addr); 1313309124Sdim 1314314564Sdim dump_stream.PutChar('\n'); 1315314564Sdim } 1316314564Sdim } 1317309124Sdim 1318314564Sdim log->PutString(dump_stream.GetString()); 1319314564Sdim } 1320309124Sdim 1321314564Sdim void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {} 1322309124Sdim 1323254721Semasteprivate: 1324314564Sdim RegisterInfo m_register_info; 1325314564Sdim lldb::DataBufferSP m_register_contents; 1326254721Semaste}; 1327254721Semaste 1328314564Sdimuint32_t Materializer::AddRegister(const RegisterInfo ®ister_info, 1329321369Sdim Status &err) { 1330314564Sdim EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP()); 1331314564Sdim iter->reset(new EntityRegister(register_info)); 1332314564Sdim uint32_t ret = AddStructMember(**iter); 1333314564Sdim (*iter)->SetOffset(ret); 1334314564Sdim return ret; 1335254721Semaste} 1336254721Semaste 1337314564SdimMaterializer::Materializer() 1338314564Sdim : m_dematerializer_wp(), m_current_offset(0), m_struct_alignment(8) {} 1339254721Semaste 1340314564SdimMaterializer::~Materializer() { 1341314564Sdim DematerializerSP dematerializer_sp = m_dematerializer_wp.lock(); 1342309124Sdim 1343314564Sdim if (dematerializer_sp) 1344314564Sdim dematerializer_sp->Wipe(); 1345254721Semaste} 1346254721Semaste 1347254721SemasteMaterializer::DematerializerSP 1348314564SdimMaterializer::Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 1349321369Sdim lldb::addr_t process_address, Status &error) { 1350314564Sdim ExecutionContextScope *exe_scope = frame_sp.get(); 1351276479Sdim 1352314564Sdim if (!exe_scope) 1353314564Sdim exe_scope = map.GetBestExecutionContextScope(); 1354276479Sdim 1355314564Sdim DematerializerSP dematerializer_sp = m_dematerializer_wp.lock(); 1356276479Sdim 1357314564Sdim if (dematerializer_sp) { 1358314564Sdim error.SetErrorToGenericError(); 1359314564Sdim error.SetErrorString("Couldn't materialize: already materialized"); 1360314564Sdim } 1361276479Sdim 1362314564Sdim DematerializerSP ret( 1363314564Sdim new Dematerializer(*this, frame_sp, map, process_address)); 1364276479Sdim 1365314564Sdim if (!exe_scope) { 1366314564Sdim error.SetErrorToGenericError(); 1367314564Sdim error.SetErrorString("Couldn't materialize: target doesn't exist"); 1368314564Sdim } 1369276479Sdim 1370314564Sdim for (EntityUP &entity_up : m_entities) { 1371314564Sdim entity_up->Materialize(frame_sp, map, process_address, error); 1372276479Sdim 1373314564Sdim if (!error.Success()) 1374314564Sdim return DematerializerSP(); 1375314564Sdim } 1376276479Sdim 1377314564Sdim if (Log *log = 1378314564Sdim lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)) { 1379314564Sdim log->Printf( 1380314564Sdim "Materializer::Materialize (frame_sp = %p, process_address = 0x%" PRIx64 1381314564Sdim ") materialized:", 1382314564Sdim static_cast<void *>(frame_sp.get()), process_address); 1383314564Sdim for (EntityUP &entity_up : m_entities) 1384314564Sdim entity_up->DumpToLog(map, process_address, log); 1385314564Sdim } 1386276479Sdim 1387314564Sdim m_dematerializer_wp = ret; 1388276479Sdim 1389314564Sdim return ret; 1390254721Semaste} 1391254721Semaste 1392321369Sdimvoid Materializer::Dematerializer::Dematerialize(Status &error, 1393314564Sdim lldb::addr_t frame_bottom, 1394314564Sdim lldb::addr_t frame_top) { 1395314564Sdim lldb::StackFrameSP frame_sp; 1396254721Semaste 1397314564Sdim lldb::ThreadSP thread_sp = m_thread_wp.lock(); 1398314564Sdim if (thread_sp) 1399314564Sdim frame_sp = thread_sp->GetFrameWithStackID(m_stack_id); 1400276479Sdim 1401314564Sdim ExecutionContextScope *exe_scope = m_map->GetBestExecutionContextScope(); 1402276479Sdim 1403314564Sdim if (!IsValid()) { 1404314564Sdim error.SetErrorToGenericError(); 1405314564Sdim error.SetErrorString("Couldn't dematerialize: invalid dematerializer"); 1406314564Sdim } 1407276479Sdim 1408314564Sdim if (!exe_scope) { 1409314564Sdim error.SetErrorToGenericError(); 1410314564Sdim error.SetErrorString("Couldn't dematerialize: target is gone"); 1411314564Sdim } else { 1412314564Sdim if (Log *log = 1413314564Sdim lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)) { 1414314564Sdim log->Printf("Materializer::Dematerialize (frame_sp = %p, process_address " 1415314564Sdim "= 0x%" PRIx64 ") about to dematerialize:", 1416314564Sdim 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