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/Expression/ExpressionVariable.h" 12 #include "lldb/Symbol/Symbol.h" 13 #include "lldb/Symbol/Type.h" 14 #include "lldb/Symbol/Variable.h" 15 #include "lldb/Target/ExecutionContext.h" 16 #include "lldb/Target/RegisterContext.h" 17 #include "lldb/Target/StackFrame.h" 18 #include "lldb/Target/Target.h" 19 #include "lldb/Target/Thread.h" 20 #include "lldb/Utility/LLDBLog.h" 21 #include "lldb/Utility/Log.h" 22 #include "lldb/Utility/RegisterValue.h" 23 #include "lldb/ValueObject/ValueObjectConstResult.h" 24 #include "lldb/ValueObject/ValueObjectVariable.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 = Status::FromErrorStringWithFormat( 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 = Status::FromErrorStringWithFormat( 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 = Status::FromErrorStringWithFormat( 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 = Status::FromErrorStringWithFormat( 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 = Status::FromErrorStringWithFormat( 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 = Status::FromErrorStringWithFormat( 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 = Status::FromErrorStringWithFormat( 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 = Status::FromErrorStringWithFormat( 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 = Status::FromErrorStringWithFormat( 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 = Status::FromErrorStringWithFormat( 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 = Status::FromErrorStringWithFormat( 461 "couldn't get a value object for variable %s", GetName().AsCString()); 462 return; 463 } 464 465 Status valobj_error = valobj_sp->GetError().Clone(); 466 467 if (valobj_error.Fail()) { 468 err = Status::FromErrorStringWithFormat( 469 "couldn't get the value of variable %s: %s", 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 = Status::FromErrorStringWithFormat( 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 = Status::FromErrorStringWithFormat( 494 "couldn't write the contents of reference " 495 "variable %s to memory: %s", 496 GetName().AsCString(), 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 = Status::FromErrorStringWithFormat( 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 = Status::FromErrorStringWithFormat( 520 "couldn't get the value of %s: %s", GetName().AsCString(), 521 extract_error.AsCString()); 522 return; 523 } 524 525 if (m_temporary_allocation != LLDB_INVALID_ADDRESS) { 526 err = Status::FromErrorStringWithFormat( 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 = Status::FromErrorStringWithFormat( 535 "the variable '%s' has no location, " 536 "it may have been optimized out", 537 GetName().AsCString()); 538 } else { 539 err = Status::FromErrorStringWithFormat( 540 "size of variable %s (%" PRIu64 541 ") is larger than the ValueObject's size (%" PRIu64 ")", 542 GetName().AsCString(), GetByteSize(scope).value_or(0), 543 data.GetByteSize()); 544 } 545 return; 546 } 547 548 std::optional<size_t> opt_bit_align = GetTypeBitAlign(scope); 549 if (!opt_bit_align) { 550 err = Status::FromErrorStringWithFormat( 551 "can't get the type alignment for %s", GetName().AsCString()); 552 return; 553 } 554 555 size_t byte_align = (*opt_bit_align + 7) / 8; 556 557 Status alloc_error; 558 const bool zero_memory = false; 559 560 m_temporary_allocation = map.Malloc( 561 data.GetByteSize(), byte_align, 562 lldb::ePermissionsReadable | lldb::ePermissionsWritable, 563 IRMemoryMap::eAllocationPolicyMirror, zero_memory, alloc_error); 564 565 m_temporary_allocation_size = data.GetByteSize(); 566 567 m_original_data = std::make_shared<DataBufferHeap>(data.GetDataStart(), 568 data.GetByteSize()); 569 570 if (!alloc_error.Success()) { 571 err = Status::FromErrorStringWithFormat( 572 "couldn't allocate a temporary region for %s: %s", 573 GetName().AsCString(), alloc_error.AsCString()); 574 return; 575 } 576 577 Status write_error; 578 579 map.WriteMemory(m_temporary_allocation, data.GetDataStart(), 580 data.GetByteSize(), write_error); 581 582 if (!write_error.Success()) { 583 err = Status::FromErrorStringWithFormat( 584 "couldn't write to the temporary region for %s: %s", 585 GetName().AsCString(), write_error.AsCString()); 586 return; 587 } 588 589 Status pointer_write_error; 590 591 map.WritePointerToMemory(load_addr, m_temporary_allocation, 592 pointer_write_error); 593 594 if (!pointer_write_error.Success()) { 595 err = Status::FromErrorStringWithFormat( 596 "couldn't write the address of the temporary region for %s: %s", 597 GetName().AsCString(), pointer_write_error.AsCString()); 598 } 599 } 600 } 601 } 602 603 void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 604 lldb::addr_t process_address, lldb::addr_t frame_top, 605 lldb::addr_t frame_bottom, Status &err) override { 606 Log *log = GetLog(LLDBLog::Expressions); 607 608 const lldb::addr_t load_addr = process_address + m_offset; 609 if (log) { 610 LLDB_LOGF(log, 611 "EntityVariable::Dematerialize [address = 0x%" PRIx64 612 ", m_variable_sp = %s]", 613 (uint64_t)load_addr, GetName().AsCString()); 614 } 615 616 if (m_temporary_allocation != LLDB_INVALID_ADDRESS) { 617 ExecutionContextScope *scope = frame_sp.get(); 618 619 if (!scope) 620 scope = map.GetBestExecutionContextScope(); 621 622 lldb::ValueObjectSP valobj_sp = SetupValueObject(scope); 623 624 if (!valobj_sp) { 625 err = Status::FromErrorStringWithFormat( 626 "couldn't get a value object for variable %s", 627 GetName().AsCString()); 628 return; 629 } 630 631 lldb_private::DataExtractor data; 632 633 Status extract_error; 634 635 map.GetMemoryData(data, m_temporary_allocation, 636 valobj_sp->GetByteSize().value_or(0), extract_error); 637 638 if (!extract_error.Success()) { 639 err = Status::FromErrorStringWithFormat( 640 "couldn't get the data for variable %s", GetName().AsCString()); 641 return; 642 } 643 644 bool actually_write = true; 645 646 if (m_original_data) { 647 if ((data.GetByteSize() == m_original_data->GetByteSize()) && 648 !memcmp(m_original_data->GetBytes(), data.GetDataStart(), 649 data.GetByteSize())) { 650 actually_write = false; 651 } 652 } 653 654 Status set_error; 655 656 if (actually_write) { 657 valobj_sp->SetData(data, set_error); 658 659 if (!set_error.Success()) { 660 err = Status::FromErrorStringWithFormat( 661 "couldn't write the new contents of %s back into the variable", 662 GetName().AsCString()); 663 return; 664 } 665 } 666 667 Status free_error; 668 669 map.Free(m_temporary_allocation, free_error); 670 671 if (!free_error.Success()) { 672 err = Status::FromErrorStringWithFormat( 673 "couldn't free the temporary region for %s: %s", 674 GetName().AsCString(), free_error.AsCString()); 675 return; 676 } 677 678 m_original_data.reset(); 679 m_temporary_allocation = LLDB_INVALID_ADDRESS; 680 m_temporary_allocation_size = 0; 681 } 682 } 683 684 void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address, 685 Log *log) override { 686 StreamString dump_stream; 687 688 const lldb::addr_t load_addr = process_address + m_offset; 689 dump_stream.Printf("0x%" PRIx64 ": EntityVariable\n", load_addr); 690 691 Status err; 692 693 lldb::addr_t ptr = LLDB_INVALID_ADDRESS; 694 695 { 696 dump_stream.Printf("Pointer:\n"); 697 698 DataBufferHeap data(m_size, 0); 699 700 map.ReadMemory(data.GetBytes(), load_addr, m_size, err); 701 702 if (!err.Success()) { 703 dump_stream.Printf(" <could not be read>\n"); 704 } else { 705 DataExtractor extractor(data.GetBytes(), data.GetByteSize(), 706 map.GetByteOrder(), map.GetAddressByteSize()); 707 708 DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, 709 load_addr); 710 711 lldb::offset_t offset = 0; 712 713 ptr = extractor.GetAddress(&offset); 714 715 dump_stream.PutChar('\n'); 716 } 717 } 718 719 if (m_temporary_allocation == LLDB_INVALID_ADDRESS) { 720 dump_stream.Printf("Points to process memory:\n"); 721 } else { 722 dump_stream.Printf("Temporary allocation:\n"); 723 } 724 725 if (ptr == LLDB_INVALID_ADDRESS) { 726 dump_stream.Printf(" <could not be be found>\n"); 727 } else { 728 DataBufferHeap data(m_temporary_allocation_size, 0); 729 730 map.ReadMemory(data.GetBytes(), m_temporary_allocation, 731 m_temporary_allocation_size, err); 732 733 if (!err.Success()) { 734 dump_stream.Printf(" <could not be read>\n"); 735 } else { 736 DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, 737 load_addr); 738 739 dump_stream.PutChar('\n'); 740 } 741 } 742 743 log->PutString(dump_stream.GetString()); 744 } 745 746 void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override { 747 if (m_temporary_allocation != LLDB_INVALID_ADDRESS) { 748 Status free_error; 749 750 map.Free(m_temporary_allocation, free_error); 751 752 m_temporary_allocation = LLDB_INVALID_ADDRESS; 753 m_temporary_allocation_size = 0; 754 } 755 } 756 757 private: 758 virtual ConstString GetName() const = 0; 759 760 /// Creates and returns ValueObject tied to this variable 761 /// and prepares Entity for materialization. 762 /// 763 /// Called each time the Materializer (de)materializes a 764 /// variable. We re-create the ValueObject based on the 765 /// current ExecutionContextScope since clients such as 766 /// conditional breakpoints may materialize the same 767 /// EntityVariable multiple times with different frames. 768 /// 769 /// Each subsequent use of the EntityVariableBase interface 770 /// will query the newly created ValueObject until this 771 /// function is called again. 772 virtual lldb::ValueObjectSP 773 SetupValueObject(ExecutionContextScope *scope) = 0; 774 775 /// Returns size in bytes of the type associated with this variable 776 /// 777 /// \returns On success, returns byte size of the type associated 778 /// with this variable. Returns std::nullopt otherwise. 779 virtual std::optional<uint64_t> 780 GetByteSize(ExecutionContextScope *scope) const = 0; 781 782 /// Returns 'true' if the location expression associated with this variable 783 /// is valid. 784 virtual bool LocationExpressionIsValid() const = 0; 785 786 /// Returns alignment of the type associated with this variable in bits. 787 /// 788 /// \returns On success, returns alignment in bits for the type associated 789 /// with this variable. Returns std::nullopt otherwise. 790 virtual std::optional<size_t> 791 GetTypeBitAlign(ExecutionContextScope *scope) const = 0; 792 793 protected: 794 bool m_is_reference = false; 795 lldb::addr_t m_temporary_allocation = LLDB_INVALID_ADDRESS; 796 size_t m_temporary_allocation_size = 0; 797 lldb::DataBufferSP m_original_data; 798 }; 799 800 /// Represents an Entity constructed from a VariableSP. 801 /// 802 /// This class is used for materialization of variables for which 803 /// the user has a VariableSP on hand. The ValueObject is then 804 /// derived from the associated DWARF location expression when needed 805 /// by the Materializer. 806 class EntityVariable : public EntityVariableBase { 807 public: 808 EntityVariable(lldb::VariableSP &variable_sp) : m_variable_sp(variable_sp) { 809 m_is_reference = 810 m_variable_sp->GetType()->GetForwardCompilerType().IsReferenceType(); 811 } 812 813 ConstString GetName() const override { return m_variable_sp->GetName(); } 814 815 lldb::ValueObjectSP SetupValueObject(ExecutionContextScope *scope) override { 816 assert(m_variable_sp != nullptr); 817 return ValueObjectVariable::Create(scope, m_variable_sp); 818 } 819 820 std::optional<uint64_t> 821 GetByteSize(ExecutionContextScope *scope) const override { 822 return m_variable_sp->GetType()->GetByteSize(scope); 823 } 824 825 bool LocationExpressionIsValid() const override { 826 return m_variable_sp->LocationExpressionList().IsValid(); 827 } 828 829 std::optional<size_t> 830 GetTypeBitAlign(ExecutionContextScope *scope) const override { 831 return m_variable_sp->GetType()->GetLayoutCompilerType().GetTypeBitAlign( 832 scope); 833 } 834 835 private: 836 lldb::VariableSP m_variable_sp; ///< Variable that this entity is based on. 837 }; 838 839 /// Represents an Entity constructed from a VariableSP. 840 /// 841 /// This class is used for materialization of variables for 842 /// which the user does not have a VariableSP available (e.g., 843 /// when materializing ivars). 844 class EntityValueObject : public EntityVariableBase { 845 public: 846 EntityValueObject(ConstString name, ValueObjectProviderTy provider) 847 : m_name(name), m_valobj_provider(std::move(provider)) { 848 assert(m_valobj_provider); 849 } 850 851 ConstString GetName() const override { return m_name; } 852 853 lldb::ValueObjectSP SetupValueObject(ExecutionContextScope *scope) override { 854 m_valobj_sp = 855 m_valobj_provider(GetName(), scope->CalculateStackFrame().get()); 856 857 if (m_valobj_sp) 858 m_is_reference = m_valobj_sp->GetCompilerType().IsReferenceType(); 859 860 return m_valobj_sp; 861 } 862 863 std::optional<uint64_t> 864 GetByteSize(ExecutionContextScope *scope) const override { 865 if (m_valobj_sp) 866 return m_valobj_sp->GetCompilerType().GetByteSize(scope); 867 868 return {}; 869 } 870 871 bool LocationExpressionIsValid() const override { 872 if (m_valobj_sp) 873 return m_valobj_sp->GetError().Success(); 874 875 return false; 876 } 877 878 std::optional<size_t> 879 GetTypeBitAlign(ExecutionContextScope *scope) const override { 880 if (m_valobj_sp) 881 return m_valobj_sp->GetCompilerType().GetTypeBitAlign(scope); 882 883 return {}; 884 } 885 886 private: 887 ConstString m_name; 888 lldb::ValueObjectSP m_valobj_sp; 889 ValueObjectProviderTy m_valobj_provider; 890 }; 891 892 uint32_t Materializer::AddVariable(lldb::VariableSP &variable_sp, Status &err) { 893 EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP()); 894 *iter = std::make_unique<EntityVariable>(variable_sp); 895 uint32_t ret = AddStructMember(**iter); 896 (*iter)->SetOffset(ret); 897 return ret; 898 } 899 900 uint32_t Materializer::AddValueObject(ConstString name, 901 ValueObjectProviderTy valobj_provider, 902 Status &err) { 903 assert(valobj_provider); 904 EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP()); 905 *iter = std::make_unique<EntityValueObject>(name, std::move(valobj_provider)); 906 uint32_t ret = AddStructMember(**iter); 907 (*iter)->SetOffset(ret); 908 return ret; 909 } 910 911 class EntityResultVariable : public Materializer::Entity { 912 public: 913 EntityResultVariable(const CompilerType &type, bool is_program_reference, 914 bool keep_in_memory, 915 Materializer::PersistentVariableDelegate *delegate) 916 : Entity(), m_type(type), m_is_program_reference(is_program_reference), 917 m_keep_in_memory(keep_in_memory), m_delegate(delegate) { 918 // Hard-coding to maximum size of a pointer since all results are 919 // materialized by reference 920 m_size = g_default_var_byte_size; 921 m_alignment = g_default_var_alignment; 922 } 923 924 void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 925 lldb::addr_t process_address, Status &err) override { 926 if (!m_is_program_reference) { 927 if (m_temporary_allocation != LLDB_INVALID_ADDRESS) { 928 err = Status::FromErrorString( 929 "Trying to create a temporary region for the result " 930 "but one exists"); 931 return; 932 } 933 934 const lldb::addr_t load_addr = process_address + m_offset; 935 936 ExecutionContextScope *exe_scope = frame_sp.get(); 937 if (!exe_scope) 938 exe_scope = map.GetBestExecutionContextScope(); 939 940 std::optional<uint64_t> byte_size = m_type.GetByteSize(exe_scope); 941 if (!byte_size) { 942 err = Status::FromErrorStringWithFormat( 943 "can't get size of type \"%s\"", m_type.GetTypeName().AsCString()); 944 return; 945 } 946 947 std::optional<size_t> opt_bit_align = m_type.GetTypeBitAlign(exe_scope); 948 if (!opt_bit_align) { 949 err = Status::FromErrorStringWithFormat( 950 "can't get the alignment of type \"%s\"", 951 m_type.GetTypeName().AsCString()); 952 return; 953 } 954 955 size_t byte_align = (*opt_bit_align + 7) / 8; 956 957 Status alloc_error; 958 const bool zero_memory = true; 959 960 m_temporary_allocation = map.Malloc( 961 *byte_size, byte_align, 962 lldb::ePermissionsReadable | lldb::ePermissionsWritable, 963 IRMemoryMap::eAllocationPolicyMirror, zero_memory, alloc_error); 964 m_temporary_allocation_size = *byte_size; 965 966 if (!alloc_error.Success()) { 967 err = Status::FromErrorStringWithFormat( 968 "couldn't allocate a temporary region for the result: %s", 969 alloc_error.AsCString()); 970 return; 971 } 972 973 Status pointer_write_error; 974 975 map.WritePointerToMemory(load_addr, m_temporary_allocation, 976 pointer_write_error); 977 978 if (!pointer_write_error.Success()) { 979 err = Status::FromErrorStringWithFormat( 980 "couldn't write the address of the " 981 "temporary region for the result: %s", 982 pointer_write_error.AsCString()); 983 } 984 } 985 } 986 987 void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 988 lldb::addr_t process_address, lldb::addr_t frame_top, 989 lldb::addr_t frame_bottom, Status &err) override { 990 err.Clear(); 991 992 ExecutionContextScope *exe_scope = frame_sp.get(); 993 if (!exe_scope) 994 exe_scope = map.GetBestExecutionContextScope(); 995 996 if (!exe_scope) { 997 err = Status::FromErrorString( 998 "Couldn't dematerialize a result variable: invalid " 999 "execution context scope"); 1000 return; 1001 } 1002 1003 lldb::addr_t address; 1004 Status read_error; 1005 const lldb::addr_t load_addr = process_address + m_offset; 1006 1007 map.ReadPointerFromMemory(&address, load_addr, read_error); 1008 1009 if (!read_error.Success()) { 1010 err = Status::FromErrorString( 1011 "Couldn't dematerialize a result variable: couldn't " 1012 "read its address"); 1013 return; 1014 } 1015 1016 lldb::TargetSP target_sp = exe_scope->CalculateTarget(); 1017 1018 if (!target_sp) { 1019 err = Status::FromErrorString( 1020 "Couldn't dematerialize a result variable: no target"); 1021 return; 1022 } 1023 1024 auto type_system_or_err = 1025 target_sp->GetScratchTypeSystemForLanguage(m_type.GetMinimumLanguage()); 1026 1027 if (auto error = type_system_or_err.takeError()) { 1028 err = Status::FromErrorStringWithFormat( 1029 "Couldn't dematerialize a result variable: " 1030 "couldn't get the corresponding type " 1031 "system: %s", 1032 llvm::toString(std::move(error)).c_str()); 1033 return; 1034 } 1035 auto ts = *type_system_or_err; 1036 if (!ts) { 1037 err = Status::FromErrorStringWithFormat( 1038 "Couldn't dematerialize a result variable: " 1039 "couldn't corresponding type system is " 1040 "no longer live."); 1041 return; 1042 } 1043 PersistentExpressionState *persistent_state = 1044 ts->GetPersistentExpressionState(); 1045 1046 if (!persistent_state) { 1047 err = Status::FromErrorString( 1048 "Couldn't dematerialize a result variable: " 1049 "corresponding type system doesn't handle persistent " 1050 "variables"); 1051 return; 1052 } 1053 1054 ConstString name = m_delegate 1055 ? m_delegate->GetName() 1056 : persistent_state->GetNextPersistentVariableName(); 1057 1058 lldb::ExpressionVariableSP ret = persistent_state->CreatePersistentVariable( 1059 exe_scope, name, m_type, map.GetByteOrder(), map.GetAddressByteSize()); 1060 1061 if (!ret) { 1062 err = Status::FromErrorStringWithFormat( 1063 "couldn't dematerialize a result variable: " 1064 "failed to make persistent variable %s", 1065 name.AsCString()); 1066 return; 1067 } 1068 1069 lldb::ProcessSP process_sp = 1070 map.GetBestExecutionContextScope()->CalculateProcess(); 1071 1072 if (m_delegate) { 1073 m_delegate->DidDematerialize(ret); 1074 } 1075 1076 bool can_persist = 1077 (m_is_program_reference && process_sp && process_sp->CanJIT() && 1078 !(address >= frame_bottom && address < frame_top)); 1079 1080 if (can_persist && m_keep_in_memory) { 1081 ret->m_live_sp = ValueObjectConstResult::Create(exe_scope, m_type, name, 1082 address, eAddressTypeLoad, 1083 map.GetAddressByteSize()); 1084 } 1085 1086 ret->ValueUpdated(); 1087 1088 const size_t pvar_byte_size = ret->GetByteSize().value_or(0); 1089 uint8_t *pvar_data = ret->GetValueBytes(); 1090 1091 map.ReadMemory(pvar_data, address, pvar_byte_size, read_error); 1092 1093 if (!read_error.Success()) { 1094 err = Status::FromErrorString( 1095 "Couldn't dematerialize a result variable: couldn't read its memory"); 1096 return; 1097 } 1098 1099 if (!can_persist || !m_keep_in_memory) { 1100 ret->m_flags |= ExpressionVariable::EVNeedsAllocation; 1101 1102 if (m_temporary_allocation != LLDB_INVALID_ADDRESS) { 1103 Status free_error; 1104 map.Free(m_temporary_allocation, free_error); 1105 } 1106 } else { 1107 ret->m_flags |= ExpressionVariable::EVIsLLDBAllocated; 1108 } 1109 1110 m_temporary_allocation = LLDB_INVALID_ADDRESS; 1111 m_temporary_allocation_size = 0; 1112 } 1113 1114 void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address, 1115 Log *log) override { 1116 StreamString dump_stream; 1117 1118 const lldb::addr_t load_addr = process_address + m_offset; 1119 1120 dump_stream.Printf("0x%" PRIx64 ": EntityResultVariable\n", load_addr); 1121 1122 Status err; 1123 1124 lldb::addr_t ptr = LLDB_INVALID_ADDRESS; 1125 1126 { 1127 dump_stream.Printf("Pointer:\n"); 1128 1129 DataBufferHeap data(m_size, 0); 1130 1131 map.ReadMemory(data.GetBytes(), load_addr, m_size, err); 1132 1133 if (!err.Success()) { 1134 dump_stream.Printf(" <could not be read>\n"); 1135 } else { 1136 DataExtractor extractor(data.GetBytes(), data.GetByteSize(), 1137 map.GetByteOrder(), map.GetAddressByteSize()); 1138 1139 DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, 1140 load_addr); 1141 1142 lldb::offset_t offset = 0; 1143 1144 ptr = extractor.GetAddress(&offset); 1145 1146 dump_stream.PutChar('\n'); 1147 } 1148 } 1149 1150 if (m_temporary_allocation == LLDB_INVALID_ADDRESS) { 1151 dump_stream.Printf("Points to process memory:\n"); 1152 } else { 1153 dump_stream.Printf("Temporary allocation:\n"); 1154 } 1155 1156 if (ptr == LLDB_INVALID_ADDRESS) { 1157 dump_stream.Printf(" <could not be be found>\n"); 1158 } else { 1159 DataBufferHeap data(m_temporary_allocation_size, 0); 1160 1161 map.ReadMemory(data.GetBytes(), m_temporary_allocation, 1162 m_temporary_allocation_size, err); 1163 1164 if (!err.Success()) { 1165 dump_stream.Printf(" <could not be read>\n"); 1166 } else { 1167 DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, 1168 load_addr); 1169 1170 dump_stream.PutChar('\n'); 1171 } 1172 } 1173 1174 log->PutString(dump_stream.GetString()); 1175 } 1176 1177 void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override { 1178 if (!m_keep_in_memory && m_temporary_allocation != LLDB_INVALID_ADDRESS) { 1179 Status free_error; 1180 1181 map.Free(m_temporary_allocation, free_error); 1182 } 1183 1184 m_temporary_allocation = LLDB_INVALID_ADDRESS; 1185 m_temporary_allocation_size = 0; 1186 } 1187 1188 private: 1189 CompilerType m_type; 1190 bool m_is_program_reference; 1191 bool m_keep_in_memory; 1192 1193 lldb::addr_t m_temporary_allocation = LLDB_INVALID_ADDRESS; 1194 size_t m_temporary_allocation_size = 0; 1195 Materializer::PersistentVariableDelegate *m_delegate; 1196 }; 1197 1198 uint32_t Materializer::AddResultVariable(const CompilerType &type, 1199 bool is_program_reference, 1200 bool keep_in_memory, 1201 PersistentVariableDelegate *delegate, 1202 Status &err) { 1203 EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP()); 1204 *iter = std::make_unique<EntityResultVariable>(type, is_program_reference, 1205 keep_in_memory, delegate); 1206 uint32_t ret = AddStructMember(**iter); 1207 (*iter)->SetOffset(ret); 1208 return ret; 1209 } 1210 1211 class EntitySymbol : public Materializer::Entity { 1212 public: 1213 EntitySymbol(const Symbol &symbol) : Entity(), m_symbol(symbol) { 1214 // Hard-coding to maximum size of a symbol 1215 m_size = g_default_var_byte_size; 1216 m_alignment = g_default_var_alignment; 1217 } 1218 1219 void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 1220 lldb::addr_t process_address, Status &err) override { 1221 Log *log = GetLog(LLDBLog::Expressions); 1222 1223 const lldb::addr_t load_addr = process_address + m_offset; 1224 1225 if (log) { 1226 LLDB_LOGF(log, 1227 "EntitySymbol::Materialize [address = 0x%" PRIx64 1228 ", m_symbol = %s]", 1229 (uint64_t)load_addr, m_symbol.GetName().AsCString()); 1230 } 1231 1232 const Address sym_address = m_symbol.GetAddress(); 1233 1234 ExecutionContextScope *exe_scope = frame_sp.get(); 1235 if (!exe_scope) 1236 exe_scope = map.GetBestExecutionContextScope(); 1237 1238 lldb::TargetSP target_sp; 1239 1240 if (exe_scope) 1241 target_sp = map.GetBestExecutionContextScope()->CalculateTarget(); 1242 1243 if (!target_sp) { 1244 err = Status::FromErrorStringWithFormat( 1245 "couldn't resolve symbol %s because there is no target", 1246 m_symbol.GetName().AsCString()); 1247 return; 1248 } 1249 1250 lldb::addr_t resolved_address = sym_address.GetLoadAddress(target_sp.get()); 1251 1252 if (resolved_address == LLDB_INVALID_ADDRESS) 1253 resolved_address = sym_address.GetFileAddress(); 1254 1255 Status pointer_write_error; 1256 1257 map.WritePointerToMemory(load_addr, resolved_address, pointer_write_error); 1258 1259 if (!pointer_write_error.Success()) { 1260 err = Status::FromErrorStringWithFormat( 1261 "couldn't write the address of symbol %s: %s", 1262 m_symbol.GetName().AsCString(), pointer_write_error.AsCString()); 1263 return; 1264 } 1265 } 1266 1267 void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 1268 lldb::addr_t process_address, lldb::addr_t frame_top, 1269 lldb::addr_t frame_bottom, Status &err) override { 1270 Log *log = GetLog(LLDBLog::Expressions); 1271 1272 const lldb::addr_t load_addr = process_address + m_offset; 1273 1274 if (log) { 1275 LLDB_LOGF(log, 1276 "EntitySymbol::Dematerialize [address = 0x%" PRIx64 1277 ", m_symbol = %s]", 1278 (uint64_t)load_addr, m_symbol.GetName().AsCString()); 1279 } 1280 1281 // no work needs to be done 1282 } 1283 1284 void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address, 1285 Log *log) override { 1286 StreamString dump_stream; 1287 1288 Status err; 1289 1290 const lldb::addr_t load_addr = process_address + m_offset; 1291 1292 dump_stream.Printf("0x%" PRIx64 ": EntitySymbol (%s)\n", load_addr, 1293 m_symbol.GetName().AsCString()); 1294 1295 { 1296 dump_stream.Printf("Pointer:\n"); 1297 1298 DataBufferHeap data(m_size, 0); 1299 1300 map.ReadMemory(data.GetBytes(), load_addr, m_size, err); 1301 1302 if (!err.Success()) { 1303 dump_stream.Printf(" <could not be read>\n"); 1304 } else { 1305 DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, 1306 load_addr); 1307 1308 dump_stream.PutChar('\n'); 1309 } 1310 } 1311 1312 log->PutString(dump_stream.GetString()); 1313 } 1314 1315 void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {} 1316 1317 private: 1318 Symbol m_symbol; 1319 }; 1320 1321 uint32_t Materializer::AddSymbol(const Symbol &symbol_sp, Status &err) { 1322 EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP()); 1323 *iter = std::make_unique<EntitySymbol>(symbol_sp); 1324 uint32_t ret = AddStructMember(**iter); 1325 (*iter)->SetOffset(ret); 1326 return ret; 1327 } 1328 1329 class EntityRegister : public Materializer::Entity { 1330 public: 1331 EntityRegister(const RegisterInfo ®ister_info) 1332 : Entity(), m_register_info(register_info) { 1333 // Hard-coding alignment conservatively 1334 m_size = m_register_info.byte_size; 1335 m_alignment = m_register_info.byte_size; 1336 } 1337 1338 void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 1339 lldb::addr_t process_address, Status &err) override { 1340 Log *log = GetLog(LLDBLog::Expressions); 1341 1342 const lldb::addr_t load_addr = process_address + m_offset; 1343 1344 if (log) { 1345 LLDB_LOGF(log, 1346 "EntityRegister::Materialize [address = 0x%" PRIx64 1347 ", m_register_info = %s]", 1348 (uint64_t)load_addr, m_register_info.name); 1349 } 1350 1351 RegisterValue reg_value; 1352 1353 if (!frame_sp.get()) { 1354 err = Status::FromErrorStringWithFormat( 1355 "couldn't materialize register %s without a stack frame", 1356 m_register_info.name); 1357 return; 1358 } 1359 1360 lldb::RegisterContextSP reg_context_sp = frame_sp->GetRegisterContext(); 1361 1362 if (!reg_context_sp->ReadRegister(&m_register_info, reg_value)) { 1363 err = Status::FromErrorStringWithFormat( 1364 "couldn't read the value of register %s", m_register_info.name); 1365 return; 1366 } 1367 1368 DataExtractor register_data; 1369 1370 if (!reg_value.GetData(register_data)) { 1371 err = Status::FromErrorStringWithFormat( 1372 "couldn't get the data for register %s", m_register_info.name); 1373 return; 1374 } 1375 1376 if (register_data.GetByteSize() != m_register_info.byte_size) { 1377 err = Status::FromErrorStringWithFormat( 1378 "data for register %s had size %llu but we expected %llu", 1379 m_register_info.name, (unsigned long long)register_data.GetByteSize(), 1380 (unsigned long long)m_register_info.byte_size); 1381 return; 1382 } 1383 1384 m_register_contents = std::make_shared<DataBufferHeap>( 1385 register_data.GetDataStart(), register_data.GetByteSize()); 1386 1387 Status write_error; 1388 1389 map.WriteMemory(load_addr, register_data.GetDataStart(), 1390 register_data.GetByteSize(), write_error); 1391 1392 if (!write_error.Success()) { 1393 err = Status::FromErrorStringWithFormat( 1394 "couldn't write the contents of register %s: %s", 1395 m_register_info.name, write_error.AsCString()); 1396 return; 1397 } 1398 } 1399 1400 void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 1401 lldb::addr_t process_address, lldb::addr_t frame_top, 1402 lldb::addr_t frame_bottom, Status &err) override { 1403 Log *log = GetLog(LLDBLog::Expressions); 1404 1405 const lldb::addr_t load_addr = process_address + m_offset; 1406 1407 if (log) { 1408 LLDB_LOGF(log, 1409 "EntityRegister::Dematerialize [address = 0x%" PRIx64 1410 ", m_register_info = %s]", 1411 (uint64_t)load_addr, m_register_info.name); 1412 } 1413 1414 Status extract_error; 1415 1416 DataExtractor register_data; 1417 1418 if (!frame_sp.get()) { 1419 err = Status::FromErrorStringWithFormat( 1420 "couldn't dematerialize register %s without a stack frame", 1421 m_register_info.name); 1422 return; 1423 } 1424 1425 lldb::RegisterContextSP reg_context_sp = frame_sp->GetRegisterContext(); 1426 1427 map.GetMemoryData(register_data, load_addr, m_register_info.byte_size, 1428 extract_error); 1429 1430 if (!extract_error.Success()) { 1431 err = Status::FromErrorStringWithFormat( 1432 "couldn't get the data for register %s: %s", m_register_info.name, 1433 extract_error.AsCString()); 1434 return; 1435 } 1436 1437 if (!memcmp(register_data.GetDataStart(), m_register_contents->GetBytes(), 1438 register_data.GetByteSize())) { 1439 // No write required, and in particular we avoid errors if the register 1440 // wasn't writable 1441 1442 m_register_contents.reset(); 1443 return; 1444 } 1445 1446 m_register_contents.reset(); 1447 1448 RegisterValue register_value(register_data.GetData(), 1449 register_data.GetByteOrder()); 1450 1451 if (!reg_context_sp->WriteRegister(&m_register_info, register_value)) { 1452 err = Status::FromErrorStringWithFormat( 1453 "couldn't write the value of register %s", m_register_info.name); 1454 return; 1455 } 1456 } 1457 1458 void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address, 1459 Log *log) override { 1460 StreamString dump_stream; 1461 1462 Status err; 1463 1464 const lldb::addr_t load_addr = process_address + m_offset; 1465 1466 dump_stream.Printf("0x%" PRIx64 ": EntityRegister (%s)\n", load_addr, 1467 m_register_info.name); 1468 1469 { 1470 dump_stream.Printf("Value:\n"); 1471 1472 DataBufferHeap data(m_size, 0); 1473 1474 map.ReadMemory(data.GetBytes(), load_addr, m_size, err); 1475 1476 if (!err.Success()) { 1477 dump_stream.Printf(" <could not be read>\n"); 1478 } else { 1479 DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, 1480 load_addr); 1481 1482 dump_stream.PutChar('\n'); 1483 } 1484 } 1485 1486 log->PutString(dump_stream.GetString()); 1487 } 1488 1489 void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {} 1490 1491 private: 1492 RegisterInfo m_register_info; 1493 lldb::DataBufferSP m_register_contents; 1494 }; 1495 1496 uint32_t Materializer::AddRegister(const RegisterInfo ®ister_info, 1497 Status &err) { 1498 EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP()); 1499 *iter = std::make_unique<EntityRegister>(register_info); 1500 uint32_t ret = AddStructMember(**iter); 1501 (*iter)->SetOffset(ret); 1502 return ret; 1503 } 1504 1505 Materializer::~Materializer() { 1506 DematerializerSP dematerializer_sp = m_dematerializer_wp.lock(); 1507 1508 if (dematerializer_sp) 1509 dematerializer_sp->Wipe(); 1510 } 1511 1512 Materializer::DematerializerSP 1513 Materializer::Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map, 1514 lldb::addr_t process_address, Status &error) { 1515 ExecutionContextScope *exe_scope = frame_sp.get(); 1516 if (!exe_scope) 1517 exe_scope = map.GetBestExecutionContextScope(); 1518 1519 DematerializerSP dematerializer_sp = m_dematerializer_wp.lock(); 1520 1521 if (dematerializer_sp) { 1522 error = 1523 Status::FromErrorString("Couldn't materialize: already materialized"); 1524 } 1525 1526 DematerializerSP ret( 1527 new Dematerializer(*this, frame_sp, map, process_address)); 1528 1529 if (!exe_scope) { 1530 error = 1531 Status::FromErrorString("Couldn't materialize: target doesn't exist"); 1532 } 1533 1534 for (EntityUP &entity_up : m_entities) { 1535 entity_up->Materialize(frame_sp, map, process_address, error); 1536 1537 if (!error.Success()) 1538 return DematerializerSP(); 1539 } 1540 1541 if (Log *log = GetLog(LLDBLog::Expressions)) { 1542 LLDB_LOGF( 1543 log, 1544 "Materializer::Materialize (frame_sp = %p, process_address = 0x%" PRIx64 1545 ") materialized:", 1546 static_cast<void *>(frame_sp.get()), process_address); 1547 for (EntityUP &entity_up : m_entities) 1548 entity_up->DumpToLog(map, process_address, log); 1549 } 1550 1551 m_dematerializer_wp = ret; 1552 1553 return ret; 1554 } 1555 1556 void Materializer::Dematerializer::Dematerialize(Status &error, 1557 lldb::addr_t frame_bottom, 1558 lldb::addr_t frame_top) { 1559 lldb::StackFrameSP frame_sp; 1560 1561 lldb::ThreadSP thread_sp = m_thread_wp.lock(); 1562 if (thread_sp) 1563 frame_sp = thread_sp->GetFrameWithStackID(m_stack_id); 1564 1565 ExecutionContextScope *exe_scope = frame_sp.get(); 1566 if (!exe_scope) 1567 exe_scope = m_map->GetBestExecutionContextScope(); 1568 1569 if (!IsValid()) { 1570 error = Status::FromErrorString( 1571 "Couldn't dematerialize: invalid dematerializer"); 1572 } 1573 1574 if (!exe_scope) { 1575 error = Status::FromErrorString("Couldn't dematerialize: target is gone"); 1576 } else { 1577 if (Log *log = GetLog(LLDBLog::Expressions)) { 1578 LLDB_LOGF(log, 1579 "Materializer::Dematerialize (frame_sp = %p, process_address " 1580 "= 0x%" PRIx64 ") about to dematerialize:", 1581 static_cast<void *>(frame_sp.get()), m_process_address); 1582 for (EntityUP &entity_up : m_materializer->m_entities) 1583 entity_up->DumpToLog(*m_map, m_process_address, log); 1584 } 1585 1586 for (EntityUP &entity_up : m_materializer->m_entities) { 1587 entity_up->Dematerialize(frame_sp, *m_map, m_process_address, frame_top, 1588 frame_bottom, error); 1589 1590 if (!error.Success()) 1591 break; 1592 } 1593 } 1594 1595 Wipe(); 1596 } 1597 1598 void Materializer::Dematerializer::Wipe() { 1599 if (!IsValid()) 1600 return; 1601 1602 for (EntityUP &entity_up : m_materializer->m_entities) { 1603 entity_up->Wipe(*m_map, m_process_address); 1604 } 1605 1606 m_materializer = nullptr; 1607 m_map = nullptr; 1608 m_process_address = LLDB_INVALID_ADDRESS; 1609 } 1610 1611 Materializer::PersistentVariableDelegate::PersistentVariableDelegate() = 1612 default; 1613 Materializer::PersistentVariableDelegate::~PersistentVariableDelegate() = 1614 default; 1615