1 //===-- Materializer.cpp --------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "lldb/Expression/Materializer.h" 10 #include "lldb/Core/DumpDataExtractor.h" 11 #include "lldb/Core/ValueObjectConstResult.h" 12 #include "lldb/Core/ValueObjectVariable.h" 13 #include "lldb/Expression/ExpressionVariable.h" 14 #include "lldb/Symbol/Symbol.h" 15 #include "lldb/Symbol/Type.h" 16 #include "lldb/Symbol/Variable.h" 17 #include "lldb/Target/ExecutionContext.h" 18 #include "lldb/Target/RegisterContext.h" 19 #include "lldb/Target/StackFrame.h" 20 #include "lldb/Target/Target.h" 21 #include "lldb/Target/Thread.h" 22 #include "lldb/Utility/LLDBLog.h" 23 #include "lldb/Utility/Log.h" 24 #include "lldb/Utility/RegisterValue.h" 25 #include "lldb/lldb-forward.h" 26 27 #include <memory> 28 #include <optional> 29 30 using namespace lldb_private; 31 32 // FIXME: these should be retrieved from the target 33 // instead of being hard-coded. Currently we 34 // assume that persistent vars are materialized 35 // as references, and thus pick the size of a 36 // 64-bit pointer. 37 static constexpr uint32_t g_default_var_alignment = 8; 38 static constexpr uint32_t g_default_var_byte_size = 8; 39 40 uint32_t Materializer::AddStructMember(Entity &entity) { 41 uint32_t size = entity.GetSize(); 42 uint32_t alignment = entity.GetAlignment(); 43 44 uint32_t ret; 45 46 if (m_current_offset == 0) 47 m_struct_alignment = alignment; 48 49 if (m_current_offset % alignment) 50 m_current_offset += (alignment - (m_current_offset % alignment)); 51 52 ret = m_current_offset; 53 54 m_current_offset += size; 55 56 return ret; 57 } 58 59 class EntityPersistentVariable : public Materializer::Entity { 60 public: 61 EntityPersistentVariable(lldb::ExpressionVariableSP &persistent_variable_sp, 62 Materializer::PersistentVariableDelegate *delegate) 63 : Entity(), m_persistent_variable_sp(persistent_variable_sp), 64 m_delegate(delegate) { 65 // Hard-coding to maximum size of a pointer since persistent variables are 66 // materialized by reference 67 m_size = g_default_var_byte_size; 68 m_alignment = g_default_var_alignment; 69 } 70 71 void MakeAllocation(IRMemoryMap &map, Status &err) { 72 Log *log = GetLog(LLDBLog::Expressions); 73 74 // Allocate a spare memory area to store the persistent variable's 75 // contents. 76 77 Status allocate_error; 78 const bool zero_memory = false; 79 80 lldb::addr_t mem = map.Malloc( 81 m_persistent_variable_sp->GetByteSize().value_or(0), 8, 82 lldb::ePermissionsReadable | lldb::ePermissionsWritable, 83 IRMemoryMap::eAllocationPolicyMirror, zero_memory, allocate_error); 84 85 if (!allocate_error.Success()) { 86 err.SetErrorStringWithFormat( 87 "couldn't allocate a memory area to store %s: %s", 88 m_persistent_variable_sp->GetName().GetCString(), 89 allocate_error.AsCString()); 90 return; 91 } 92 93 LLDB_LOGF(log, "Allocated %s (0x%" PRIx64 ") successfully", 94 m_persistent_variable_sp->GetName().GetCString(), mem); 95 96 // Put the location of the spare memory into the live data of the 97 // ValueObject. 98 99 m_persistent_variable_sp->m_live_sp = ValueObjectConstResult::Create( 100 map.GetBestExecutionContextScope(), 101 m_persistent_variable_sp->GetCompilerType(), 102 m_persistent_variable_sp->GetName(), mem, eAddressTypeLoad, 103 map.GetAddressByteSize()); 104 105 // Clear the flag if the variable will never be deallocated. 106 107 if (m_persistent_variable_sp->m_flags & 108 ExpressionVariable::EVKeepInTarget) { 109 Status leak_error; 110 map.Leak(mem, leak_error); 111 m_persistent_variable_sp->m_flags &= 112 ~ExpressionVariable::EVNeedsAllocation; 113 } 114 115 // Write the contents of the variable to the area. 116 117 Status write_error; 118 119 map.WriteMemory(mem, m_persistent_variable_sp->GetValueBytes(), 120 m_persistent_variable_sp->GetByteSize().value_or(0), 121 write_error); 122 123 if (!write_error.Success()) { 124 err.SetErrorStringWithFormat( 125 "couldn't write %s to the target: %s", 126 m_persistent_variable_sp->GetName().AsCString(), 127 write_error.AsCString()); 128 return; 129 } 130 } 131 132 void DestroyAllocation(IRMemoryMap &map, Status &err) { 133 Status deallocate_error; 134 135 map.Free((lldb::addr_t)m_persistent_variable_sp->m_live_sp->GetValue() 136 .GetScalar() 137 .ULongLong(), 138 deallocate_error); 139 140 m_persistent_variable_sp->m_live_sp.reset(); 141 142 if (!deallocate_error.Success()) { 143 err.SetErrorStringWithFormat( 144 "couldn't deallocate memory for %s: %s", 145 m_persistent_variable_sp->GetName().GetCString(), 146 deallocate_error.AsCString()); 147 } 148 } 149 150 void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 151 lldb::addr_t process_address, Status &err) override { 152 Log *log = GetLog(LLDBLog::Expressions); 153 154 const lldb::addr_t load_addr = process_address + m_offset; 155 156 if (log) { 157 LLDB_LOGF(log, 158 "EntityPersistentVariable::Materialize [address = 0x%" PRIx64 159 ", m_name = %s, m_flags = 0x%hx]", 160 (uint64_t)load_addr, 161 m_persistent_variable_sp->GetName().AsCString(), 162 m_persistent_variable_sp->m_flags); 163 } 164 165 if (m_persistent_variable_sp->m_flags & 166 ExpressionVariable::EVNeedsAllocation) { 167 MakeAllocation(map, err); 168 m_persistent_variable_sp->m_flags |= 169 ExpressionVariable::EVIsLLDBAllocated; 170 171 if (!err.Success()) 172 return; 173 } 174 175 if ((m_persistent_variable_sp->m_flags & 176 ExpressionVariable::EVIsProgramReference && 177 m_persistent_variable_sp->m_live_sp) || 178 m_persistent_variable_sp->m_flags & 179 ExpressionVariable::EVIsLLDBAllocated) { 180 Status write_error; 181 182 map.WriteScalarToMemory( 183 load_addr, 184 m_persistent_variable_sp->m_live_sp->GetValue().GetScalar(), 185 map.GetAddressByteSize(), write_error); 186 187 if (!write_error.Success()) { 188 err.SetErrorStringWithFormat( 189 "couldn't write the location of %s to memory: %s", 190 m_persistent_variable_sp->GetName().AsCString(), 191 write_error.AsCString()); 192 } 193 } else { 194 err.SetErrorStringWithFormat( 195 "no materialization happened for persistent variable %s", 196 m_persistent_variable_sp->GetName().AsCString()); 197 return; 198 } 199 } 200 201 void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 202 lldb::addr_t process_address, lldb::addr_t frame_top, 203 lldb::addr_t frame_bottom, Status &err) override { 204 Log *log = GetLog(LLDBLog::Expressions); 205 206 const lldb::addr_t load_addr = process_address + m_offset; 207 208 if (log) { 209 LLDB_LOGF(log, 210 "EntityPersistentVariable::Dematerialize [address = 0x%" PRIx64 211 ", m_name = %s, m_flags = 0x%hx]", 212 (uint64_t)process_address + m_offset, 213 m_persistent_variable_sp->GetName().AsCString(), 214 m_persistent_variable_sp->m_flags); 215 } 216 217 if (m_delegate) { 218 m_delegate->DidDematerialize(m_persistent_variable_sp); 219 } 220 221 if ((m_persistent_variable_sp->m_flags & 222 ExpressionVariable::EVIsLLDBAllocated) || 223 (m_persistent_variable_sp->m_flags & 224 ExpressionVariable::EVIsProgramReference)) { 225 if (m_persistent_variable_sp->m_flags & 226 ExpressionVariable::EVIsProgramReference && 227 !m_persistent_variable_sp->m_live_sp) { 228 // If the reference comes from the program, then the 229 // ClangExpressionVariable's live variable data hasn't been set up yet. 230 // Do this now. 231 232 lldb::addr_t location; 233 Status read_error; 234 235 map.ReadPointerFromMemory(&location, load_addr, read_error); 236 237 if (!read_error.Success()) { 238 err.SetErrorStringWithFormat( 239 "couldn't read the address of program-allocated variable %s: %s", 240 m_persistent_variable_sp->GetName().GetCString(), 241 read_error.AsCString()); 242 return; 243 } 244 245 m_persistent_variable_sp->m_live_sp = ValueObjectConstResult::Create( 246 map.GetBestExecutionContextScope(), 247 m_persistent_variable_sp.get()->GetCompilerType(), 248 m_persistent_variable_sp->GetName(), location, eAddressTypeLoad, 249 m_persistent_variable_sp->GetByteSize().value_or(0)); 250 251 if (frame_top != LLDB_INVALID_ADDRESS && 252 frame_bottom != LLDB_INVALID_ADDRESS && location >= frame_bottom && 253 location <= frame_top) { 254 // If the variable is resident in the stack frame created by the 255 // expression, then it cannot be relied upon to stay around. We 256 // treat it as needing reallocation. 257 m_persistent_variable_sp->m_flags |= 258 ExpressionVariable::EVIsLLDBAllocated; 259 m_persistent_variable_sp->m_flags |= 260 ExpressionVariable::EVNeedsAllocation; 261 m_persistent_variable_sp->m_flags |= 262 ExpressionVariable::EVNeedsFreezeDry; 263 m_persistent_variable_sp->m_flags &= 264 ~ExpressionVariable::EVIsProgramReference; 265 } 266 } 267 268 lldb::addr_t mem = m_persistent_variable_sp->m_live_sp->GetValue() 269 .GetScalar() 270 .ULongLong(); 271 272 if (!m_persistent_variable_sp->m_live_sp) { 273 err.SetErrorStringWithFormat( 274 "couldn't find the memory area used to store %s", 275 m_persistent_variable_sp->GetName().GetCString()); 276 return; 277 } 278 279 if (m_persistent_variable_sp->m_live_sp->GetValue() 280 .GetValueAddressType() != eAddressTypeLoad) { 281 err.SetErrorStringWithFormat( 282 "the address of the memory area for %s is in an incorrect format", 283 m_persistent_variable_sp->GetName().GetCString()); 284 return; 285 } 286 287 if (m_persistent_variable_sp->m_flags & 288 ExpressionVariable::EVNeedsFreezeDry || 289 m_persistent_variable_sp->m_flags & 290 ExpressionVariable::EVKeepInTarget) { 291 LLDB_LOGF(log, "Dematerializing %s from 0x%" PRIx64 " (size = %llu)", 292 m_persistent_variable_sp->GetName().GetCString(), 293 (uint64_t)mem, 294 (unsigned long long)m_persistent_variable_sp->GetByteSize() 295 .value_or(0)); 296 297 // Read the contents of the spare memory area 298 299 m_persistent_variable_sp->ValueUpdated(); 300 301 Status read_error; 302 303 map.ReadMemory(m_persistent_variable_sp->GetValueBytes(), mem, 304 m_persistent_variable_sp->GetByteSize().value_or(0), 305 read_error); 306 307 if (!read_error.Success()) { 308 err.SetErrorStringWithFormat( 309 "couldn't read the contents of %s from memory: %s", 310 m_persistent_variable_sp->GetName().GetCString(), 311 read_error.AsCString()); 312 return; 313 } 314 315 m_persistent_variable_sp->m_flags &= 316 ~ExpressionVariable::EVNeedsFreezeDry; 317 } 318 } else { 319 err.SetErrorStringWithFormat( 320 "no dematerialization happened for persistent variable %s", 321 m_persistent_variable_sp->GetName().AsCString()); 322 return; 323 } 324 325 lldb::ProcessSP process_sp = 326 map.GetBestExecutionContextScope()->CalculateProcess(); 327 if (!process_sp || !process_sp->CanJIT()) { 328 // Allocations are not persistent so persistent variables cannot stay 329 // materialized. 330 331 m_persistent_variable_sp->m_flags |= 332 ExpressionVariable::EVNeedsAllocation; 333 334 DestroyAllocation(map, err); 335 if (!err.Success()) 336 return; 337 } else if (m_persistent_variable_sp->m_flags & 338 ExpressionVariable::EVNeedsAllocation && 339 !(m_persistent_variable_sp->m_flags & 340 ExpressionVariable::EVKeepInTarget)) { 341 DestroyAllocation(map, err); 342 if (!err.Success()) 343 return; 344 } 345 } 346 347 void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address, 348 Log *log) override { 349 StreamString dump_stream; 350 351 Status err; 352 353 const lldb::addr_t load_addr = process_address + m_offset; 354 355 dump_stream.Printf("0x%" PRIx64 ": EntityPersistentVariable (%s)\n", 356 load_addr, 357 m_persistent_variable_sp->GetName().AsCString()); 358 359 { 360 dump_stream.Printf("Pointer:\n"); 361 362 DataBufferHeap data(m_size, 0); 363 364 map.ReadMemory(data.GetBytes(), load_addr, m_size, err); 365 366 if (!err.Success()) { 367 dump_stream.Printf(" <could not be read>\n"); 368 } else { 369 DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, 370 load_addr); 371 372 dump_stream.PutChar('\n'); 373 } 374 } 375 376 { 377 dump_stream.Printf("Target:\n"); 378 379 lldb::addr_t target_address; 380 381 map.ReadPointerFromMemory(&target_address, load_addr, err); 382 383 if (!err.Success()) { 384 dump_stream.Printf(" <could not be read>\n"); 385 } else { 386 DataBufferHeap data(m_persistent_variable_sp->GetByteSize().value_or(0), 387 0); 388 389 map.ReadMemory(data.GetBytes(), target_address, 390 m_persistent_variable_sp->GetByteSize().value_or(0), 391 err); 392 393 if (!err.Success()) { 394 dump_stream.Printf(" <could not be read>\n"); 395 } else { 396 DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, 397 target_address); 398 399 dump_stream.PutChar('\n'); 400 } 401 } 402 } 403 404 log->PutString(dump_stream.GetString()); 405 } 406 407 void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {} 408 409 private: 410 lldb::ExpressionVariableSP m_persistent_variable_sp; 411 Materializer::PersistentVariableDelegate *m_delegate; 412 }; 413 414 uint32_t Materializer::AddPersistentVariable( 415 lldb::ExpressionVariableSP &persistent_variable_sp, 416 PersistentVariableDelegate *delegate, Status &err) { 417 EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP()); 418 *iter = std::make_unique<EntityPersistentVariable>(persistent_variable_sp, 419 delegate); 420 uint32_t ret = AddStructMember(**iter); 421 (*iter)->SetOffset(ret); 422 return ret; 423 } 424 425 /// Base class for materialization of Variables and ValueObjects. 426 /// 427 /// Subclasses specify how to obtain the Value which is to be 428 /// materialized. 429 class EntityVariableBase : public Materializer::Entity { 430 public: 431 virtual ~EntityVariableBase() = default; 432 433 EntityVariableBase() { 434 // Hard-coding to maximum size of a pointer since all variables are 435 // materialized by reference 436 m_size = g_default_var_byte_size; 437 m_alignment = g_default_var_alignment; 438 } 439 440 void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 441 lldb::addr_t process_address, Status &err) override { 442 Log *log = GetLog(LLDBLog::Expressions); 443 444 const lldb::addr_t load_addr = process_address + m_offset; 445 if (log) { 446 LLDB_LOGF(log, 447 "EntityVariable::Materialize [address = 0x%" PRIx64 448 ", m_variable_sp = %s]", 449 (uint64_t)load_addr, GetName().GetCString()); 450 } 451 452 ExecutionContextScope *scope = frame_sp.get(); 453 454 if (!scope) 455 scope = map.GetBestExecutionContextScope(); 456 457 lldb::ValueObjectSP valobj_sp = SetupValueObject(scope); 458 459 if (!valobj_sp) { 460 err.SetErrorStringWithFormat( 461 "couldn't get a value object for variable %s", GetName().AsCString()); 462 return; 463 } 464 465 Status valobj_error = valobj_sp->GetError(); 466 467 if (valobj_error.Fail()) { 468 err.SetErrorStringWithFormat("couldn't get the value of variable %s: %s", 469 GetName().AsCString(), 470 valobj_error.AsCString()); 471 return; 472 } 473 474 if (m_is_reference) { 475 DataExtractor valobj_extractor; 476 Status extract_error; 477 valobj_sp->GetData(valobj_extractor, extract_error); 478 479 if (!extract_error.Success()) { 480 err.SetErrorStringWithFormat( 481 "couldn't read contents of reference variable %s: %s", 482 GetName().AsCString(), extract_error.AsCString()); 483 return; 484 } 485 486 lldb::offset_t offset = 0; 487 lldb::addr_t reference_addr = valobj_extractor.GetAddress(&offset); 488 489 Status write_error; 490 map.WritePointerToMemory(load_addr, reference_addr, write_error); 491 492 if (!write_error.Success()) { 493 err.SetErrorStringWithFormat("couldn't write the contents of reference " 494 "variable %s to memory: %s", 495 GetName().AsCString(), 496 write_error.AsCString()); 497 return; 498 } 499 } else { 500 AddressType address_type = eAddressTypeInvalid; 501 const bool scalar_is_load_address = false; 502 lldb::addr_t addr_of_valobj = 503 valobj_sp->GetAddressOf(scalar_is_load_address, &address_type); 504 if (addr_of_valobj != LLDB_INVALID_ADDRESS) { 505 Status write_error; 506 map.WritePointerToMemory(load_addr, addr_of_valobj, write_error); 507 508 if (!write_error.Success()) { 509 err.SetErrorStringWithFormat( 510 "couldn't write the address of variable %s to memory: %s", 511 GetName().AsCString(), write_error.AsCString()); 512 return; 513 } 514 } else { 515 DataExtractor data; 516 Status extract_error; 517 valobj_sp->GetData(data, extract_error); 518 if (!extract_error.Success()) { 519 err.SetErrorStringWithFormat("couldn't get the value of %s: %s", 520 GetName().AsCString(), 521 extract_error.AsCString()); 522 return; 523 } 524 525 if (m_temporary_allocation != LLDB_INVALID_ADDRESS) { 526 err.SetErrorStringWithFormat( 527 "trying to create a temporary region for %s but one exists", 528 GetName().AsCString()); 529 return; 530 } 531 532 if (data.GetByteSize() < GetByteSize(scope)) { 533 if (data.GetByteSize() == 0 && !LocationExpressionIsValid()) { 534 err.SetErrorStringWithFormat("the variable '%s' has no location, " 535 "it may have been optimized out", 536 GetName().AsCString()); 537 } else { 538 err.SetErrorStringWithFormat( 539 "size of variable %s (%" PRIu64 540 ") is larger than the ValueObject's size (%" PRIu64 ")", 541 GetName().AsCString(), GetByteSize(scope).value_or(0), 542 data.GetByteSize()); 543 } 544 return; 545 } 546 547 std::optional<size_t> opt_bit_align = GetTypeBitAlign(scope); 548 if (!opt_bit_align) { 549 err.SetErrorStringWithFormat("can't get the type alignment for %s", 550 GetName().AsCString()); 551 return; 552 } 553 554 size_t byte_align = (*opt_bit_align + 7) / 8; 555 556 Status alloc_error; 557 const bool zero_memory = false; 558 559 m_temporary_allocation = map.Malloc( 560 data.GetByteSize(), byte_align, 561 lldb::ePermissionsReadable | lldb::ePermissionsWritable, 562 IRMemoryMap::eAllocationPolicyMirror, zero_memory, alloc_error); 563 564 m_temporary_allocation_size = data.GetByteSize(); 565 566 m_original_data = std::make_shared<DataBufferHeap>(data.GetDataStart(), 567 data.GetByteSize()); 568 569 if (!alloc_error.Success()) { 570 err.SetErrorStringWithFormat( 571 "couldn't allocate a temporary region for %s: %s", 572 GetName().AsCString(), alloc_error.AsCString()); 573 return; 574 } 575 576 Status write_error; 577 578 map.WriteMemory(m_temporary_allocation, data.GetDataStart(), 579 data.GetByteSize(), write_error); 580 581 if (!write_error.Success()) { 582 err.SetErrorStringWithFormat( 583 "couldn't write to the temporary region for %s: %s", 584 GetName().AsCString(), write_error.AsCString()); 585 return; 586 } 587 588 Status pointer_write_error; 589 590 map.WritePointerToMemory(load_addr, m_temporary_allocation, 591 pointer_write_error); 592 593 if (!pointer_write_error.Success()) { 594 err.SetErrorStringWithFormat( 595 "couldn't write the address of the temporary region for %s: %s", 596 GetName().AsCString(), pointer_write_error.AsCString()); 597 } 598 } 599 } 600 } 601 602 void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 603 lldb::addr_t process_address, lldb::addr_t frame_top, 604 lldb::addr_t frame_bottom, Status &err) override { 605 Log *log = GetLog(LLDBLog::Expressions); 606 607 const lldb::addr_t load_addr = process_address + m_offset; 608 if (log) { 609 LLDB_LOGF(log, 610 "EntityVariable::Dematerialize [address = 0x%" PRIx64 611 ", m_variable_sp = %s]", 612 (uint64_t)load_addr, GetName().AsCString()); 613 } 614 615 if (m_temporary_allocation != LLDB_INVALID_ADDRESS) { 616 ExecutionContextScope *scope = frame_sp.get(); 617 618 if (!scope) 619 scope = map.GetBestExecutionContextScope(); 620 621 lldb::ValueObjectSP valobj_sp = SetupValueObject(scope); 622 623 if (!valobj_sp) { 624 err.SetErrorStringWithFormat( 625 "couldn't get a value object for variable %s", 626 GetName().AsCString()); 627 return; 628 } 629 630 lldb_private::DataExtractor data; 631 632 Status extract_error; 633 634 map.GetMemoryData(data, m_temporary_allocation, 635 valobj_sp->GetByteSize().value_or(0), extract_error); 636 637 if (!extract_error.Success()) { 638 err.SetErrorStringWithFormat("couldn't get the data for variable %s", 639 GetName().AsCString()); 640 return; 641 } 642 643 bool actually_write = true; 644 645 if (m_original_data) { 646 if ((data.GetByteSize() == m_original_data->GetByteSize()) && 647 !memcmp(m_original_data->GetBytes(), data.GetDataStart(), 648 data.GetByteSize())) { 649 actually_write = false; 650 } 651 } 652 653 Status set_error; 654 655 if (actually_write) { 656 valobj_sp->SetData(data, set_error); 657 658 if (!set_error.Success()) { 659 err.SetErrorStringWithFormat( 660 "couldn't write the new contents of %s back into the variable", 661 GetName().AsCString()); 662 return; 663 } 664 } 665 666 Status free_error; 667 668 map.Free(m_temporary_allocation, free_error); 669 670 if (!free_error.Success()) { 671 err.SetErrorStringWithFormat( 672 "couldn't free the temporary region for %s: %s", 673 GetName().AsCString(), free_error.AsCString()); 674 return; 675 } 676 677 m_original_data.reset(); 678 m_temporary_allocation = LLDB_INVALID_ADDRESS; 679 m_temporary_allocation_size = 0; 680 } 681 } 682 683 void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address, 684 Log *log) override { 685 StreamString dump_stream; 686 687 const lldb::addr_t load_addr = process_address + m_offset; 688 dump_stream.Printf("0x%" PRIx64 ": EntityVariable\n", load_addr); 689 690 Status err; 691 692 lldb::addr_t ptr = LLDB_INVALID_ADDRESS; 693 694 { 695 dump_stream.Printf("Pointer:\n"); 696 697 DataBufferHeap data(m_size, 0); 698 699 map.ReadMemory(data.GetBytes(), load_addr, m_size, err); 700 701 if (!err.Success()) { 702 dump_stream.Printf(" <could not be read>\n"); 703 } else { 704 DataExtractor extractor(data.GetBytes(), data.GetByteSize(), 705 map.GetByteOrder(), map.GetAddressByteSize()); 706 707 DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, 708 load_addr); 709 710 lldb::offset_t offset = 0; 711 712 ptr = extractor.GetAddress(&offset); 713 714 dump_stream.PutChar('\n'); 715 } 716 } 717 718 if (m_temporary_allocation == LLDB_INVALID_ADDRESS) { 719 dump_stream.Printf("Points to process memory:\n"); 720 } else { 721 dump_stream.Printf("Temporary allocation:\n"); 722 } 723 724 if (ptr == LLDB_INVALID_ADDRESS) { 725 dump_stream.Printf(" <could not be be found>\n"); 726 } else { 727 DataBufferHeap data(m_temporary_allocation_size, 0); 728 729 map.ReadMemory(data.GetBytes(), m_temporary_allocation, 730 m_temporary_allocation_size, err); 731 732 if (!err.Success()) { 733 dump_stream.Printf(" <could not be read>\n"); 734 } else { 735 DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, 736 load_addr); 737 738 dump_stream.PutChar('\n'); 739 } 740 } 741 742 log->PutString(dump_stream.GetString()); 743 } 744 745 void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override { 746 if (m_temporary_allocation != LLDB_INVALID_ADDRESS) { 747 Status free_error; 748 749 map.Free(m_temporary_allocation, free_error); 750 751 m_temporary_allocation = LLDB_INVALID_ADDRESS; 752 m_temporary_allocation_size = 0; 753 } 754 } 755 756 private: 757 virtual ConstString GetName() const = 0; 758 759 /// Creates and returns ValueObject tied to this variable 760 /// and prepares Entity for materialization. 761 /// 762 /// Called each time the Materializer (de)materializes a 763 /// variable. We re-create the ValueObject based on the 764 /// current ExecutionContextScope since clients such as 765 /// conditional breakpoints may materialize the same 766 /// EntityVariable multiple times with different frames. 767 /// 768 /// Each subsequent use of the EntityVariableBase interface 769 /// will query the newly created ValueObject until this 770 /// function is called again. 771 virtual lldb::ValueObjectSP 772 SetupValueObject(ExecutionContextScope *scope) = 0; 773 774 /// Returns size in bytes of the type associated with this variable 775 /// 776 /// \returns On success, returns byte size of the type associated 777 /// with this variable. Returns std::nullopt otherwise. 778 virtual std::optional<uint64_t> 779 GetByteSize(ExecutionContextScope *scope) const = 0; 780 781 /// Returns 'true' if the location expression associated with this variable 782 /// is valid. 783 virtual bool LocationExpressionIsValid() const = 0; 784 785 /// Returns alignment of the type associated with this variable in bits. 786 /// 787 /// \returns On success, returns alignment in bits for the type associated 788 /// with this variable. Returns std::nullopt otherwise. 789 virtual std::optional<size_t> 790 GetTypeBitAlign(ExecutionContextScope *scope) const = 0; 791 792 protected: 793 bool m_is_reference = false; 794 lldb::addr_t m_temporary_allocation = LLDB_INVALID_ADDRESS; 795 size_t m_temporary_allocation_size = 0; 796 lldb::DataBufferSP m_original_data; 797 }; 798 799 /// Represents an Entity constructed from a VariableSP. 800 /// 801 /// This class is used for materialization of variables for which 802 /// the user has a VariableSP on hand. The ValueObject is then 803 /// derived from the associated DWARF location expression when needed 804 /// by the Materializer. 805 class EntityVariable : public EntityVariableBase { 806 public: 807 EntityVariable(lldb::VariableSP &variable_sp) : m_variable_sp(variable_sp) { 808 m_is_reference = 809 m_variable_sp->GetType()->GetForwardCompilerType().IsReferenceType(); 810 } 811 812 ConstString GetName() const override { return m_variable_sp->GetName(); } 813 814 lldb::ValueObjectSP SetupValueObject(ExecutionContextScope *scope) override { 815 assert(m_variable_sp != nullptr); 816 return ValueObjectVariable::Create(scope, m_variable_sp); 817 } 818 819 std::optional<uint64_t> 820 GetByteSize(ExecutionContextScope *scope) const override { 821 return m_variable_sp->GetType()->GetByteSize(scope); 822 } 823 824 bool LocationExpressionIsValid() const override { 825 return m_variable_sp->LocationExpressionList().IsValid(); 826 } 827 828 std::optional<size_t> 829 GetTypeBitAlign(ExecutionContextScope *scope) const override { 830 return m_variable_sp->GetType()->GetLayoutCompilerType().GetTypeBitAlign( 831 scope); 832 } 833 834 private: 835 lldb::VariableSP m_variable_sp; ///< Variable that this entity is based on. 836 }; 837 838 /// Represents an Entity constructed from a VariableSP. 839 /// 840 /// This class is used for materialization of variables for 841 /// which the user does not have a VariableSP available (e.g., 842 /// when materializing ivars). 843 class EntityValueObject : public EntityVariableBase { 844 public: 845 EntityValueObject(ConstString name, ValueObjectProviderTy provider) 846 : m_name(name), m_valobj_provider(std::move(provider)) { 847 assert(m_valobj_provider); 848 } 849 850 ConstString GetName() const override { return m_name; } 851 852 lldb::ValueObjectSP SetupValueObject(ExecutionContextScope *scope) override { 853 m_valobj_sp = 854 m_valobj_provider(GetName(), scope->CalculateStackFrame().get()); 855 856 if (m_valobj_sp) 857 m_is_reference = m_valobj_sp->GetCompilerType().IsReferenceType(); 858 859 return m_valobj_sp; 860 } 861 862 std::optional<uint64_t> 863 GetByteSize(ExecutionContextScope *scope) const override { 864 if (m_valobj_sp) 865 return m_valobj_sp->GetCompilerType().GetByteSize(scope); 866 867 return {}; 868 } 869 870 bool LocationExpressionIsValid() const override { 871 if (m_valobj_sp) 872 return m_valobj_sp->GetError().Success(); 873 874 return false; 875 } 876 877 std::optional<size_t> 878 GetTypeBitAlign(ExecutionContextScope *scope) const override { 879 if (m_valobj_sp) 880 return m_valobj_sp->GetCompilerType().GetTypeBitAlign(scope); 881 882 return {}; 883 } 884 885 private: 886 ConstString m_name; 887 lldb::ValueObjectSP m_valobj_sp; 888 ValueObjectProviderTy m_valobj_provider; 889 }; 890 891 uint32_t Materializer::AddVariable(lldb::VariableSP &variable_sp, Status &err) { 892 EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP()); 893 *iter = std::make_unique<EntityVariable>(variable_sp); 894 uint32_t ret = AddStructMember(**iter); 895 (*iter)->SetOffset(ret); 896 return ret; 897 } 898 899 uint32_t Materializer::AddValueObject(ConstString name, 900 ValueObjectProviderTy valobj_provider, 901 Status &err) { 902 assert(valobj_provider); 903 EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP()); 904 *iter = std::make_unique<EntityValueObject>(name, std::move(valobj_provider)); 905 uint32_t ret = AddStructMember(**iter); 906 (*iter)->SetOffset(ret); 907 return ret; 908 } 909 910 class EntityResultVariable : public Materializer::Entity { 911 public: 912 EntityResultVariable(const CompilerType &type, bool is_program_reference, 913 bool keep_in_memory, 914 Materializer::PersistentVariableDelegate *delegate) 915 : Entity(), m_type(type), m_is_program_reference(is_program_reference), 916 m_keep_in_memory(keep_in_memory), m_delegate(delegate) { 917 // Hard-coding to maximum size of a pointer since all results are 918 // materialized by reference 919 m_size = g_default_var_byte_size; 920 m_alignment = g_default_var_alignment; 921 } 922 923 void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 924 lldb::addr_t process_address, Status &err) override { 925 if (!m_is_program_reference) { 926 if (m_temporary_allocation != LLDB_INVALID_ADDRESS) { 927 err.SetErrorString("Trying to create a temporary region for the result " 928 "but one exists"); 929 return; 930 } 931 932 const lldb::addr_t load_addr = process_address + m_offset; 933 934 ExecutionContextScope *exe_scope = frame_sp.get(); 935 if (!exe_scope) 936 exe_scope = map.GetBestExecutionContextScope(); 937 938 std::optional<uint64_t> byte_size = m_type.GetByteSize(exe_scope); 939 if (!byte_size) { 940 err.SetErrorStringWithFormat("can't get size of type \"%s\"", 941 m_type.GetTypeName().AsCString()); 942 return; 943 } 944 945 std::optional<size_t> opt_bit_align = m_type.GetTypeBitAlign(exe_scope); 946 if (!opt_bit_align) { 947 err.SetErrorStringWithFormat("can't get the alignment of type \"%s\"", 948 m_type.GetTypeName().AsCString()); 949 return; 950 } 951 952 size_t byte_align = (*opt_bit_align + 7) / 8; 953 954 Status alloc_error; 955 const bool zero_memory = true; 956 957 m_temporary_allocation = map.Malloc( 958 *byte_size, byte_align, 959 lldb::ePermissionsReadable | lldb::ePermissionsWritable, 960 IRMemoryMap::eAllocationPolicyMirror, zero_memory, alloc_error); 961 m_temporary_allocation_size = *byte_size; 962 963 if (!alloc_error.Success()) { 964 err.SetErrorStringWithFormat( 965 "couldn't allocate a temporary region for the result: %s", 966 alloc_error.AsCString()); 967 return; 968 } 969 970 Status pointer_write_error; 971 972 map.WritePointerToMemory(load_addr, m_temporary_allocation, 973 pointer_write_error); 974 975 if (!pointer_write_error.Success()) { 976 err.SetErrorStringWithFormat("couldn't write the address of the " 977 "temporary region for the result: %s", 978 pointer_write_error.AsCString()); 979 } 980 } 981 } 982 983 void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 984 lldb::addr_t process_address, lldb::addr_t frame_top, 985 lldb::addr_t frame_bottom, Status &err) override { 986 err.Clear(); 987 988 ExecutionContextScope *exe_scope = frame_sp.get(); 989 if (!exe_scope) 990 exe_scope = map.GetBestExecutionContextScope(); 991 992 if (!exe_scope) { 993 err.SetErrorString("Couldn't dematerialize a result variable: invalid " 994 "execution context scope"); 995 return; 996 } 997 998 lldb::addr_t address; 999 Status read_error; 1000 const lldb::addr_t load_addr = process_address + m_offset; 1001 1002 map.ReadPointerFromMemory(&address, load_addr, read_error); 1003 1004 if (!read_error.Success()) { 1005 err.SetErrorString("Couldn't dematerialize a result variable: couldn't " 1006 "read its address"); 1007 return; 1008 } 1009 1010 lldb::TargetSP target_sp = exe_scope->CalculateTarget(); 1011 1012 if (!target_sp) { 1013 err.SetErrorString("Couldn't dematerialize a result variable: no target"); 1014 return; 1015 } 1016 1017 auto type_system_or_err = 1018 target_sp->GetScratchTypeSystemForLanguage(m_type.GetMinimumLanguage()); 1019 1020 if (auto error = type_system_or_err.takeError()) { 1021 err.SetErrorStringWithFormat("Couldn't dematerialize a result variable: " 1022 "couldn't get the corresponding type " 1023 "system: %s", 1024 llvm::toString(std::move(error)).c_str()); 1025 return; 1026 } 1027 auto ts = *type_system_or_err; 1028 if (!ts) { 1029 err.SetErrorStringWithFormat("Couldn't dematerialize a result variable: " 1030 "couldn't corresponding type system is " 1031 "no longer live."); 1032 return; 1033 } 1034 PersistentExpressionState *persistent_state = 1035 ts->GetPersistentExpressionState(); 1036 1037 if (!persistent_state) { 1038 err.SetErrorString("Couldn't dematerialize a result variable: " 1039 "corresponding type system doesn't handle persistent " 1040 "variables"); 1041 return; 1042 } 1043 1044 ConstString name = m_delegate 1045 ? m_delegate->GetName() 1046 : persistent_state->GetNextPersistentVariableName(); 1047 1048 lldb::ExpressionVariableSP ret = persistent_state->CreatePersistentVariable( 1049 exe_scope, name, m_type, map.GetByteOrder(), map.GetAddressByteSize()); 1050 1051 if (!ret) { 1052 err.SetErrorStringWithFormat("couldn't dematerialize a result variable: " 1053 "failed to make persistent variable %s", 1054 name.AsCString()); 1055 return; 1056 } 1057 1058 lldb::ProcessSP process_sp = 1059 map.GetBestExecutionContextScope()->CalculateProcess(); 1060 1061 if (m_delegate) { 1062 m_delegate->DidDematerialize(ret); 1063 } 1064 1065 bool can_persist = 1066 (m_is_program_reference && process_sp && process_sp->CanJIT() && 1067 !(address >= frame_bottom && address < frame_top)); 1068 1069 if (can_persist && m_keep_in_memory) { 1070 ret->m_live_sp = ValueObjectConstResult::Create(exe_scope, m_type, name, 1071 address, eAddressTypeLoad, 1072 map.GetAddressByteSize()); 1073 } 1074 1075 ret->ValueUpdated(); 1076 1077 const size_t pvar_byte_size = ret->GetByteSize().value_or(0); 1078 uint8_t *pvar_data = ret->GetValueBytes(); 1079 1080 map.ReadMemory(pvar_data, address, pvar_byte_size, read_error); 1081 1082 if (!read_error.Success()) { 1083 err.SetErrorString( 1084 "Couldn't dematerialize a result variable: couldn't read its memory"); 1085 return; 1086 } 1087 1088 if (!can_persist || !m_keep_in_memory) { 1089 ret->m_flags |= ExpressionVariable::EVNeedsAllocation; 1090 1091 if (m_temporary_allocation != LLDB_INVALID_ADDRESS) { 1092 Status free_error; 1093 map.Free(m_temporary_allocation, free_error); 1094 } 1095 } else { 1096 ret->m_flags |= ExpressionVariable::EVIsLLDBAllocated; 1097 } 1098 1099 m_temporary_allocation = LLDB_INVALID_ADDRESS; 1100 m_temporary_allocation_size = 0; 1101 } 1102 1103 void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address, 1104 Log *log) override { 1105 StreamString dump_stream; 1106 1107 const lldb::addr_t load_addr = process_address + m_offset; 1108 1109 dump_stream.Printf("0x%" PRIx64 ": EntityResultVariable\n", load_addr); 1110 1111 Status err; 1112 1113 lldb::addr_t ptr = LLDB_INVALID_ADDRESS; 1114 1115 { 1116 dump_stream.Printf("Pointer:\n"); 1117 1118 DataBufferHeap data(m_size, 0); 1119 1120 map.ReadMemory(data.GetBytes(), load_addr, m_size, err); 1121 1122 if (!err.Success()) { 1123 dump_stream.Printf(" <could not be read>\n"); 1124 } else { 1125 DataExtractor extractor(data.GetBytes(), data.GetByteSize(), 1126 map.GetByteOrder(), map.GetAddressByteSize()); 1127 1128 DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, 1129 load_addr); 1130 1131 lldb::offset_t offset = 0; 1132 1133 ptr = extractor.GetAddress(&offset); 1134 1135 dump_stream.PutChar('\n'); 1136 } 1137 } 1138 1139 if (m_temporary_allocation == LLDB_INVALID_ADDRESS) { 1140 dump_stream.Printf("Points to process memory:\n"); 1141 } else { 1142 dump_stream.Printf("Temporary allocation:\n"); 1143 } 1144 1145 if (ptr == LLDB_INVALID_ADDRESS) { 1146 dump_stream.Printf(" <could not be be found>\n"); 1147 } else { 1148 DataBufferHeap data(m_temporary_allocation_size, 0); 1149 1150 map.ReadMemory(data.GetBytes(), m_temporary_allocation, 1151 m_temporary_allocation_size, err); 1152 1153 if (!err.Success()) { 1154 dump_stream.Printf(" <could not be read>\n"); 1155 } else { 1156 DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, 1157 load_addr); 1158 1159 dump_stream.PutChar('\n'); 1160 } 1161 } 1162 1163 log->PutString(dump_stream.GetString()); 1164 } 1165 1166 void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override { 1167 if (!m_keep_in_memory && m_temporary_allocation != LLDB_INVALID_ADDRESS) { 1168 Status free_error; 1169 1170 map.Free(m_temporary_allocation, free_error); 1171 } 1172 1173 m_temporary_allocation = LLDB_INVALID_ADDRESS; 1174 m_temporary_allocation_size = 0; 1175 } 1176 1177 private: 1178 CompilerType m_type; 1179 bool m_is_program_reference; 1180 bool m_keep_in_memory; 1181 1182 lldb::addr_t m_temporary_allocation = LLDB_INVALID_ADDRESS; 1183 size_t m_temporary_allocation_size = 0; 1184 Materializer::PersistentVariableDelegate *m_delegate; 1185 }; 1186 1187 uint32_t Materializer::AddResultVariable(const CompilerType &type, 1188 bool is_program_reference, 1189 bool keep_in_memory, 1190 PersistentVariableDelegate *delegate, 1191 Status &err) { 1192 EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP()); 1193 *iter = std::make_unique<EntityResultVariable>(type, is_program_reference, 1194 keep_in_memory, delegate); 1195 uint32_t ret = AddStructMember(**iter); 1196 (*iter)->SetOffset(ret); 1197 return ret; 1198 } 1199 1200 class EntitySymbol : public Materializer::Entity { 1201 public: 1202 EntitySymbol(const Symbol &symbol) : Entity(), m_symbol(symbol) { 1203 // Hard-coding to maximum size of a symbol 1204 m_size = g_default_var_byte_size; 1205 m_alignment = g_default_var_alignment; 1206 } 1207 1208 void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 1209 lldb::addr_t process_address, Status &err) override { 1210 Log *log = GetLog(LLDBLog::Expressions); 1211 1212 const lldb::addr_t load_addr = process_address + m_offset; 1213 1214 if (log) { 1215 LLDB_LOGF(log, 1216 "EntitySymbol::Materialize [address = 0x%" PRIx64 1217 ", m_symbol = %s]", 1218 (uint64_t)load_addr, m_symbol.GetName().AsCString()); 1219 } 1220 1221 const Address sym_address = m_symbol.GetAddress(); 1222 1223 ExecutionContextScope *exe_scope = frame_sp.get(); 1224 if (!exe_scope) 1225 exe_scope = map.GetBestExecutionContextScope(); 1226 1227 lldb::TargetSP target_sp; 1228 1229 if (exe_scope) 1230 target_sp = map.GetBestExecutionContextScope()->CalculateTarget(); 1231 1232 if (!target_sp) { 1233 err.SetErrorStringWithFormat( 1234 "couldn't resolve symbol %s because there is no target", 1235 m_symbol.GetName().AsCString()); 1236 return; 1237 } 1238 1239 lldb::addr_t resolved_address = sym_address.GetLoadAddress(target_sp.get()); 1240 1241 if (resolved_address == LLDB_INVALID_ADDRESS) 1242 resolved_address = sym_address.GetFileAddress(); 1243 1244 Status pointer_write_error; 1245 1246 map.WritePointerToMemory(load_addr, resolved_address, pointer_write_error); 1247 1248 if (!pointer_write_error.Success()) { 1249 err.SetErrorStringWithFormat( 1250 "couldn't write the address of symbol %s: %s", 1251 m_symbol.GetName().AsCString(), pointer_write_error.AsCString()); 1252 return; 1253 } 1254 } 1255 1256 void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 1257 lldb::addr_t process_address, lldb::addr_t frame_top, 1258 lldb::addr_t frame_bottom, Status &err) override { 1259 Log *log = GetLog(LLDBLog::Expressions); 1260 1261 const lldb::addr_t load_addr = process_address + m_offset; 1262 1263 if (log) { 1264 LLDB_LOGF(log, 1265 "EntitySymbol::Dematerialize [address = 0x%" PRIx64 1266 ", m_symbol = %s]", 1267 (uint64_t)load_addr, m_symbol.GetName().AsCString()); 1268 } 1269 1270 // no work needs to be done 1271 } 1272 1273 void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address, 1274 Log *log) override { 1275 StreamString dump_stream; 1276 1277 Status err; 1278 1279 const lldb::addr_t load_addr = process_address + m_offset; 1280 1281 dump_stream.Printf("0x%" PRIx64 ": EntitySymbol (%s)\n", load_addr, 1282 m_symbol.GetName().AsCString()); 1283 1284 { 1285 dump_stream.Printf("Pointer:\n"); 1286 1287 DataBufferHeap data(m_size, 0); 1288 1289 map.ReadMemory(data.GetBytes(), load_addr, m_size, err); 1290 1291 if (!err.Success()) { 1292 dump_stream.Printf(" <could not be read>\n"); 1293 } else { 1294 DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, 1295 load_addr); 1296 1297 dump_stream.PutChar('\n'); 1298 } 1299 } 1300 1301 log->PutString(dump_stream.GetString()); 1302 } 1303 1304 void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {} 1305 1306 private: 1307 Symbol m_symbol; 1308 }; 1309 1310 uint32_t Materializer::AddSymbol(const Symbol &symbol_sp, Status &err) { 1311 EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP()); 1312 *iter = std::make_unique<EntitySymbol>(symbol_sp); 1313 uint32_t ret = AddStructMember(**iter); 1314 (*iter)->SetOffset(ret); 1315 return ret; 1316 } 1317 1318 class EntityRegister : public Materializer::Entity { 1319 public: 1320 EntityRegister(const RegisterInfo ®ister_info) 1321 : Entity(), m_register_info(register_info) { 1322 // Hard-coding alignment conservatively 1323 m_size = m_register_info.byte_size; 1324 m_alignment = m_register_info.byte_size; 1325 } 1326 1327 void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 1328 lldb::addr_t process_address, Status &err) override { 1329 Log *log = GetLog(LLDBLog::Expressions); 1330 1331 const lldb::addr_t load_addr = process_address + m_offset; 1332 1333 if (log) { 1334 LLDB_LOGF(log, 1335 "EntityRegister::Materialize [address = 0x%" PRIx64 1336 ", m_register_info = %s]", 1337 (uint64_t)load_addr, m_register_info.name); 1338 } 1339 1340 RegisterValue reg_value; 1341 1342 if (!frame_sp.get()) { 1343 err.SetErrorStringWithFormat( 1344 "couldn't materialize register %s without a stack frame", 1345 m_register_info.name); 1346 return; 1347 } 1348 1349 lldb::RegisterContextSP reg_context_sp = frame_sp->GetRegisterContext(); 1350 1351 if (!reg_context_sp->ReadRegister(&m_register_info, reg_value)) { 1352 err.SetErrorStringWithFormat("couldn't read the value of register %s", 1353 m_register_info.name); 1354 return; 1355 } 1356 1357 DataExtractor register_data; 1358 1359 if (!reg_value.GetData(register_data)) { 1360 err.SetErrorStringWithFormat("couldn't get the data for register %s", 1361 m_register_info.name); 1362 return; 1363 } 1364 1365 if (register_data.GetByteSize() != m_register_info.byte_size) { 1366 err.SetErrorStringWithFormat( 1367 "data for register %s had size %llu but we expected %llu", 1368 m_register_info.name, (unsigned long long)register_data.GetByteSize(), 1369 (unsigned long long)m_register_info.byte_size); 1370 return; 1371 } 1372 1373 m_register_contents = std::make_shared<DataBufferHeap>( 1374 register_data.GetDataStart(), register_data.GetByteSize()); 1375 1376 Status write_error; 1377 1378 map.WriteMemory(load_addr, register_data.GetDataStart(), 1379 register_data.GetByteSize(), write_error); 1380 1381 if (!write_error.Success()) { 1382 err.SetErrorStringWithFormat( 1383 "couldn't write the contents of register %s: %s", 1384 m_register_info.name, write_error.AsCString()); 1385 return; 1386 } 1387 } 1388 1389 void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 1390 lldb::addr_t process_address, lldb::addr_t frame_top, 1391 lldb::addr_t frame_bottom, Status &err) override { 1392 Log *log = GetLog(LLDBLog::Expressions); 1393 1394 const lldb::addr_t load_addr = process_address + m_offset; 1395 1396 if (log) { 1397 LLDB_LOGF(log, 1398 "EntityRegister::Dematerialize [address = 0x%" PRIx64 1399 ", m_register_info = %s]", 1400 (uint64_t)load_addr, m_register_info.name); 1401 } 1402 1403 Status extract_error; 1404 1405 DataExtractor register_data; 1406 1407 if (!frame_sp.get()) { 1408 err.SetErrorStringWithFormat( 1409 "couldn't dematerialize register %s without a stack frame", 1410 m_register_info.name); 1411 return; 1412 } 1413 1414 lldb::RegisterContextSP reg_context_sp = frame_sp->GetRegisterContext(); 1415 1416 map.GetMemoryData(register_data, load_addr, m_register_info.byte_size, 1417 extract_error); 1418 1419 if (!extract_error.Success()) { 1420 err.SetErrorStringWithFormat("couldn't get the data for register %s: %s", 1421 m_register_info.name, 1422 extract_error.AsCString()); 1423 return; 1424 } 1425 1426 if (!memcmp(register_data.GetDataStart(), m_register_contents->GetBytes(), 1427 register_data.GetByteSize())) { 1428 // No write required, and in particular we avoid errors if the register 1429 // wasn't writable 1430 1431 m_register_contents.reset(); 1432 return; 1433 } 1434 1435 m_register_contents.reset(); 1436 1437 RegisterValue register_value(register_data.GetData(), 1438 register_data.GetByteOrder()); 1439 1440 if (!reg_context_sp->WriteRegister(&m_register_info, register_value)) { 1441 err.SetErrorStringWithFormat("couldn't write the value of register %s", 1442 m_register_info.name); 1443 return; 1444 } 1445 } 1446 1447 void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address, 1448 Log *log) override { 1449 StreamString dump_stream; 1450 1451 Status err; 1452 1453 const lldb::addr_t load_addr = process_address + m_offset; 1454 1455 dump_stream.Printf("0x%" PRIx64 ": EntityRegister (%s)\n", load_addr, 1456 m_register_info.name); 1457 1458 { 1459 dump_stream.Printf("Value:\n"); 1460 1461 DataBufferHeap data(m_size, 0); 1462 1463 map.ReadMemory(data.GetBytes(), load_addr, m_size, err); 1464 1465 if (!err.Success()) { 1466 dump_stream.Printf(" <could not be read>\n"); 1467 } else { 1468 DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, 1469 load_addr); 1470 1471 dump_stream.PutChar('\n'); 1472 } 1473 } 1474 1475 log->PutString(dump_stream.GetString()); 1476 } 1477 1478 void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {} 1479 1480 private: 1481 RegisterInfo m_register_info; 1482 lldb::DataBufferSP m_register_contents; 1483 }; 1484 1485 uint32_t Materializer::AddRegister(const RegisterInfo ®ister_info, 1486 Status &err) { 1487 EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP()); 1488 *iter = std::make_unique<EntityRegister>(register_info); 1489 uint32_t ret = AddStructMember(**iter); 1490 (*iter)->SetOffset(ret); 1491 return ret; 1492 } 1493 1494 Materializer::~Materializer() { 1495 DematerializerSP dematerializer_sp = m_dematerializer_wp.lock(); 1496 1497 if (dematerializer_sp) 1498 dematerializer_sp->Wipe(); 1499 } 1500 1501 Materializer::DematerializerSP 1502 Materializer::Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 1503 lldb::addr_t process_address, Status &error) { 1504 ExecutionContextScope *exe_scope = frame_sp.get(); 1505 if (!exe_scope) 1506 exe_scope = map.GetBestExecutionContextScope(); 1507 1508 DematerializerSP dematerializer_sp = m_dematerializer_wp.lock(); 1509 1510 if (dematerializer_sp) { 1511 error.SetErrorToGenericError(); 1512 error.SetErrorString("Couldn't materialize: already materialized"); 1513 } 1514 1515 DematerializerSP ret( 1516 new Dematerializer(*this, frame_sp, map, process_address)); 1517 1518 if (!exe_scope) { 1519 error.SetErrorToGenericError(); 1520 error.SetErrorString("Couldn't materialize: target doesn't exist"); 1521 } 1522 1523 for (EntityUP &entity_up : m_entities) { 1524 entity_up->Materialize(frame_sp, map, process_address, error); 1525 1526 if (!error.Success()) 1527 return DematerializerSP(); 1528 } 1529 1530 if (Log *log = GetLog(LLDBLog::Expressions)) { 1531 LLDB_LOGF( 1532 log, 1533 "Materializer::Materialize (frame_sp = %p, process_address = 0x%" PRIx64 1534 ") materialized:", 1535 static_cast<void *>(frame_sp.get()), process_address); 1536 for (EntityUP &entity_up : m_entities) 1537 entity_up->DumpToLog(map, process_address, log); 1538 } 1539 1540 m_dematerializer_wp = ret; 1541 1542 return ret; 1543 } 1544 1545 void Materializer::Dematerializer::Dematerialize(Status &error, 1546 lldb::addr_t frame_bottom, 1547 lldb::addr_t frame_top) { 1548 lldb::StackFrameSP frame_sp; 1549 1550 lldb::ThreadSP thread_sp = m_thread_wp.lock(); 1551 if (thread_sp) 1552 frame_sp = thread_sp->GetFrameWithStackID(m_stack_id); 1553 1554 ExecutionContextScope *exe_scope = frame_sp.get(); 1555 if (!exe_scope) 1556 exe_scope = m_map->GetBestExecutionContextScope(); 1557 1558 if (!IsValid()) { 1559 error.SetErrorToGenericError(); 1560 error.SetErrorString("Couldn't dematerialize: invalid dematerializer"); 1561 } 1562 1563 if (!exe_scope) { 1564 error.SetErrorToGenericError(); 1565 error.SetErrorString("Couldn't dematerialize: target is gone"); 1566 } else { 1567 if (Log *log = GetLog(LLDBLog::Expressions)) { 1568 LLDB_LOGF(log, 1569 "Materializer::Dematerialize (frame_sp = %p, process_address " 1570 "= 0x%" PRIx64 ") about to dematerialize:", 1571 static_cast<void *>(frame_sp.get()), m_process_address); 1572 for (EntityUP &entity_up : m_materializer->m_entities) 1573 entity_up->DumpToLog(*m_map, m_process_address, log); 1574 } 1575 1576 for (EntityUP &entity_up : m_materializer->m_entities) { 1577 entity_up->Dematerialize(frame_sp, *m_map, m_process_address, frame_top, 1578 frame_bottom, error); 1579 1580 if (!error.Success()) 1581 break; 1582 } 1583 } 1584 1585 Wipe(); 1586 } 1587 1588 void Materializer::Dematerializer::Wipe() { 1589 if (!IsValid()) 1590 return; 1591 1592 for (EntityUP &entity_up : m_materializer->m_entities) { 1593 entity_up->Wipe(*m_map, m_process_address); 1594 } 1595 1596 m_materializer = nullptr; 1597 m_map = nullptr; 1598 m_process_address = LLDB_INVALID_ADDRESS; 1599 } 1600 1601 Materializer::PersistentVariableDelegate::PersistentVariableDelegate() = 1602 default; 1603 Materializer::PersistentVariableDelegate::~PersistentVariableDelegate() = 1604 default; 1605