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