Materializer.cpp revision 344779
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 10314564Sdim#include "lldb/Expression/Materializer.h" 11321369Sdim#include "lldb/Core/DumpDataExtractor.h" 12254721Semaste#include "lldb/Core/ValueObjectConstResult.h" 13254721Semaste#include "lldb/Core/ValueObjectVariable.h" 14296417Sdim#include "lldb/Expression/ExpressionVariable.h" 15254721Semaste#include "lldb/Symbol/ClangASTContext.h" 16254721Semaste#include "lldb/Symbol/Symbol.h" 17254721Semaste#include "lldb/Symbol/Type.h" 18254721Semaste#include "lldb/Symbol/Variable.h" 19254721Semaste#include "lldb/Target/ExecutionContext.h" 20254721Semaste#include "lldb/Target/RegisterContext.h" 21254721Semaste#include "lldb/Target/StackFrame.h" 22254721Semaste#include "lldb/Target/Target.h" 23254721Semaste#include "lldb/Target/Thread.h" 24321369Sdim#include "lldb/Utility/Log.h" 25344779Sdim#include "lldb/Utility/RegisterValue.h" 26254721Semaste 27254721Semasteusing namespace lldb_private; 28254721Semaste 29314564Sdimuint32_t Materializer::AddStructMember(Entity &entity) { 30314564Sdim uint32_t size = entity.GetSize(); 31314564Sdim uint32_t alignment = entity.GetAlignment(); 32309124Sdim 33314564Sdim uint32_t ret; 34309124Sdim 35314564Sdim if (m_current_offset == 0) 36314564Sdim m_struct_alignment = alignment; 37309124Sdim 38314564Sdim if (m_current_offset % alignment) 39314564Sdim m_current_offset += (alignment - (m_current_offset % alignment)); 40309124Sdim 41314564Sdim ret = m_current_offset; 42309124Sdim 43314564Sdim m_current_offset += size; 44309124Sdim 45314564Sdim return ret; 46254721Semaste} 47254721Semaste 48314564Sdimvoid Materializer::Entity::SetSizeAndAlignmentFromType(CompilerType &type) { 49344779Sdim if (llvm::Optional<uint64_t> size = type.GetByteSize(nullptr)) 50344779Sdim m_size = *size; 51309124Sdim 52314564Sdim uint32_t bit_alignment = type.GetTypeBitAlign(); 53309124Sdim 54314564Sdim if (bit_alignment % 8) { 55314564Sdim bit_alignment += 8; 56314564Sdim bit_alignment &= ~((uint32_t)0x111u); 57314564Sdim } 58309124Sdim 59314564Sdim m_alignment = bit_alignment / 8; 60254721Semaste} 61254721Semaste 62314564Sdimclass EntityPersistentVariable : public Materializer::Entity { 63254721Semastepublic: 64314564Sdim EntityPersistentVariable(lldb::ExpressionVariableSP &persistent_variable_sp, 65314564Sdim Materializer::PersistentVariableDelegate *delegate) 66314564Sdim : Entity(), m_persistent_variable_sp(persistent_variable_sp), 67314564Sdim m_delegate(delegate) { 68314564Sdim // Hard-coding to maximum size of a pointer since persistent variables are 69314564Sdim // materialized by reference 70314564Sdim m_size = 8; 71314564Sdim m_alignment = 8; 72314564Sdim } 73309124Sdim 74321369Sdim void MakeAllocation(IRMemoryMap &map, Status &err) { 75314564Sdim Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); 76254721Semaste 77341825Sdim // Allocate a spare memory area to store the persistent variable's 78341825Sdim // contents. 79309124Sdim 80321369Sdim Status allocate_error; 81314564Sdim const bool zero_memory = false; 82309124Sdim 83314564Sdim lldb::addr_t mem = map.Malloc( 84314564Sdim m_persistent_variable_sp->GetByteSize(), 8, 85314564Sdim lldb::ePermissionsReadable | lldb::ePermissionsWritable, 86314564Sdim IRMemoryMap::eAllocationPolicyMirror, zero_memory, allocate_error); 87309124Sdim 88314564Sdim if (!allocate_error.Success()) { 89314564Sdim err.SetErrorStringWithFormat( 90314564Sdim "couldn't allocate a memory area to store %s: %s", 91314564Sdim m_persistent_variable_sp->GetName().GetCString(), 92314564Sdim allocate_error.AsCString()); 93314564Sdim return; 94314564Sdim } 95309124Sdim 96314564Sdim if (log) 97314564Sdim log->Printf("Allocated %s (0x%" PRIx64 ") successfully", 98314564Sdim m_persistent_variable_sp->GetName().GetCString(), mem); 99309124Sdim 100314564Sdim // Put the location of the spare memory into the live data of the 101314564Sdim // ValueObject. 102309124Sdim 103314564Sdim m_persistent_variable_sp->m_live_sp = ValueObjectConstResult::Create( 104314564Sdim map.GetBestExecutionContextScope(), 105314564Sdim m_persistent_variable_sp->GetCompilerType(), 106314564Sdim m_persistent_variable_sp->GetName(), mem, eAddressTypeLoad, 107314564Sdim map.GetAddressByteSize()); 108309124Sdim 109314564Sdim // Clear the flag if the variable will never be deallocated. 110309124Sdim 111314564Sdim if (m_persistent_variable_sp->m_flags & 112314564Sdim ExpressionVariable::EVKeepInTarget) { 113321369Sdim Status leak_error; 114314564Sdim map.Leak(mem, leak_error); 115314564Sdim m_persistent_variable_sp->m_flags &= 116314564Sdim ~ExpressionVariable::EVNeedsAllocation; 117314564Sdim } 118309124Sdim 119314564Sdim // Write the contents of the variable to the area. 120309124Sdim 121321369Sdim Status write_error; 122309124Sdim 123314564Sdim map.WriteMemory(mem, m_persistent_variable_sp->GetValueBytes(), 124314564Sdim m_persistent_variable_sp->GetByteSize(), write_error); 125309124Sdim 126314564Sdim if (!write_error.Success()) { 127314564Sdim err.SetErrorStringWithFormat( 128314564Sdim "couldn't write %s to the target: %s", 129314564Sdim m_persistent_variable_sp->GetName().AsCString(), 130314564Sdim write_error.AsCString()); 131314564Sdim return; 132254721Semaste } 133314564Sdim } 134309124Sdim 135321369Sdim void DestroyAllocation(IRMemoryMap &map, Status &err) { 136321369Sdim Status deallocate_error; 137309124Sdim 138314564Sdim map.Free((lldb::addr_t)m_persistent_variable_sp->m_live_sp->GetValue() 139314564Sdim .GetScalar() 140314564Sdim .ULongLong(), 141314564Sdim deallocate_error); 142309124Sdim 143314564Sdim m_persistent_variable_sp->m_live_sp.reset(); 144309124Sdim 145314564Sdim if (!deallocate_error.Success()) { 146314564Sdim err.SetErrorStringWithFormat( 147314564Sdim "couldn't deallocate memory for %s: %s", 148314564Sdim m_persistent_variable_sp->GetName().GetCString(), 149314564Sdim deallocate_error.AsCString()); 150254721Semaste } 151314564Sdim } 152309124Sdim 153314564Sdim void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 154321369Sdim lldb::addr_t process_address, Status &err) override { 155314564Sdim Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); 156254721Semaste 157314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 158309124Sdim 159314564Sdim if (log) { 160314564Sdim log->Printf("EntityPersistentVariable::Materialize [address = 0x%" PRIx64 161314564Sdim ", m_name = %s, m_flags = 0x%hx]", 162314564Sdim (uint64_t)load_addr, 163314564Sdim m_persistent_variable_sp->GetName().AsCString(), 164314564Sdim m_persistent_variable_sp->m_flags); 165314564Sdim } 166309124Sdim 167314564Sdim if (m_persistent_variable_sp->m_flags & 168314564Sdim ExpressionVariable::EVNeedsAllocation) { 169314564Sdim MakeAllocation(map, err); 170314564Sdim m_persistent_variable_sp->m_flags |= 171314564Sdim ExpressionVariable::EVIsLLDBAllocated; 172309124Sdim 173314564Sdim if (!err.Success()) 174314564Sdim return; 175314564Sdim } 176309124Sdim 177314564Sdim if ((m_persistent_variable_sp->m_flags & 178314564Sdim ExpressionVariable::EVIsProgramReference && 179314564Sdim m_persistent_variable_sp->m_live_sp) || 180314564Sdim m_persistent_variable_sp->m_flags & 181314564Sdim ExpressionVariable::EVIsLLDBAllocated) { 182321369Sdim Status write_error; 183309124Sdim 184314564Sdim map.WriteScalarToMemory( 185314564Sdim load_addr, 186314564Sdim m_persistent_variable_sp->m_live_sp->GetValue().GetScalar(), 187314564Sdim map.GetAddressByteSize(), write_error); 188309124Sdim 189314564Sdim if (!write_error.Success()) { 190314564Sdim err.SetErrorStringWithFormat( 191314564Sdim "couldn't write the location of %s to memory: %s", 192314564Sdim m_persistent_variable_sp->GetName().AsCString(), 193314564Sdim write_error.AsCString()); 194314564Sdim } 195314564Sdim } else { 196314564Sdim err.SetErrorStringWithFormat( 197314564Sdim "no materialization happened for persistent variable %s", 198314564Sdim m_persistent_variable_sp->GetName().AsCString()); 199314564Sdim return; 200254721Semaste } 201314564Sdim } 202309124Sdim 203314564Sdim void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 204314564Sdim lldb::addr_t process_address, lldb::addr_t frame_top, 205321369Sdim lldb::addr_t frame_bottom, Status &err) override { 206314564Sdim Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); 207309124Sdim 208314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 209254721Semaste 210314564Sdim if (log) { 211314564Sdim log->Printf( 212314564Sdim "EntityPersistentVariable::Dematerialize [address = 0x%" PRIx64 213314564Sdim ", m_name = %s, m_flags = 0x%hx]", 214314564Sdim (uint64_t)process_address + m_offset, 215314564Sdim m_persistent_variable_sp->GetName().AsCString(), 216314564Sdim m_persistent_variable_sp->m_flags); 217314564Sdim } 218309124Sdim 219314564Sdim if (m_delegate) { 220314564Sdim m_delegate->DidDematerialize(m_persistent_variable_sp); 221314564Sdim } 222296417Sdim 223314564Sdim if ((m_persistent_variable_sp->m_flags & 224314564Sdim ExpressionVariable::EVIsLLDBAllocated) || 225314564Sdim (m_persistent_variable_sp->m_flags & 226314564Sdim ExpressionVariable::EVIsProgramReference)) { 227314564Sdim if (m_persistent_variable_sp->m_flags & 228314564Sdim ExpressionVariable::EVIsProgramReference && 229314564Sdim !m_persistent_variable_sp->m_live_sp) { 230314564Sdim // If the reference comes from the program, then the 231341825Sdim // ClangExpressionVariable's live variable data hasn't been set up yet. 232341825Sdim // Do this now. 233309124Sdim 234314564Sdim lldb::addr_t location; 235321369Sdim Status read_error; 236309124Sdim 237314564Sdim map.ReadPointerFromMemory(&location, load_addr, read_error); 238309124Sdim 239314564Sdim if (!read_error.Success()) { 240314564Sdim err.SetErrorStringWithFormat( 241314564Sdim "couldn't read the address of program-allocated variable %s: %s", 242314564Sdim m_persistent_variable_sp->GetName().GetCString(), 243314564Sdim read_error.AsCString()); 244314564Sdim return; 245314564Sdim } 246309124Sdim 247314564Sdim m_persistent_variable_sp->m_live_sp = ValueObjectConstResult::Create( 248314564Sdim map.GetBestExecutionContextScope(), 249314564Sdim m_persistent_variable_sp.get()->GetCompilerType(), 250314564Sdim m_persistent_variable_sp->GetName(), location, eAddressTypeLoad, 251314564Sdim m_persistent_variable_sp->GetByteSize()); 252309124Sdim 253314564Sdim if (frame_top != LLDB_INVALID_ADDRESS && 254314564Sdim frame_bottom != LLDB_INVALID_ADDRESS && location >= frame_bottom && 255314564Sdim location <= frame_top) { 256314564Sdim // If the variable is resident in the stack frame created by the 257341825Sdim // expression, then it cannot be relied upon to stay around. We 258341825Sdim // treat it as needing reallocation. 259314564Sdim m_persistent_variable_sp->m_flags |= 260314564Sdim ExpressionVariable::EVIsLLDBAllocated; 261314564Sdim m_persistent_variable_sp->m_flags |= 262314564Sdim ExpressionVariable::EVNeedsAllocation; 263314564Sdim m_persistent_variable_sp->m_flags |= 264314564Sdim ExpressionVariable::EVNeedsFreezeDry; 265314564Sdim m_persistent_variable_sp->m_flags &= 266314564Sdim ~ExpressionVariable::EVIsProgramReference; 267314564Sdim } 268314564Sdim } 269309124Sdim 270314564Sdim lldb::addr_t mem = m_persistent_variable_sp->m_live_sp->GetValue() 271314564Sdim .GetScalar() 272314564Sdim .ULongLong(); 273309124Sdim 274314564Sdim if (!m_persistent_variable_sp->m_live_sp) { 275314564Sdim err.SetErrorStringWithFormat( 276314564Sdim "couldn't find the memory area used to store %s", 277314564Sdim m_persistent_variable_sp->GetName().GetCString()); 278314564Sdim return; 279314564Sdim } 280309124Sdim 281314564Sdim if (m_persistent_variable_sp->m_live_sp->GetValue() 282314564Sdim .GetValueAddressType() != eAddressTypeLoad) { 283314564Sdim err.SetErrorStringWithFormat( 284314564Sdim "the address of the memory area for %s is in an incorrect format", 285314564Sdim m_persistent_variable_sp->GetName().GetCString()); 286314564Sdim return; 287314564Sdim } 288309124Sdim 289314564Sdim if (m_persistent_variable_sp->m_flags & 290314564Sdim ExpressionVariable::EVNeedsFreezeDry || 291314564Sdim m_persistent_variable_sp->m_flags & 292314564Sdim ExpressionVariable::EVKeepInTarget) { 293314564Sdim if (log) 294314564Sdim log->Printf( 295314564Sdim "Dematerializing %s from 0x%" PRIx64 " (size = %llu)", 296314564Sdim m_persistent_variable_sp->GetName().GetCString(), (uint64_t)mem, 297314564Sdim (unsigned long long)m_persistent_variable_sp->GetByteSize()); 298309124Sdim 299314564Sdim // Read the contents of the spare memory area 300309124Sdim 301314564Sdim m_persistent_variable_sp->ValueUpdated(); 302309124Sdim 303321369Sdim Status read_error; 304309124Sdim 305314564Sdim map.ReadMemory(m_persistent_variable_sp->GetValueBytes(), mem, 306314564Sdim m_persistent_variable_sp->GetByteSize(), read_error); 307309124Sdim 308314564Sdim if (!read_error.Success()) { 309314564Sdim err.SetErrorStringWithFormat( 310314564Sdim "couldn't read the contents of %s from memory: %s", 311314564Sdim m_persistent_variable_sp->GetName().GetCString(), 312314564Sdim read_error.AsCString()); 313314564Sdim return; 314254721Semaste } 315309124Sdim 316314564Sdim m_persistent_variable_sp->m_flags &= 317314564Sdim ~ExpressionVariable::EVNeedsFreezeDry; 318314564Sdim } 319314564Sdim } else { 320314564Sdim err.SetErrorStringWithFormat( 321314564Sdim "no dematerialization happened for persistent variable %s", 322314564Sdim m_persistent_variable_sp->GetName().AsCString()); 323314564Sdim return; 324314564Sdim } 325309124Sdim 326314564Sdim lldb::ProcessSP process_sp = 327314564Sdim map.GetBestExecutionContextScope()->CalculateProcess(); 328314564Sdim if (!process_sp || !process_sp->CanJIT()) { 329314564Sdim // Allocations are not persistent so persistent variables cannot stay 330314564Sdim // materialized. 331254721Semaste 332314564Sdim m_persistent_variable_sp->m_flags |= 333314564Sdim ExpressionVariable::EVNeedsAllocation; 334314564Sdim 335314564Sdim DestroyAllocation(map, err); 336314564Sdim if (!err.Success()) 337314564Sdim return; 338314564Sdim } else if (m_persistent_variable_sp->m_flags & 339314564Sdim ExpressionVariable::EVNeedsAllocation && 340314564Sdim !(m_persistent_variable_sp->m_flags & 341314564Sdim ExpressionVariable::EVKeepInTarget)) { 342314564Sdim DestroyAllocation(map, err); 343314564Sdim if (!err.Success()) 344314564Sdim return; 345254721Semaste } 346314564Sdim } 347309124Sdim 348314564Sdim void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address, 349314564Sdim Log *log) override { 350314564Sdim StreamString dump_stream; 351309124Sdim 352321369Sdim Status err; 353309124Sdim 354314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 355254721Semaste 356314564Sdim dump_stream.Printf("0x%" PRIx64 ": EntityPersistentVariable (%s)\n", 357314564Sdim load_addr, 358314564Sdim m_persistent_variable_sp->GetName().AsCString()); 359309124Sdim 360314564Sdim { 361314564Sdim dump_stream.Printf("Pointer:\n"); 362309124Sdim 363314564Sdim DataBufferHeap data(m_size, 0); 364309124Sdim 365314564Sdim map.ReadMemory(data.GetBytes(), load_addr, m_size, err); 366309124Sdim 367314564Sdim if (!err.Success()) { 368314564Sdim dump_stream.Printf(" <could not be read>\n"); 369314564Sdim } else { 370321369Sdim DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, 371321369Sdim load_addr); 372309124Sdim 373314564Sdim dump_stream.PutChar('\n'); 374314564Sdim } 375314564Sdim } 376309124Sdim 377314564Sdim { 378314564Sdim dump_stream.Printf("Target:\n"); 379309124Sdim 380314564Sdim lldb::addr_t target_address; 381309124Sdim 382314564Sdim map.ReadPointerFromMemory(&target_address, load_addr, err); 383309124Sdim 384314564Sdim if (!err.Success()) { 385314564Sdim dump_stream.Printf(" <could not be read>\n"); 386314564Sdim } else { 387314564Sdim DataBufferHeap data(m_persistent_variable_sp->GetByteSize(), 0); 388309124Sdim 389314564Sdim map.ReadMemory(data.GetBytes(), target_address, 390314564Sdim m_persistent_variable_sp->GetByteSize(), err); 391309124Sdim 392314564Sdim if (!err.Success()) { 393314564Sdim dump_stream.Printf(" <could not be read>\n"); 394314564Sdim } else { 395321369Sdim DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, 396321369Sdim target_address); 397309124Sdim 398314564Sdim dump_stream.PutChar('\n'); 399254721Semaste } 400314564Sdim } 401254721Semaste } 402309124Sdim 403314564Sdim log->PutString(dump_stream.GetString()); 404314564Sdim } 405296417Sdim 406314564Sdim void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {} 407314564Sdim 408254721Semasteprivate: 409314564Sdim lldb::ExpressionVariableSP m_persistent_variable_sp; 410314564Sdim Materializer::PersistentVariableDelegate *m_delegate; 411254721Semaste}; 412254721Semaste 413314564Sdimuint32_t Materializer::AddPersistentVariable( 414314564Sdim lldb::ExpressionVariableSP &persistent_variable_sp, 415321369Sdim PersistentVariableDelegate *delegate, Status &err) { 416314564Sdim EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP()); 417314564Sdim iter->reset(new EntityPersistentVariable(persistent_variable_sp, delegate)); 418314564Sdim uint32_t ret = AddStructMember(**iter); 419314564Sdim (*iter)->SetOffset(ret); 420314564Sdim return ret; 421254721Semaste} 422254721Semaste 423314564Sdimclass EntityVariable : public Materializer::Entity { 424254721Semastepublic: 425314564Sdim EntityVariable(lldb::VariableSP &variable_sp) 426314564Sdim : Entity(), m_variable_sp(variable_sp), m_is_reference(false), 427254721Semaste m_temporary_allocation(LLDB_INVALID_ADDRESS), 428314564Sdim m_temporary_allocation_size(0) { 429314564Sdim // Hard-coding to maximum size of a pointer since all variables are 430314564Sdim // materialized by reference 431314564Sdim m_size = 8; 432314564Sdim m_alignment = 8; 433314564Sdim m_is_reference = 434314564Sdim m_variable_sp->GetType()->GetForwardCompilerType().IsReferenceType(); 435314564Sdim } 436314564Sdim 437314564Sdim void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 438321369Sdim lldb::addr_t process_address, Status &err) override { 439314564Sdim Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); 440314564Sdim 441314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 442314564Sdim if (log) { 443314564Sdim log->Printf("EntityVariable::Materialize [address = 0x%" PRIx64 444314564Sdim ", m_variable_sp = %s]", 445314564Sdim (uint64_t)load_addr, m_variable_sp->GetName().AsCString()); 446254721Semaste } 447309124Sdim 448314564Sdim ExecutionContextScope *scope = frame_sp.get(); 449309124Sdim 450314564Sdim if (!scope) 451314564Sdim scope = map.GetBestExecutionContextScope(); 452309124Sdim 453314564Sdim lldb::ValueObjectSP valobj_sp = 454314564Sdim ValueObjectVariable::Create(scope, m_variable_sp); 455309124Sdim 456314564Sdim if (!valobj_sp) { 457314564Sdim err.SetErrorStringWithFormat( 458314564Sdim "couldn't get a value object for variable %s", 459314564Sdim m_variable_sp->GetName().AsCString()); 460314564Sdim return; 461314564Sdim } 462309124Sdim 463321369Sdim Status valobj_error = valobj_sp->GetError(); 464309124Sdim 465314564Sdim if (valobj_error.Fail()) { 466314564Sdim err.SetErrorStringWithFormat("couldn't get the value of variable %s: %s", 467314564Sdim m_variable_sp->GetName().AsCString(), 468314564Sdim valobj_error.AsCString()); 469314564Sdim return; 470314564Sdim } 471309124Sdim 472314564Sdim if (m_is_reference) { 473314564Sdim DataExtractor valobj_extractor; 474321369Sdim Status extract_error; 475314564Sdim valobj_sp->GetData(valobj_extractor, extract_error); 476309124Sdim 477314564Sdim if (!extract_error.Success()) { 478314564Sdim err.SetErrorStringWithFormat( 479314564Sdim "couldn't read contents of reference variable %s: %s", 480314564Sdim m_variable_sp->GetName().AsCString(), extract_error.AsCString()); 481314564Sdim return; 482314564Sdim } 483309124Sdim 484314564Sdim lldb::offset_t offset = 0; 485314564Sdim lldb::addr_t reference_addr = valobj_extractor.GetAddress(&offset); 486309124Sdim 487321369Sdim Status write_error; 488314564Sdim map.WritePointerToMemory(load_addr, reference_addr, write_error); 489309124Sdim 490314564Sdim if (!write_error.Success()) { 491314564Sdim err.SetErrorStringWithFormat("couldn't write the contents of reference " 492314564Sdim "variable %s to memory: %s", 493314564Sdim m_variable_sp->GetName().AsCString(), 494314564Sdim write_error.AsCString()); 495314564Sdim return; 496314564Sdim } 497314564Sdim } else { 498314564Sdim AddressType address_type = eAddressTypeInvalid; 499314564Sdim const bool scalar_is_load_address = false; 500314564Sdim lldb::addr_t addr_of_valobj = 501314564Sdim valobj_sp->GetAddressOf(scalar_is_load_address, &address_type); 502314564Sdim if (addr_of_valobj != LLDB_INVALID_ADDRESS) { 503321369Sdim Status write_error; 504314564Sdim map.WritePointerToMemory(load_addr, addr_of_valobj, write_error); 505309124Sdim 506314564Sdim if (!write_error.Success()) { 507314564Sdim err.SetErrorStringWithFormat( 508314564Sdim "couldn't write the address of variable %s to memory: %s", 509314564Sdim m_variable_sp->GetName().AsCString(), write_error.AsCString()); 510314564Sdim return; 511314564Sdim } 512314564Sdim } else { 513314564Sdim DataExtractor data; 514321369Sdim Status extract_error; 515314564Sdim valobj_sp->GetData(data, extract_error); 516314564Sdim if (!extract_error.Success()) { 517314564Sdim err.SetErrorStringWithFormat("couldn't get the value of %s: %s", 518314564Sdim m_variable_sp->GetName().AsCString(), 519314564Sdim extract_error.AsCString()); 520314564Sdim return; 521314564Sdim } 522309124Sdim 523314564Sdim if (m_temporary_allocation != LLDB_INVALID_ADDRESS) { 524314564Sdim err.SetErrorStringWithFormat( 525314564Sdim "trying to create a temporary region for %s but one exists", 526314564Sdim m_variable_sp->GetName().AsCString()); 527314564Sdim return; 528254721Semaste } 529309124Sdim 530314564Sdim if (data.GetByteSize() < m_variable_sp->GetType()->GetByteSize()) { 531314564Sdim if (data.GetByteSize() == 0 && 532344779Sdim !m_variable_sp->LocationExpression().IsValid()) { 533314564Sdim err.SetErrorStringWithFormat("the variable '%s' has no location, " 534314564Sdim "it may have been optimized out", 535314564Sdim m_variable_sp->GetName().AsCString()); 536314564Sdim } else { 537314564Sdim err.SetErrorStringWithFormat( 538314564Sdim "size of variable %s (%" PRIu64 539314564Sdim ") is larger than the ValueObject's size (%" PRIu64 ")", 540314564Sdim m_variable_sp->GetName().AsCString(), 541314564Sdim m_variable_sp->GetType()->GetByteSize(), data.GetByteSize()); 542314564Sdim } 543314564Sdim return; 544314564Sdim } 545309124Sdim 546314564Sdim size_t bit_align = 547314564Sdim m_variable_sp->GetType()->GetLayoutCompilerType().GetTypeBitAlign(); 548314564Sdim size_t byte_align = (bit_align + 7) / 8; 549309124Sdim 550314564Sdim if (!byte_align) 551314564Sdim byte_align = 1; 552309124Sdim 553321369Sdim Status alloc_error; 554314564Sdim const bool zero_memory = false; 555309124Sdim 556314564Sdim m_temporary_allocation = map.Malloc( 557314564Sdim data.GetByteSize(), byte_align, 558314564Sdim lldb::ePermissionsReadable | lldb::ePermissionsWritable, 559314564Sdim IRMemoryMap::eAllocationPolicyMirror, zero_memory, alloc_error); 560309124Sdim 561314564Sdim m_temporary_allocation_size = data.GetByteSize(); 562296417Sdim 563314564Sdim m_original_data.reset( 564314564Sdim new DataBufferHeap(data.GetDataStart(), data.GetByteSize())); 565309124Sdim 566314564Sdim if (!alloc_error.Success()) { 567314564Sdim err.SetErrorStringWithFormat( 568314564Sdim "couldn't allocate a temporary region for %s: %s", 569314564Sdim m_variable_sp->GetName().AsCString(), alloc_error.AsCString()); 570314564Sdim return; 571314564Sdim } 572309124Sdim 573321369Sdim Status write_error; 574309124Sdim 575314564Sdim map.WriteMemory(m_temporary_allocation, data.GetDataStart(), 576314564Sdim data.GetByteSize(), write_error); 577309124Sdim 578314564Sdim if (!write_error.Success()) { 579314564Sdim err.SetErrorStringWithFormat( 580314564Sdim "couldn't write to the temporary region for %s: %s", 581314564Sdim m_variable_sp->GetName().AsCString(), write_error.AsCString()); 582314564Sdim return; 583314564Sdim } 584309124Sdim 585321369Sdim Status pointer_write_error; 586309124Sdim 587314564Sdim map.WritePointerToMemory(load_addr, m_temporary_allocation, 588314564Sdim pointer_write_error); 589309124Sdim 590314564Sdim if (!pointer_write_error.Success()) { 591314564Sdim err.SetErrorStringWithFormat( 592314564Sdim "couldn't write the address of the temporary region for %s: %s", 593314564Sdim m_variable_sp->GetName().AsCString(), 594314564Sdim pointer_write_error.AsCString()); 595254721Semaste } 596314564Sdim } 597254721Semaste } 598314564Sdim } 599309124Sdim 600314564Sdim void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 601314564Sdim lldb::addr_t process_address, lldb::addr_t frame_top, 602321369Sdim lldb::addr_t frame_bottom, Status &err) override { 603314564Sdim Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); 604254721Semaste 605314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 606314564Sdim if (log) { 607314564Sdim log->Printf("EntityVariable::Dematerialize [address = 0x%" PRIx64 608314564Sdim ", m_variable_sp = %s]", 609314564Sdim (uint64_t)load_addr, m_variable_sp->GetName().AsCString()); 610314564Sdim } 611309124Sdim 612314564Sdim if (m_temporary_allocation != LLDB_INVALID_ADDRESS) { 613314564Sdim ExecutionContextScope *scope = frame_sp.get(); 614309124Sdim 615314564Sdim if (!scope) 616314564Sdim scope = map.GetBestExecutionContextScope(); 617309124Sdim 618314564Sdim lldb::ValueObjectSP valobj_sp = 619314564Sdim ValueObjectVariable::Create(scope, m_variable_sp); 620309124Sdim 621314564Sdim if (!valobj_sp) { 622314564Sdim err.SetErrorStringWithFormat( 623314564Sdim "couldn't get a value object for variable %s", 624314564Sdim m_variable_sp->GetName().AsCString()); 625314564Sdim return; 626314564Sdim } 627309124Sdim 628314564Sdim lldb_private::DataExtractor data; 629309124Sdim 630321369Sdim Status extract_error; 631309124Sdim 632314564Sdim map.GetMemoryData(data, m_temporary_allocation, valobj_sp->GetByteSize(), 633314564Sdim extract_error); 634309124Sdim 635314564Sdim if (!extract_error.Success()) { 636314564Sdim err.SetErrorStringWithFormat("couldn't get the data for variable %s", 637314564Sdim m_variable_sp->GetName().AsCString()); 638314564Sdim return; 639314564Sdim } 640309124Sdim 641314564Sdim bool actually_write = true; 642309124Sdim 643314564Sdim if (m_original_data) { 644314564Sdim if ((data.GetByteSize() == m_original_data->GetByteSize()) && 645314564Sdim !memcmp(m_original_data->GetBytes(), data.GetDataStart(), 646314564Sdim data.GetByteSize())) { 647314564Sdim actually_write = false; 648314564Sdim } 649314564Sdim } 650309124Sdim 651321369Sdim Status set_error; 652309124Sdim 653314564Sdim if (actually_write) { 654314564Sdim valobj_sp->SetData(data, set_error); 655309124Sdim 656314564Sdim if (!set_error.Success()) { 657314564Sdim err.SetErrorStringWithFormat( 658314564Sdim "couldn't write the new contents of %s back into the variable", 659314564Sdim m_variable_sp->GetName().AsCString()); 660314564Sdim return; 661314564Sdim } 662314564Sdim } 663309124Sdim 664321369Sdim Status free_error; 665309124Sdim 666314564Sdim map.Free(m_temporary_allocation, free_error); 667309124Sdim 668314564Sdim if (!free_error.Success()) { 669314564Sdim err.SetErrorStringWithFormat( 670314564Sdim "couldn't free the temporary region for %s: %s", 671314564Sdim m_variable_sp->GetName().AsCString(), free_error.AsCString()); 672314564Sdim return; 673314564Sdim } 674309124Sdim 675314564Sdim m_original_data.reset(); 676314564Sdim m_temporary_allocation = LLDB_INVALID_ADDRESS; 677314564Sdim m_temporary_allocation_size = 0; 678254721Semaste } 679314564Sdim } 680309124Sdim 681314564Sdim void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address, 682314564Sdim Log *log) override { 683314564Sdim StreamString dump_stream; 684254721Semaste 685314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 686314564Sdim dump_stream.Printf("0x%" PRIx64 ": EntityVariable\n", load_addr); 687309124Sdim 688321369Sdim Status err; 689309124Sdim 690314564Sdim lldb::addr_t ptr = LLDB_INVALID_ADDRESS; 691309124Sdim 692314564Sdim { 693314564Sdim dump_stream.Printf("Pointer:\n"); 694309124Sdim 695314564Sdim DataBufferHeap data(m_size, 0); 696309124Sdim 697314564Sdim map.ReadMemory(data.GetBytes(), load_addr, m_size, err); 698309124Sdim 699314564Sdim if (!err.Success()) { 700314564Sdim dump_stream.Printf(" <could not be read>\n"); 701314564Sdim } else { 702314564Sdim DataExtractor extractor(data.GetBytes(), data.GetByteSize(), 703314564Sdim map.GetByteOrder(), map.GetAddressByteSize()); 704309124Sdim 705321369Sdim DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, 706321369Sdim load_addr); 707309124Sdim 708314564Sdim lldb::offset_t offset; 709309124Sdim 710314564Sdim ptr = extractor.GetPointer(&offset); 711309124Sdim 712314564Sdim dump_stream.PutChar('\n'); 713314564Sdim } 714314564Sdim } 715309124Sdim 716314564Sdim if (m_temporary_allocation == LLDB_INVALID_ADDRESS) { 717314564Sdim dump_stream.Printf("Points to process memory:\n"); 718314564Sdim } else { 719314564Sdim dump_stream.Printf("Temporary allocation:\n"); 720314564Sdim } 721309124Sdim 722314564Sdim if (ptr == LLDB_INVALID_ADDRESS) { 723314564Sdim dump_stream.Printf(" <could not be be found>\n"); 724314564Sdim } else { 725314564Sdim DataBufferHeap data(m_temporary_allocation_size, 0); 726309124Sdim 727314564Sdim map.ReadMemory(data.GetBytes(), m_temporary_allocation, 728314564Sdim m_temporary_allocation_size, err); 729309124Sdim 730314564Sdim if (!err.Success()) { 731314564Sdim dump_stream.Printf(" <could not be read>\n"); 732314564Sdim } else { 733321369Sdim DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, 734321369Sdim load_addr); 735309124Sdim 736314564Sdim dump_stream.PutChar('\n'); 737314564Sdim } 738254721Semaste } 739309124Sdim 740314564Sdim log->PutString(dump_stream.GetString()); 741314564Sdim } 742309124Sdim 743314564Sdim void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override { 744314564Sdim if (m_temporary_allocation != LLDB_INVALID_ADDRESS) { 745321369Sdim Status free_error; 746309124Sdim 747314564Sdim map.Free(m_temporary_allocation, free_error); 748254721Semaste 749314564Sdim m_temporary_allocation = LLDB_INVALID_ADDRESS; 750314564Sdim m_temporary_allocation_size = 0; 751254721Semaste } 752314564Sdim } 753296417Sdim 754254721Semasteprivate: 755314564Sdim lldb::VariableSP m_variable_sp; 756314564Sdim bool m_is_reference; 757314564Sdim lldb::addr_t m_temporary_allocation; 758314564Sdim size_t m_temporary_allocation_size; 759314564Sdim lldb::DataBufferSP m_original_data; 760254721Semaste}; 761254721Semaste 762321369Sdimuint32_t Materializer::AddVariable(lldb::VariableSP &variable_sp, Status &err) { 763314564Sdim EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP()); 764314564Sdim iter->reset(new EntityVariable(variable_sp)); 765314564Sdim uint32_t ret = AddStructMember(**iter); 766314564Sdim (*iter)->SetOffset(ret); 767314564Sdim return ret; 768254721Semaste} 769254721Semaste 770314564Sdimclass EntityResultVariable : public Materializer::Entity { 771254721Semastepublic: 772314564Sdim EntityResultVariable(const CompilerType &type, bool is_program_reference, 773314564Sdim bool keep_in_memory, 774314564Sdim Materializer::PersistentVariableDelegate *delegate) 775314564Sdim : Entity(), m_type(type), m_is_program_reference(is_program_reference), 776254721Semaste m_keep_in_memory(keep_in_memory), 777254721Semaste m_temporary_allocation(LLDB_INVALID_ADDRESS), 778314564Sdim m_temporary_allocation_size(0), m_delegate(delegate) { 779314564Sdim // Hard-coding to maximum size of a pointer since all results are 780314564Sdim // materialized by reference 781314564Sdim m_size = 8; 782314564Sdim m_alignment = 8; 783314564Sdim } 784309124Sdim 785314564Sdim void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 786321369Sdim lldb::addr_t process_address, Status &err) override { 787314564Sdim if (!m_is_program_reference) { 788314564Sdim if (m_temporary_allocation != LLDB_INVALID_ADDRESS) { 789314564Sdim err.SetErrorString("Trying to create a temporary region for the result " 790314564Sdim "but one exists"); 791314564Sdim return; 792314564Sdim } 793309124Sdim 794314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 795254721Semaste 796314564Sdim ExecutionContextScope *exe_scope = map.GetBestExecutionContextScope(); 797309124Sdim 798344779Sdim llvm::Optional<uint64_t> byte_size = m_type.GetByteSize(exe_scope); 799344779Sdim if (!byte_size) { 800344779Sdim err.SetErrorString("can't get size of type"); 801344779Sdim return; 802344779Sdim } 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( 813344779Sdim *byte_size, byte_align, 814314564Sdim lldb::ePermissionsReadable | lldb::ePermissionsWritable, 815314564Sdim IRMemoryMap::eAllocationPolicyMirror, zero_memory, alloc_error); 816344779Sdim 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 892341825Sdim ConstString name = 893341825Sdim m_delegate 894341825Sdim ? m_delegate->GetName() 895341825Sdim : persistent_state->GetNextPersistentVariableName( 896341825Sdim *target_sp, persistent_state->GetPersistentVariablePrefix()); 897309124Sdim 898314564Sdim lldb::ExpressionVariableSP ret = persistent_state->CreatePersistentVariable( 899314564Sdim exe_scope, name, m_type, map.GetByteOrder(), map.GetAddressByteSize()); 900309124Sdim 901314564Sdim if (!ret) { 902314564Sdim err.SetErrorStringWithFormat("couldn't dematerialize a result variable: " 903314564Sdim "failed to make persistent variable %s", 904314564Sdim name.AsCString()); 905314564Sdim return; 906314564Sdim } 907309124Sdim 908314564Sdim lldb::ProcessSP process_sp = 909314564Sdim map.GetBestExecutionContextScope()->CalculateProcess(); 910309124Sdim 911314564Sdim if (m_delegate) { 912314564Sdim m_delegate->DidDematerialize(ret); 913314564Sdim } 914309124Sdim 915314564Sdim bool can_persist = 916314564Sdim (m_is_program_reference && process_sp && process_sp->CanJIT() && 917314564Sdim !(address >= frame_bottom && address < frame_top)); 918254721Semaste 919314564Sdim if (can_persist && m_keep_in_memory) { 920314564Sdim ret->m_live_sp = ValueObjectConstResult::Create(exe_scope, m_type, name, 921314564Sdim address, eAddressTypeLoad, 922314564Sdim map.GetAddressByteSize()); 923314564Sdim } 924309124Sdim 925314564Sdim ret->ValueUpdated(); 926309124Sdim 927314564Sdim const size_t pvar_byte_size = ret->GetByteSize(); 928314564Sdim uint8_t *pvar_data = ret->GetValueBytes(); 929309124Sdim 930314564Sdim map.ReadMemory(pvar_data, address, pvar_byte_size, read_error); 931309124Sdim 932314564Sdim if (!read_error.Success()) { 933314564Sdim err.SetErrorString( 934314564Sdim "Couldn't dematerialize a result variable: couldn't read its memory"); 935314564Sdim return; 936314564Sdim } 937309124Sdim 938314564Sdim if (!can_persist || !m_keep_in_memory) { 939314564Sdim ret->m_flags |= ExpressionVariable::EVNeedsAllocation; 940309124Sdim 941314564Sdim if (m_temporary_allocation != LLDB_INVALID_ADDRESS) { 942321369Sdim Status free_error; 943314564Sdim map.Free(m_temporary_allocation, free_error); 944314564Sdim } 945314564Sdim } else { 946314564Sdim ret->m_flags |= ExpressionVariable::EVIsLLDBAllocated; 947254721Semaste } 948309124Sdim 949314564Sdim m_temporary_allocation = LLDB_INVALID_ADDRESS; 950314564Sdim m_temporary_allocation_size = 0; 951314564Sdim } 952309124Sdim 953314564Sdim void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address, 954314564Sdim Log *log) override { 955314564Sdim StreamString dump_stream; 956254721Semaste 957314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 958309124Sdim 959314564Sdim dump_stream.Printf("0x%" PRIx64 ": EntityResultVariable\n", load_addr); 960309124Sdim 961321369Sdim Status err; 962309124Sdim 963314564Sdim lldb::addr_t ptr = LLDB_INVALID_ADDRESS; 964309124Sdim 965314564Sdim { 966314564Sdim dump_stream.Printf("Pointer:\n"); 967309124Sdim 968314564Sdim DataBufferHeap data(m_size, 0); 969309124Sdim 970314564Sdim map.ReadMemory(data.GetBytes(), load_addr, m_size, err); 971309124Sdim 972314564Sdim if (!err.Success()) { 973314564Sdim dump_stream.Printf(" <could not be read>\n"); 974314564Sdim } else { 975314564Sdim DataExtractor extractor(data.GetBytes(), data.GetByteSize(), 976314564Sdim map.GetByteOrder(), map.GetAddressByteSize()); 977309124Sdim 978321369Sdim DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, 979321369Sdim load_addr); 980309124Sdim 981314564Sdim lldb::offset_t offset; 982309124Sdim 983314564Sdim ptr = extractor.GetPointer(&offset); 984309124Sdim 985314564Sdim dump_stream.PutChar('\n'); 986314564Sdim } 987314564Sdim } 988309124Sdim 989314564Sdim if (m_temporary_allocation == LLDB_INVALID_ADDRESS) { 990314564Sdim dump_stream.Printf("Points to process memory:\n"); 991314564Sdim } else { 992314564Sdim dump_stream.Printf("Temporary allocation:\n"); 993314564Sdim } 994309124Sdim 995314564Sdim if (ptr == LLDB_INVALID_ADDRESS) { 996314564Sdim dump_stream.Printf(" <could not be be found>\n"); 997314564Sdim } else { 998314564Sdim DataBufferHeap data(m_temporary_allocation_size, 0); 999309124Sdim 1000314564Sdim map.ReadMemory(data.GetBytes(), m_temporary_allocation, 1001314564Sdim m_temporary_allocation_size, err); 1002309124Sdim 1003314564Sdim if (!err.Success()) { 1004314564Sdim dump_stream.Printf(" <could not be read>\n"); 1005314564Sdim } else { 1006321369Sdim DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, 1007321369Sdim load_addr); 1008309124Sdim 1009314564Sdim dump_stream.PutChar('\n'); 1010314564Sdim } 1011254721Semaste } 1012309124Sdim 1013314564Sdim log->PutString(dump_stream.GetString()); 1014314564Sdim } 1015309124Sdim 1016314564Sdim void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override { 1017314564Sdim if (!m_keep_in_memory && m_temporary_allocation != LLDB_INVALID_ADDRESS) { 1018321369Sdim Status free_error; 1019309124Sdim 1020314564Sdim map.Free(m_temporary_allocation, free_error); 1021254721Semaste } 1022296417Sdim 1023314564Sdim m_temporary_allocation = LLDB_INVALID_ADDRESS; 1024314564Sdim m_temporary_allocation_size = 0; 1025314564Sdim } 1026314564Sdim 1027254721Semasteprivate: 1028314564Sdim CompilerType m_type; 1029314564Sdim bool m_is_program_reference; 1030314564Sdim bool m_keep_in_memory; 1031309124Sdim 1032314564Sdim lldb::addr_t m_temporary_allocation; 1033314564Sdim size_t m_temporary_allocation_size; 1034314564Sdim Materializer::PersistentVariableDelegate *m_delegate; 1035254721Semaste}; 1036254721Semaste 1037314564Sdimuint32_t Materializer::AddResultVariable(const CompilerType &type, 1038314564Sdim bool is_program_reference, 1039314564Sdim bool keep_in_memory, 1040314564Sdim PersistentVariableDelegate *delegate, 1041321369Sdim Status &err) { 1042314564Sdim EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP()); 1043314564Sdim iter->reset(new EntityResultVariable(type, is_program_reference, 1044314564Sdim keep_in_memory, delegate)); 1045314564Sdim uint32_t ret = AddStructMember(**iter); 1046314564Sdim (*iter)->SetOffset(ret); 1047314564Sdim return ret; 1048254721Semaste} 1049254721Semaste 1050314564Sdimclass EntitySymbol : public Materializer::Entity { 1051254721Semastepublic: 1052314564Sdim EntitySymbol(const Symbol &symbol) : Entity(), m_symbol(symbol) { 1053314564Sdim // Hard-coding to maximum size of a symbol 1054314564Sdim m_size = 8; 1055314564Sdim m_alignment = 8; 1056314564Sdim } 1057309124Sdim 1058314564Sdim void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 1059321369Sdim lldb::addr_t process_address, Status &err) override { 1060314564Sdim Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); 1061254721Semaste 1062314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 1063254721Semaste 1064314564Sdim if (log) { 1065314564Sdim log->Printf("EntitySymbol::Materialize [address = 0x%" PRIx64 1066314564Sdim ", m_symbol = %s]", 1067314564Sdim (uint64_t)load_addr, m_symbol.GetName().AsCString()); 1068314564Sdim } 1069309124Sdim 1070314564Sdim const Address sym_address = m_symbol.GetAddress(); 1071254721Semaste 1072314564Sdim ExecutionContextScope *exe_scope = map.GetBestExecutionContextScope(); 1073309124Sdim 1074314564Sdim lldb::TargetSP target_sp; 1075309124Sdim 1076314564Sdim if (exe_scope) 1077314564Sdim target_sp = map.GetBestExecutionContextScope()->CalculateTarget(); 1078309124Sdim 1079314564Sdim if (!target_sp) { 1080314564Sdim err.SetErrorStringWithFormat( 1081314564Sdim "couldn't resolve symbol %s because there is no target", 1082314564Sdim m_symbol.GetName().AsCString()); 1083314564Sdim return; 1084314564Sdim } 1085309124Sdim 1086314564Sdim lldb::addr_t resolved_address = sym_address.GetLoadAddress(target_sp.get()); 1087309124Sdim 1088314564Sdim if (resolved_address == LLDB_INVALID_ADDRESS) 1089314564Sdim resolved_address = sym_address.GetFileAddress(); 1090309124Sdim 1091321369Sdim Status pointer_write_error; 1092309124Sdim 1093314564Sdim map.WritePointerToMemory(load_addr, resolved_address, pointer_write_error); 1094309124Sdim 1095314564Sdim if (!pointer_write_error.Success()) { 1096314564Sdim err.SetErrorStringWithFormat( 1097314564Sdim "couldn't write the address of symbol %s: %s", 1098314564Sdim m_symbol.GetName().AsCString(), pointer_write_error.AsCString()); 1099314564Sdim return; 1100254721Semaste } 1101314564Sdim } 1102309124Sdim 1103314564Sdim void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 1104314564Sdim lldb::addr_t process_address, lldb::addr_t frame_top, 1105321369Sdim lldb::addr_t frame_bottom, Status &err) override { 1106314564Sdim Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); 1107254721Semaste 1108314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 1109254721Semaste 1110314564Sdim if (log) { 1111314564Sdim log->Printf("EntitySymbol::Dematerialize [address = 0x%" PRIx64 1112314564Sdim ", m_symbol = %s]", 1113314564Sdim (uint64_t)load_addr, m_symbol.GetName().AsCString()); 1114254721Semaste } 1115309124Sdim 1116314564Sdim // no work needs to be done 1117314564Sdim } 1118309124Sdim 1119314564Sdim void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address, 1120314564Sdim Log *log) override { 1121314564Sdim StreamString dump_stream; 1122309124Sdim 1123321369Sdim Status err; 1124254721Semaste 1125314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 1126309124Sdim 1127314564Sdim dump_stream.Printf("0x%" PRIx64 ": EntitySymbol (%s)\n", load_addr, 1128314564Sdim m_symbol.GetName().AsCString()); 1129309124Sdim 1130314564Sdim { 1131314564Sdim dump_stream.Printf("Pointer:\n"); 1132309124Sdim 1133314564Sdim DataBufferHeap data(m_size, 0); 1134309124Sdim 1135314564Sdim map.ReadMemory(data.GetBytes(), load_addr, m_size, err); 1136309124Sdim 1137314564Sdim if (!err.Success()) { 1138314564Sdim dump_stream.Printf(" <could not be read>\n"); 1139314564Sdim } else { 1140321369Sdim DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, 1141321369Sdim load_addr); 1142309124Sdim 1143314564Sdim dump_stream.PutChar('\n'); 1144314564Sdim } 1145254721Semaste } 1146309124Sdim 1147314564Sdim log->PutString(dump_stream.GetString()); 1148314564Sdim } 1149296417Sdim 1150314564Sdim void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {} 1151314564Sdim 1152254721Semasteprivate: 1153314564Sdim Symbol m_symbol; 1154254721Semaste}; 1155254721Semaste 1156321369Sdimuint32_t Materializer::AddSymbol(const Symbol &symbol_sp, Status &err) { 1157314564Sdim EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP()); 1158314564Sdim iter->reset(new EntitySymbol(symbol_sp)); 1159314564Sdim uint32_t ret = AddStructMember(**iter); 1160314564Sdim (*iter)->SetOffset(ret); 1161314564Sdim return ret; 1162254721Semaste} 1163254721Semaste 1164314564Sdimclass EntityRegister : public Materializer::Entity { 1165254721Semastepublic: 1166314564Sdim EntityRegister(const RegisterInfo ®ister_info) 1167314564Sdim : Entity(), m_register_info(register_info) { 1168314564Sdim // Hard-coding alignment conservatively 1169314564Sdim m_size = m_register_info.byte_size; 1170314564Sdim m_alignment = m_register_info.byte_size; 1171314564Sdim } 1172314564Sdim 1173314564Sdim void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 1174321369Sdim lldb::addr_t process_address, Status &err) override { 1175314564Sdim Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); 1176314564Sdim 1177314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 1178314564Sdim 1179314564Sdim if (log) { 1180314564Sdim log->Printf("EntityRegister::Materialize [address = 0x%" PRIx64 1181314564Sdim ", m_register_info = %s]", 1182314564Sdim (uint64_t)load_addr, m_register_info.name); 1183254721Semaste } 1184309124Sdim 1185314564Sdim RegisterValue reg_value; 1186309124Sdim 1187314564Sdim if (!frame_sp.get()) { 1188314564Sdim err.SetErrorStringWithFormat( 1189314564Sdim "couldn't materialize register %s without a stack frame", 1190314564Sdim m_register_info.name); 1191314564Sdim return; 1192314564Sdim } 1193254721Semaste 1194314564Sdim lldb::RegisterContextSP reg_context_sp = frame_sp->GetRegisterContext(); 1195254721Semaste 1196314564Sdim if (!reg_context_sp->ReadRegister(&m_register_info, reg_value)) { 1197314564Sdim err.SetErrorStringWithFormat("couldn't read the value of register %s", 1198314564Sdim m_register_info.name); 1199314564Sdim return; 1200314564Sdim } 1201309124Sdim 1202314564Sdim DataExtractor register_data; 1203309124Sdim 1204314564Sdim if (!reg_value.GetData(register_data)) { 1205314564Sdim err.SetErrorStringWithFormat("couldn't get the data for register %s", 1206314564Sdim m_register_info.name); 1207314564Sdim return; 1208314564Sdim } 1209309124Sdim 1210314564Sdim if (register_data.GetByteSize() != m_register_info.byte_size) { 1211314564Sdim err.SetErrorStringWithFormat( 1212314564Sdim "data for register %s had size %llu but we expected %llu", 1213314564Sdim m_register_info.name, (unsigned long long)register_data.GetByteSize(), 1214314564Sdim (unsigned long long)m_register_info.byte_size); 1215314564Sdim return; 1216314564Sdim } 1217309124Sdim 1218314564Sdim m_register_contents.reset(new DataBufferHeap(register_data.GetDataStart(), 1219314564Sdim register_data.GetByteSize())); 1220309124Sdim 1221321369Sdim Status write_error; 1222309124Sdim 1223314564Sdim map.WriteMemory(load_addr, register_data.GetDataStart(), 1224314564Sdim register_data.GetByteSize(), write_error); 1225309124Sdim 1226314564Sdim if (!write_error.Success()) { 1227314564Sdim err.SetErrorStringWithFormat( 1228314564Sdim "couldn't write the contents of register %s: %s", 1229314564Sdim m_register_info.name, write_error.AsCString()); 1230314564Sdim return; 1231254721Semaste } 1232314564Sdim } 1233309124Sdim 1234314564Sdim void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 1235314564Sdim lldb::addr_t process_address, lldb::addr_t frame_top, 1236321369Sdim lldb::addr_t frame_bottom, Status &err) override { 1237314564Sdim Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)); 1238309124Sdim 1239314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 1240254721Semaste 1241314564Sdim if (log) { 1242314564Sdim log->Printf("EntityRegister::Dematerialize [address = 0x%" PRIx64 1243314564Sdim ", m_register_info = %s]", 1244314564Sdim (uint64_t)load_addr, m_register_info.name); 1245314564Sdim } 1246309124Sdim 1247321369Sdim Status extract_error; 1248309124Sdim 1249314564Sdim DataExtractor register_data; 1250309124Sdim 1251314564Sdim if (!frame_sp.get()) { 1252314564Sdim err.SetErrorStringWithFormat( 1253314564Sdim "couldn't dematerialize register %s without a stack frame", 1254314564Sdim m_register_info.name); 1255314564Sdim return; 1256314564Sdim } 1257309124Sdim 1258314564Sdim lldb::RegisterContextSP reg_context_sp = frame_sp->GetRegisterContext(); 1259309124Sdim 1260314564Sdim map.GetMemoryData(register_data, load_addr, m_register_info.byte_size, 1261314564Sdim extract_error); 1262309124Sdim 1263314564Sdim if (!extract_error.Success()) { 1264314564Sdim err.SetErrorStringWithFormat("couldn't get the data for register %s: %s", 1265314564Sdim m_register_info.name, 1266314564Sdim extract_error.AsCString()); 1267314564Sdim return; 1268314564Sdim } 1269309124Sdim 1270314564Sdim if (!memcmp(register_data.GetDataStart(), m_register_contents->GetBytes(), 1271314564Sdim register_data.GetByteSize())) { 1272314564Sdim // No write required, and in particular we avoid errors if the register 1273314564Sdim // wasn't writable 1274309124Sdim 1275314564Sdim m_register_contents.reset(); 1276314564Sdim return; 1277314564Sdim } 1278309124Sdim 1279314564Sdim m_register_contents.reset(); 1280309124Sdim 1281314564Sdim RegisterValue register_value( 1282314564Sdim const_cast<uint8_t *>(register_data.GetDataStart()), 1283314564Sdim register_data.GetByteSize(), register_data.GetByteOrder()); 1284309124Sdim 1285314564Sdim if (!reg_context_sp->WriteRegister(&m_register_info, register_value)) { 1286314564Sdim err.SetErrorStringWithFormat("couldn't write the value of register %s", 1287314564Sdim m_register_info.name); 1288314564Sdim return; 1289254721Semaste } 1290314564Sdim } 1291309124Sdim 1292314564Sdim void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address, 1293314564Sdim Log *log) override { 1294314564Sdim StreamString dump_stream; 1295309124Sdim 1296321369Sdim Status err; 1297309124Sdim 1298314564Sdim const lldb::addr_t load_addr = process_address + m_offset; 1299254721Semaste 1300314564Sdim dump_stream.Printf("0x%" PRIx64 ": EntityRegister (%s)\n", load_addr, 1301314564Sdim m_register_info.name); 1302309124Sdim 1303314564Sdim { 1304314564Sdim dump_stream.Printf("Value:\n"); 1305309124Sdim 1306314564Sdim DataBufferHeap data(m_size, 0); 1307309124Sdim 1308314564Sdim map.ReadMemory(data.GetBytes(), load_addr, m_size, err); 1309309124Sdim 1310314564Sdim if (!err.Success()) { 1311314564Sdim dump_stream.Printf(" <could not be read>\n"); 1312314564Sdim } else { 1313321369Sdim DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, 1314321369Sdim load_addr); 1315309124Sdim 1316314564Sdim dump_stream.PutChar('\n'); 1317314564Sdim } 1318314564Sdim } 1319309124Sdim 1320314564Sdim log->PutString(dump_stream.GetString()); 1321314564Sdim } 1322309124Sdim 1323314564Sdim void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {} 1324309124Sdim 1325254721Semasteprivate: 1326314564Sdim RegisterInfo m_register_info; 1327314564Sdim lldb::DataBufferSP m_register_contents; 1328254721Semaste}; 1329254721Semaste 1330314564Sdimuint32_t Materializer::AddRegister(const RegisterInfo ®ister_info, 1331321369Sdim Status &err) { 1332314564Sdim EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP()); 1333314564Sdim iter->reset(new EntityRegister(register_info)); 1334314564Sdim uint32_t ret = AddStructMember(**iter); 1335314564Sdim (*iter)->SetOffset(ret); 1336314564Sdim return ret; 1337254721Semaste} 1338254721Semaste 1339314564SdimMaterializer::Materializer() 1340314564Sdim : m_dematerializer_wp(), m_current_offset(0), m_struct_alignment(8) {} 1341254721Semaste 1342314564SdimMaterializer::~Materializer() { 1343314564Sdim DematerializerSP dematerializer_sp = m_dematerializer_wp.lock(); 1344309124Sdim 1345314564Sdim if (dematerializer_sp) 1346314564Sdim dematerializer_sp->Wipe(); 1347254721Semaste} 1348254721Semaste 1349254721SemasteMaterializer::DematerializerSP 1350314564SdimMaterializer::Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 1351321369Sdim lldb::addr_t process_address, Status &error) { 1352314564Sdim ExecutionContextScope *exe_scope = frame_sp.get(); 1353276479Sdim 1354314564Sdim if (!exe_scope) 1355314564Sdim exe_scope = map.GetBestExecutionContextScope(); 1356276479Sdim 1357314564Sdim DematerializerSP dematerializer_sp = m_dematerializer_wp.lock(); 1358276479Sdim 1359314564Sdim if (dematerializer_sp) { 1360314564Sdim error.SetErrorToGenericError(); 1361314564Sdim error.SetErrorString("Couldn't materialize: already materialized"); 1362314564Sdim } 1363276479Sdim 1364314564Sdim DematerializerSP ret( 1365314564Sdim new Dematerializer(*this, frame_sp, map, process_address)); 1366276479Sdim 1367314564Sdim if (!exe_scope) { 1368314564Sdim error.SetErrorToGenericError(); 1369314564Sdim error.SetErrorString("Couldn't materialize: target doesn't exist"); 1370314564Sdim } 1371276479Sdim 1372314564Sdim for (EntityUP &entity_up : m_entities) { 1373314564Sdim entity_up->Materialize(frame_sp, map, process_address, error); 1374276479Sdim 1375314564Sdim if (!error.Success()) 1376314564Sdim return DematerializerSP(); 1377314564Sdim } 1378276479Sdim 1379314564Sdim if (Log *log = 1380314564Sdim lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)) { 1381314564Sdim log->Printf( 1382314564Sdim "Materializer::Materialize (frame_sp = %p, process_address = 0x%" PRIx64 1383314564Sdim ") materialized:", 1384314564Sdim static_cast<void *>(frame_sp.get()), process_address); 1385314564Sdim for (EntityUP &entity_up : m_entities) 1386314564Sdim entity_up->DumpToLog(map, process_address, log); 1387314564Sdim } 1388276479Sdim 1389314564Sdim m_dematerializer_wp = ret; 1390276479Sdim 1391314564Sdim return ret; 1392254721Semaste} 1393254721Semaste 1394321369Sdimvoid Materializer::Dematerializer::Dematerialize(Status &error, 1395314564Sdim lldb::addr_t frame_bottom, 1396314564Sdim lldb::addr_t frame_top) { 1397314564Sdim lldb::StackFrameSP frame_sp; 1398254721Semaste 1399314564Sdim lldb::ThreadSP thread_sp = m_thread_wp.lock(); 1400314564Sdim if (thread_sp) 1401314564Sdim frame_sp = thread_sp->GetFrameWithStackID(m_stack_id); 1402276479Sdim 1403314564Sdim ExecutionContextScope *exe_scope = m_map->GetBestExecutionContextScope(); 1404276479Sdim 1405314564Sdim if (!IsValid()) { 1406314564Sdim error.SetErrorToGenericError(); 1407314564Sdim error.SetErrorString("Couldn't dematerialize: invalid dematerializer"); 1408314564Sdim } 1409276479Sdim 1410314564Sdim if (!exe_scope) { 1411314564Sdim error.SetErrorToGenericError(); 1412314564Sdim error.SetErrorString("Couldn't dematerialize: target is gone"); 1413314564Sdim } else { 1414314564Sdim if (Log *log = 1415314564Sdim lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)) { 1416314564Sdim log->Printf("Materializer::Dematerialize (frame_sp = %p, process_address " 1417314564Sdim "= 0x%" PRIx64 ") about to dematerialize:", 1418314564Sdim static_cast<void *>(frame_sp.get()), m_process_address); 1419314564Sdim for (EntityUP &entity_up : m_materializer->m_entities) 1420314564Sdim entity_up->DumpToLog(*m_map, m_process_address, log); 1421254721Semaste } 1422276479Sdim 1423314564Sdim for (EntityUP &entity_up : m_materializer->m_entities) { 1424314564Sdim entity_up->Dematerialize(frame_sp, *m_map, m_process_address, frame_top, 1425314564Sdim frame_bottom, error); 1426276479Sdim 1427314564Sdim if (!error.Success()) 1428314564Sdim break; 1429254721Semaste } 1430314564Sdim } 1431276479Sdim 1432314564Sdim Wipe(); 1433254721Semaste} 1434254721Semaste 1435314564Sdimvoid Materializer::Dematerializer::Wipe() { 1436314564Sdim if (!IsValid()) 1437314564Sdim return; 1438309124Sdim 1439314564Sdim for (EntityUP &entity_up : m_materializer->m_entities) { 1440314564Sdim entity_up->Wipe(*m_map, m_process_address); 1441314564Sdim } 1442254721Semaste 1443314564Sdim m_materializer = nullptr; 1444314564Sdim m_map = nullptr; 1445314564Sdim m_process_address = LLDB_INVALID_ADDRESS; 1446254721Semaste} 1447296417Sdim 1448314564SdimMaterializer::PersistentVariableDelegate::~PersistentVariableDelegate() = 1449314564Sdim default; 1450