1 //===-- Materializer.cpp ----------------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
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/ClangASTContext.h"
15 #include "lldb/Symbol/Symbol.h"
16 #include "lldb/Symbol/Type.h"
17 #include "lldb/Symbol/Variable.h"
18 #include "lldb/Target/ExecutionContext.h"
19 #include "lldb/Target/RegisterContext.h"
20 #include "lldb/Target/StackFrame.h"
21 #include "lldb/Target/Target.h"
22 #include "lldb/Target/Thread.h"
23 #include "lldb/Utility/Log.h"
24 #include "lldb/Utility/RegisterValue.h"
28 using namespace lldb_private;
30 uint32_t Materializer::AddStructMember(Entity &entity) {
31 uint32_t size = entity.GetSize();
32 uint32_t alignment = entity.GetAlignment();
36 if (m_current_offset == 0)
37 m_struct_alignment = alignment;
39 if (m_current_offset % alignment)
40 m_current_offset += (alignment - (m_current_offset % alignment));
42 ret = m_current_offset;
44 m_current_offset += size;
49 void Materializer::Entity::SetSizeAndAlignmentFromType(CompilerType &type) {
50 if (llvm::Optional<uint64_t> size = type.GetByteSize(nullptr))
53 uint32_t bit_alignment = type.GetTypeBitAlign();
55 if (bit_alignment % 8) {
57 bit_alignment &= ~((uint32_t)0x111u);
60 m_alignment = bit_alignment / 8;
63 class EntityPersistentVariable : public Materializer::Entity {
65 EntityPersistentVariable(lldb::ExpressionVariableSP &persistent_variable_sp,
66 Materializer::PersistentVariableDelegate *delegate)
67 : Entity(), m_persistent_variable_sp(persistent_variable_sp),
68 m_delegate(delegate) {
69 // Hard-coding to maximum size of a pointer since persistent variables are
70 // materialized by reference
75 void MakeAllocation(IRMemoryMap &map, Status &err) {
76 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
78 // Allocate a spare memory area to store the persistent variable's
81 Status allocate_error;
82 const bool zero_memory = false;
84 lldb::addr_t mem = map.Malloc(
85 m_persistent_variable_sp->GetByteSize(), 8,
86 lldb::ePermissionsReadable | lldb::ePermissionsWritable,
87 IRMemoryMap::eAllocationPolicyMirror, zero_memory, allocate_error);
89 if (!allocate_error.Success()) {
90 err.SetErrorStringWithFormat(
91 "couldn't allocate a memory area to store %s: %s",
92 m_persistent_variable_sp->GetName().GetCString(),
93 allocate_error.AsCString());
98 log->Printf("Allocated %s (0x%" PRIx64 ") successfully",
99 m_persistent_variable_sp->GetName().GetCString(), mem);
101 // Put the location of the spare memory into the live data of the
104 m_persistent_variable_sp->m_live_sp = ValueObjectConstResult::Create(
105 map.GetBestExecutionContextScope(),
106 m_persistent_variable_sp->GetCompilerType(),
107 m_persistent_variable_sp->GetName(), mem, eAddressTypeLoad,
108 map.GetAddressByteSize());
110 // Clear the flag if the variable will never be deallocated.
112 if (m_persistent_variable_sp->m_flags &
113 ExpressionVariable::EVKeepInTarget) {
115 map.Leak(mem, leak_error);
116 m_persistent_variable_sp->m_flags &=
117 ~ExpressionVariable::EVNeedsAllocation;
120 // Write the contents of the variable to the area.
124 map.WriteMemory(mem, m_persistent_variable_sp->GetValueBytes(),
125 m_persistent_variable_sp->GetByteSize(), write_error);
127 if (!write_error.Success()) {
128 err.SetErrorStringWithFormat(
129 "couldn't write %s to the target: %s",
130 m_persistent_variable_sp->GetName().AsCString(),
131 write_error.AsCString());
136 void DestroyAllocation(IRMemoryMap &map, Status &err) {
137 Status deallocate_error;
139 map.Free((lldb::addr_t)m_persistent_variable_sp->m_live_sp->GetValue()
144 m_persistent_variable_sp->m_live_sp.reset();
146 if (!deallocate_error.Success()) {
147 err.SetErrorStringWithFormat(
148 "couldn't deallocate memory for %s: %s",
149 m_persistent_variable_sp->GetName().GetCString(),
150 deallocate_error.AsCString());
154 void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
155 lldb::addr_t process_address, Status &err) override {
156 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
158 const lldb::addr_t load_addr = process_address + m_offset;
161 log->Printf("EntityPersistentVariable::Materialize [address = 0x%" PRIx64
162 ", m_name = %s, m_flags = 0x%hx]",
164 m_persistent_variable_sp->GetName().AsCString(),
165 m_persistent_variable_sp->m_flags);
168 if (m_persistent_variable_sp->m_flags &
169 ExpressionVariable::EVNeedsAllocation) {
170 MakeAllocation(map, err);
171 m_persistent_variable_sp->m_flags |=
172 ExpressionVariable::EVIsLLDBAllocated;
178 if ((m_persistent_variable_sp->m_flags &
179 ExpressionVariable::EVIsProgramReference &&
180 m_persistent_variable_sp->m_live_sp) ||
181 m_persistent_variable_sp->m_flags &
182 ExpressionVariable::EVIsLLDBAllocated) {
185 map.WriteScalarToMemory(
187 m_persistent_variable_sp->m_live_sp->GetValue().GetScalar(),
188 map.GetAddressByteSize(), write_error);
190 if (!write_error.Success()) {
191 err.SetErrorStringWithFormat(
192 "couldn't write the location of %s to memory: %s",
193 m_persistent_variable_sp->GetName().AsCString(),
194 write_error.AsCString());
197 err.SetErrorStringWithFormat(
198 "no materialization happened for persistent variable %s",
199 m_persistent_variable_sp->GetName().AsCString());
204 void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
205 lldb::addr_t process_address, lldb::addr_t frame_top,
206 lldb::addr_t frame_bottom, Status &err) override {
207 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
209 const lldb::addr_t load_addr = process_address + m_offset;
213 "EntityPersistentVariable::Dematerialize [address = 0x%" PRIx64
214 ", m_name = %s, m_flags = 0x%hx]",
215 (uint64_t)process_address + m_offset,
216 m_persistent_variable_sp->GetName().AsCString(),
217 m_persistent_variable_sp->m_flags);
221 m_delegate->DidDematerialize(m_persistent_variable_sp);
224 if ((m_persistent_variable_sp->m_flags &
225 ExpressionVariable::EVIsLLDBAllocated) ||
226 (m_persistent_variable_sp->m_flags &
227 ExpressionVariable::EVIsProgramReference)) {
228 if (m_persistent_variable_sp->m_flags &
229 ExpressionVariable::EVIsProgramReference &&
230 !m_persistent_variable_sp->m_live_sp) {
231 // If the reference comes from the program, then the
232 // ClangExpressionVariable's live variable data hasn't been set up yet.
235 lldb::addr_t location;
238 map.ReadPointerFromMemory(&location, load_addr, read_error);
240 if (!read_error.Success()) {
241 err.SetErrorStringWithFormat(
242 "couldn't read the address of program-allocated variable %s: %s",
243 m_persistent_variable_sp->GetName().GetCString(),
244 read_error.AsCString());
248 m_persistent_variable_sp->m_live_sp = ValueObjectConstResult::Create(
249 map.GetBestExecutionContextScope(),
250 m_persistent_variable_sp.get()->GetCompilerType(),
251 m_persistent_variable_sp->GetName(), location, eAddressTypeLoad,
252 m_persistent_variable_sp->GetByteSize());
254 if (frame_top != LLDB_INVALID_ADDRESS &&
255 frame_bottom != LLDB_INVALID_ADDRESS && location >= frame_bottom &&
256 location <= frame_top) {
257 // If the variable is resident in the stack frame created by the
258 // expression, then it cannot be relied upon to stay around. We
259 // treat it as needing reallocation.
260 m_persistent_variable_sp->m_flags |=
261 ExpressionVariable::EVIsLLDBAllocated;
262 m_persistent_variable_sp->m_flags |=
263 ExpressionVariable::EVNeedsAllocation;
264 m_persistent_variable_sp->m_flags |=
265 ExpressionVariable::EVNeedsFreezeDry;
266 m_persistent_variable_sp->m_flags &=
267 ~ExpressionVariable::EVIsProgramReference;
271 lldb::addr_t mem = m_persistent_variable_sp->m_live_sp->GetValue()
275 if (!m_persistent_variable_sp->m_live_sp) {
276 err.SetErrorStringWithFormat(
277 "couldn't find the memory area used to store %s",
278 m_persistent_variable_sp->GetName().GetCString());
282 if (m_persistent_variable_sp->m_live_sp->GetValue()
283 .GetValueAddressType() != eAddressTypeLoad) {
284 err.SetErrorStringWithFormat(
285 "the address of the memory area for %s is in an incorrect format",
286 m_persistent_variable_sp->GetName().GetCString());
290 if (m_persistent_variable_sp->m_flags &
291 ExpressionVariable::EVNeedsFreezeDry ||
292 m_persistent_variable_sp->m_flags &
293 ExpressionVariable::EVKeepInTarget) {
296 "Dematerializing %s from 0x%" PRIx64 " (size = %llu)",
297 m_persistent_variable_sp->GetName().GetCString(), (uint64_t)mem,
298 (unsigned long long)m_persistent_variable_sp->GetByteSize());
300 // Read the contents of the spare memory area
302 m_persistent_variable_sp->ValueUpdated();
306 map.ReadMemory(m_persistent_variable_sp->GetValueBytes(), mem,
307 m_persistent_variable_sp->GetByteSize(), read_error);
309 if (!read_error.Success()) {
310 err.SetErrorStringWithFormat(
311 "couldn't read the contents of %s from memory: %s",
312 m_persistent_variable_sp->GetName().GetCString(),
313 read_error.AsCString());
317 m_persistent_variable_sp->m_flags &=
318 ~ExpressionVariable::EVNeedsFreezeDry;
321 err.SetErrorStringWithFormat(
322 "no dematerialization happened for persistent variable %s",
323 m_persistent_variable_sp->GetName().AsCString());
327 lldb::ProcessSP process_sp =
328 map.GetBestExecutionContextScope()->CalculateProcess();
329 if (!process_sp || !process_sp->CanJIT()) {
330 // Allocations are not persistent so persistent variables cannot stay
333 m_persistent_variable_sp->m_flags |=
334 ExpressionVariable::EVNeedsAllocation;
336 DestroyAllocation(map, err);
339 } else if (m_persistent_variable_sp->m_flags &
340 ExpressionVariable::EVNeedsAllocation &&
341 !(m_persistent_variable_sp->m_flags &
342 ExpressionVariable::EVKeepInTarget)) {
343 DestroyAllocation(map, err);
349 void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
351 StreamString dump_stream;
355 const lldb::addr_t load_addr = process_address + m_offset;
357 dump_stream.Printf("0x%" PRIx64 ": EntityPersistentVariable (%s)\n",
359 m_persistent_variable_sp->GetName().AsCString());
362 dump_stream.Printf("Pointer:\n");
364 DataBufferHeap data(m_size, 0);
366 map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
368 if (!err.Success()) {
369 dump_stream.Printf(" <could not be read>\n");
371 DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
374 dump_stream.PutChar('\n');
379 dump_stream.Printf("Target:\n");
381 lldb::addr_t target_address;
383 map.ReadPointerFromMemory(&target_address, load_addr, err);
385 if (!err.Success()) {
386 dump_stream.Printf(" <could not be read>\n");
388 DataBufferHeap data(m_persistent_variable_sp->GetByteSize(), 0);
390 map.ReadMemory(data.GetBytes(), target_address,
391 m_persistent_variable_sp->GetByteSize(), err);
393 if (!err.Success()) {
394 dump_stream.Printf(" <could not be read>\n");
396 DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
399 dump_stream.PutChar('\n');
404 log->PutString(dump_stream.GetString());
407 void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {}
410 lldb::ExpressionVariableSP m_persistent_variable_sp;
411 Materializer::PersistentVariableDelegate *m_delegate;
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->reset(new EntityPersistentVariable(persistent_variable_sp, delegate));
419 uint32_t ret = AddStructMember(**iter);
420 (*iter)->SetOffset(ret);
424 class EntityVariable : public Materializer::Entity {
426 EntityVariable(lldb::VariableSP &variable_sp)
427 : Entity(), m_variable_sp(variable_sp), m_is_reference(false),
428 m_temporary_allocation(LLDB_INVALID_ADDRESS),
429 m_temporary_allocation_size(0) {
430 // Hard-coding to maximum size of a pointer since all variables are
431 // materialized by reference
435 m_variable_sp->GetType()->GetForwardCompilerType().IsReferenceType();
438 void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
439 lldb::addr_t process_address, Status &err) override {
440 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
442 const lldb::addr_t load_addr = process_address + m_offset;
444 log->Printf("EntityVariable::Materialize [address = 0x%" PRIx64
445 ", m_variable_sp = %s]",
446 (uint64_t)load_addr, m_variable_sp->GetName().AsCString());
449 ExecutionContextScope *scope = frame_sp.get();
452 scope = map.GetBestExecutionContextScope();
454 lldb::ValueObjectSP valobj_sp =
455 ValueObjectVariable::Create(scope, m_variable_sp);
458 err.SetErrorStringWithFormat(
459 "couldn't get a value object for variable %s",
460 m_variable_sp->GetName().AsCString());
464 Status valobj_error = valobj_sp->GetError();
466 if (valobj_error.Fail()) {
467 err.SetErrorStringWithFormat("couldn't get the value of variable %s: %s",
468 m_variable_sp->GetName().AsCString(),
469 valobj_error.AsCString());
473 if (m_is_reference) {
474 DataExtractor valobj_extractor;
475 Status extract_error;
476 valobj_sp->GetData(valobj_extractor, extract_error);
478 if (!extract_error.Success()) {
479 err.SetErrorStringWithFormat(
480 "couldn't read contents of reference variable %s: %s",
481 m_variable_sp->GetName().AsCString(), extract_error.AsCString());
485 lldb::offset_t offset = 0;
486 lldb::addr_t reference_addr = valobj_extractor.GetAddress(&offset);
489 map.WritePointerToMemory(load_addr, reference_addr, write_error);
491 if (!write_error.Success()) {
492 err.SetErrorStringWithFormat("couldn't write the contents of reference "
493 "variable %s to memory: %s",
494 m_variable_sp->GetName().AsCString(),
495 write_error.AsCString());
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) {
505 map.WritePointerToMemory(load_addr, addr_of_valobj, write_error);
507 if (!write_error.Success()) {
508 err.SetErrorStringWithFormat(
509 "couldn't write the address of variable %s to memory: %s",
510 m_variable_sp->GetName().AsCString(), write_error.AsCString());
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 m_variable_sp->GetName().AsCString(),
520 extract_error.AsCString());
524 if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
525 err.SetErrorStringWithFormat(
526 "trying to create a temporary region for %s but one exists",
527 m_variable_sp->GetName().AsCString());
531 if (data.GetByteSize() < m_variable_sp->GetType()->GetByteSize()) {
532 if (data.GetByteSize() == 0 &&
533 !m_variable_sp->LocationExpression().IsValid()) {
534 err.SetErrorStringWithFormat("the variable '%s' has no location, "
535 "it may have been optimized out",
536 m_variable_sp->GetName().AsCString());
538 err.SetErrorStringWithFormat(
539 "size of variable %s (%" PRIu64
540 ") is larger than the ValueObject's size (%" PRIu64 ")",
541 m_variable_sp->GetName().AsCString(),
542 m_variable_sp->GetType()->GetByteSize().getValueOr(0),
549 m_variable_sp->GetType()->GetLayoutCompilerType().GetTypeBitAlign();
550 size_t byte_align = (bit_align + 7) / 8;
556 const bool zero_memory = false;
558 m_temporary_allocation = map.Malloc(
559 data.GetByteSize(), byte_align,
560 lldb::ePermissionsReadable | lldb::ePermissionsWritable,
561 IRMemoryMap::eAllocationPolicyMirror, zero_memory, alloc_error);
563 m_temporary_allocation_size = data.GetByteSize();
565 m_original_data = std::make_shared<DataBufferHeap>(data.GetDataStart(),
568 if (!alloc_error.Success()) {
569 err.SetErrorStringWithFormat(
570 "couldn't allocate a temporary region for %s: %s",
571 m_variable_sp->GetName().AsCString(), alloc_error.AsCString());
577 map.WriteMemory(m_temporary_allocation, data.GetDataStart(),
578 data.GetByteSize(), write_error);
580 if (!write_error.Success()) {
581 err.SetErrorStringWithFormat(
582 "couldn't write to the temporary region for %s: %s",
583 m_variable_sp->GetName().AsCString(), write_error.AsCString());
587 Status pointer_write_error;
589 map.WritePointerToMemory(load_addr, m_temporary_allocation,
590 pointer_write_error);
592 if (!pointer_write_error.Success()) {
593 err.SetErrorStringWithFormat(
594 "couldn't write the address of the temporary region for %s: %s",
595 m_variable_sp->GetName().AsCString(),
596 pointer_write_error.AsCString());
602 void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
603 lldb::addr_t process_address, lldb::addr_t frame_top,
604 lldb::addr_t frame_bottom, Status &err) override {
605 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
607 const lldb::addr_t load_addr = process_address + m_offset;
609 log->Printf("EntityVariable::Dematerialize [address = 0x%" PRIx64
610 ", m_variable_sp = %s]",
611 (uint64_t)load_addr, m_variable_sp->GetName().AsCString());
614 if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
615 ExecutionContextScope *scope = frame_sp.get();
618 scope = map.GetBestExecutionContextScope();
620 lldb::ValueObjectSP valobj_sp =
621 ValueObjectVariable::Create(scope, m_variable_sp);
624 err.SetErrorStringWithFormat(
625 "couldn't get a value object for variable %s",
626 m_variable_sp->GetName().AsCString());
630 lldb_private::DataExtractor data;
632 Status extract_error;
634 map.GetMemoryData(data, m_temporary_allocation, valobj_sp->GetByteSize(),
637 if (!extract_error.Success()) {
638 err.SetErrorStringWithFormat("couldn't get the data for variable %s",
639 m_variable_sp->GetName().AsCString());
643 bool actually_write = true;
645 if (m_original_data) {
646 if ((data.GetByteSize() == m_original_data->GetByteSize()) &&
647 !memcmp(m_original_data->GetBytes(), data.GetDataStart(),
648 data.GetByteSize())) {
649 actually_write = false;
655 if (actually_write) {
656 valobj_sp->SetData(data, set_error);
658 if (!set_error.Success()) {
659 err.SetErrorStringWithFormat(
660 "couldn't write the new contents of %s back into the variable",
661 m_variable_sp->GetName().AsCString());
668 map.Free(m_temporary_allocation, free_error);
670 if (!free_error.Success()) {
671 err.SetErrorStringWithFormat(
672 "couldn't free the temporary region for %s: %s",
673 m_variable_sp->GetName().AsCString(), free_error.AsCString());
677 m_original_data.reset();
678 m_temporary_allocation = LLDB_INVALID_ADDRESS;
679 m_temporary_allocation_size = 0;
683 void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
685 StreamString dump_stream;
687 const lldb::addr_t load_addr = process_address + m_offset;
688 dump_stream.Printf("0x%" PRIx64 ": EntityVariable\n", load_addr);
692 lldb::addr_t ptr = LLDB_INVALID_ADDRESS;
695 dump_stream.Printf("Pointer:\n");
697 DataBufferHeap data(m_size, 0);
699 map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
701 if (!err.Success()) {
702 dump_stream.Printf(" <could not be read>\n");
704 DataExtractor extractor(data.GetBytes(), data.GetByteSize(),
705 map.GetByteOrder(), map.GetAddressByteSize());
707 DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
710 lldb::offset_t offset;
712 ptr = extractor.GetPointer(&offset);
714 dump_stream.PutChar('\n');
718 if (m_temporary_allocation == LLDB_INVALID_ADDRESS) {
719 dump_stream.Printf("Points to process memory:\n");
721 dump_stream.Printf("Temporary allocation:\n");
724 if (ptr == LLDB_INVALID_ADDRESS) {
725 dump_stream.Printf(" <could not be be found>\n");
727 DataBufferHeap data(m_temporary_allocation_size, 0);
729 map.ReadMemory(data.GetBytes(), m_temporary_allocation,
730 m_temporary_allocation_size, err);
732 if (!err.Success()) {
733 dump_stream.Printf(" <could not be read>\n");
735 DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
738 dump_stream.PutChar('\n');
742 log->PutString(dump_stream.GetString());
745 void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {
746 if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
749 map.Free(m_temporary_allocation, free_error);
751 m_temporary_allocation = LLDB_INVALID_ADDRESS;
752 m_temporary_allocation_size = 0;
757 lldb::VariableSP m_variable_sp;
759 lldb::addr_t m_temporary_allocation;
760 size_t m_temporary_allocation_size;
761 lldb::DataBufferSP m_original_data;
764 uint32_t Materializer::AddVariable(lldb::VariableSP &variable_sp, Status &err) {
765 EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
766 iter->reset(new EntityVariable(variable_sp));
767 uint32_t ret = AddStructMember(**iter);
768 (*iter)->SetOffset(ret);
772 class EntityResultVariable : public Materializer::Entity {
774 EntityResultVariable(const CompilerType &type, bool is_program_reference,
776 Materializer::PersistentVariableDelegate *delegate)
777 : Entity(), m_type(type), m_is_program_reference(is_program_reference),
778 m_keep_in_memory(keep_in_memory),
779 m_temporary_allocation(LLDB_INVALID_ADDRESS),
780 m_temporary_allocation_size(0), m_delegate(delegate) {
781 // Hard-coding to maximum size of a pointer since all results are
782 // materialized by reference
787 void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
788 lldb::addr_t process_address, Status &err) override {
789 if (!m_is_program_reference) {
790 if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
791 err.SetErrorString("Trying to create a temporary region for the result "
796 const lldb::addr_t load_addr = process_address + m_offset;
798 ExecutionContextScope *exe_scope = map.GetBestExecutionContextScope();
800 llvm::Optional<uint64_t> byte_size = m_type.GetByteSize(exe_scope);
802 err.SetErrorString("can't get size of type");
805 size_t bit_align = m_type.GetTypeBitAlign();
806 size_t byte_align = (bit_align + 7) / 8;
812 const bool zero_memory = true;
814 m_temporary_allocation = map.Malloc(
815 *byte_size, byte_align,
816 lldb::ePermissionsReadable | lldb::ePermissionsWritable,
817 IRMemoryMap::eAllocationPolicyMirror, zero_memory, alloc_error);
818 m_temporary_allocation_size = *byte_size;
820 if (!alloc_error.Success()) {
821 err.SetErrorStringWithFormat(
822 "couldn't allocate a temporary region for the result: %s",
823 alloc_error.AsCString());
827 Status pointer_write_error;
829 map.WritePointerToMemory(load_addr, m_temporary_allocation,
830 pointer_write_error);
832 if (!pointer_write_error.Success()) {
833 err.SetErrorStringWithFormat("couldn't write the address of the "
834 "temporary region for the result: %s",
835 pointer_write_error.AsCString());
840 void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
841 lldb::addr_t process_address, lldb::addr_t frame_top,
842 lldb::addr_t frame_bottom, Status &err) override {
845 ExecutionContextScope *exe_scope = map.GetBestExecutionContextScope();
848 err.SetErrorString("Couldn't dematerialize a result variable: invalid "
849 "execution context scope");
853 lldb::addr_t address;
855 const lldb::addr_t load_addr = process_address + m_offset;
857 map.ReadPointerFromMemory(&address, load_addr, read_error);
859 if (!read_error.Success()) {
860 err.SetErrorString("Couldn't dematerialize a result variable: couldn't "
865 lldb::TargetSP target_sp = exe_scope->CalculateTarget();
868 err.SetErrorString("Couldn't dematerialize a result variable: no target");
872 Status type_system_error;
873 TypeSystem *type_system = target_sp->GetScratchTypeSystemForLanguage(
874 &type_system_error, m_type.GetMinimumLanguage());
877 err.SetErrorStringWithFormat("Couldn't dematerialize a result variable: "
878 "couldn't get the corresponding type "
880 type_system_error.AsCString());
884 PersistentExpressionState *persistent_state =
885 type_system->GetPersistentExpressionState();
887 if (!persistent_state) {
888 err.SetErrorString("Couldn't dematerialize a result variable: "
889 "corresponding type system doesn't handle persistent "
896 ? m_delegate->GetName()
897 : persistent_state->GetNextPersistentVariableName(
898 *target_sp, persistent_state->GetPersistentVariablePrefix());
900 lldb::ExpressionVariableSP ret = persistent_state->CreatePersistentVariable(
901 exe_scope, name, m_type, map.GetByteOrder(), map.GetAddressByteSize());
904 err.SetErrorStringWithFormat("couldn't dematerialize a result variable: "
905 "failed to make persistent variable %s",
910 lldb::ProcessSP process_sp =
911 map.GetBestExecutionContextScope()->CalculateProcess();
914 m_delegate->DidDematerialize(ret);
918 (m_is_program_reference && process_sp && process_sp->CanJIT() &&
919 !(address >= frame_bottom && address < frame_top));
921 if (can_persist && m_keep_in_memory) {
922 ret->m_live_sp = ValueObjectConstResult::Create(exe_scope, m_type, name,
923 address, eAddressTypeLoad,
924 map.GetAddressByteSize());
929 const size_t pvar_byte_size = ret->GetByteSize();
930 uint8_t *pvar_data = ret->GetValueBytes();
932 map.ReadMemory(pvar_data, address, pvar_byte_size, read_error);
934 if (!read_error.Success()) {
936 "Couldn't dematerialize a result variable: couldn't read its memory");
940 if (!can_persist || !m_keep_in_memory) {
941 ret->m_flags |= ExpressionVariable::EVNeedsAllocation;
943 if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
945 map.Free(m_temporary_allocation, free_error);
948 ret->m_flags |= ExpressionVariable::EVIsLLDBAllocated;
951 m_temporary_allocation = LLDB_INVALID_ADDRESS;
952 m_temporary_allocation_size = 0;
955 void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
957 StreamString dump_stream;
959 const lldb::addr_t load_addr = process_address + m_offset;
961 dump_stream.Printf("0x%" PRIx64 ": EntityResultVariable\n", load_addr);
965 lldb::addr_t ptr = LLDB_INVALID_ADDRESS;
968 dump_stream.Printf("Pointer:\n");
970 DataBufferHeap data(m_size, 0);
972 map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
974 if (!err.Success()) {
975 dump_stream.Printf(" <could not be read>\n");
977 DataExtractor extractor(data.GetBytes(), data.GetByteSize(),
978 map.GetByteOrder(), map.GetAddressByteSize());
980 DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
983 lldb::offset_t offset;
985 ptr = extractor.GetPointer(&offset);
987 dump_stream.PutChar('\n');
991 if (m_temporary_allocation == LLDB_INVALID_ADDRESS) {
992 dump_stream.Printf("Points to process memory:\n");
994 dump_stream.Printf("Temporary allocation:\n");
997 if (ptr == LLDB_INVALID_ADDRESS) {
998 dump_stream.Printf(" <could not be be found>\n");
1000 DataBufferHeap data(m_temporary_allocation_size, 0);
1002 map.ReadMemory(data.GetBytes(), m_temporary_allocation,
1003 m_temporary_allocation_size, err);
1005 if (!err.Success()) {
1006 dump_stream.Printf(" <could not be read>\n");
1008 DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
1011 dump_stream.PutChar('\n');
1015 log->PutString(dump_stream.GetString());
1018 void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {
1019 if (!m_keep_in_memory && m_temporary_allocation != LLDB_INVALID_ADDRESS) {
1022 map.Free(m_temporary_allocation, free_error);
1025 m_temporary_allocation = LLDB_INVALID_ADDRESS;
1026 m_temporary_allocation_size = 0;
1030 CompilerType m_type;
1031 bool m_is_program_reference;
1032 bool m_keep_in_memory;
1034 lldb::addr_t m_temporary_allocation;
1035 size_t m_temporary_allocation_size;
1036 Materializer::PersistentVariableDelegate *m_delegate;
1039 uint32_t Materializer::AddResultVariable(const CompilerType &type,
1040 bool is_program_reference,
1041 bool keep_in_memory,
1042 PersistentVariableDelegate *delegate,
1044 EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
1045 iter->reset(new EntityResultVariable(type, is_program_reference,
1046 keep_in_memory, delegate));
1047 uint32_t ret = AddStructMember(**iter);
1048 (*iter)->SetOffset(ret);
1052 class EntitySymbol : public Materializer::Entity {
1054 EntitySymbol(const Symbol &symbol) : Entity(), m_symbol(symbol) {
1055 // Hard-coding to maximum size of a symbol
1060 void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1061 lldb::addr_t process_address, Status &err) override {
1062 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
1064 const lldb::addr_t load_addr = process_address + m_offset;
1067 log->Printf("EntitySymbol::Materialize [address = 0x%" PRIx64
1069 (uint64_t)load_addr, m_symbol.GetName().AsCString());
1072 const Address sym_address = m_symbol.GetAddress();
1074 ExecutionContextScope *exe_scope = map.GetBestExecutionContextScope();
1076 lldb::TargetSP target_sp;
1079 target_sp = map.GetBestExecutionContextScope()->CalculateTarget();
1082 err.SetErrorStringWithFormat(
1083 "couldn't resolve symbol %s because there is no target",
1084 m_symbol.GetName().AsCString());
1088 lldb::addr_t resolved_address = sym_address.GetLoadAddress(target_sp.get());
1090 if (resolved_address == LLDB_INVALID_ADDRESS)
1091 resolved_address = sym_address.GetFileAddress();
1093 Status pointer_write_error;
1095 map.WritePointerToMemory(load_addr, resolved_address, pointer_write_error);
1097 if (!pointer_write_error.Success()) {
1098 err.SetErrorStringWithFormat(
1099 "couldn't write the address of symbol %s: %s",
1100 m_symbol.GetName().AsCString(), pointer_write_error.AsCString());
1105 void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1106 lldb::addr_t process_address, lldb::addr_t frame_top,
1107 lldb::addr_t frame_bottom, Status &err) override {
1108 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
1110 const lldb::addr_t load_addr = process_address + m_offset;
1113 log->Printf("EntitySymbol::Dematerialize [address = 0x%" PRIx64
1115 (uint64_t)load_addr, m_symbol.GetName().AsCString());
1118 // no work needs to be done
1121 void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
1122 Log *log) override {
1123 StreamString dump_stream;
1127 const lldb::addr_t load_addr = process_address + m_offset;
1129 dump_stream.Printf("0x%" PRIx64 ": EntitySymbol (%s)\n", load_addr,
1130 m_symbol.GetName().AsCString());
1133 dump_stream.Printf("Pointer:\n");
1135 DataBufferHeap data(m_size, 0);
1137 map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
1139 if (!err.Success()) {
1140 dump_stream.Printf(" <could not be read>\n");
1142 DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
1145 dump_stream.PutChar('\n');
1149 log->PutString(dump_stream.GetString());
1152 void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {}
1158 uint32_t Materializer::AddSymbol(const Symbol &symbol_sp, Status &err) {
1159 EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
1160 iter->reset(new EntitySymbol(symbol_sp));
1161 uint32_t ret = AddStructMember(**iter);
1162 (*iter)->SetOffset(ret);
1166 class EntityRegister : public Materializer::Entity {
1168 EntityRegister(const RegisterInfo ®ister_info)
1169 : Entity(), m_register_info(register_info) {
1170 // Hard-coding alignment conservatively
1171 m_size = m_register_info.byte_size;
1172 m_alignment = m_register_info.byte_size;
1175 void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1176 lldb::addr_t process_address, Status &err) override {
1177 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
1179 const lldb::addr_t load_addr = process_address + m_offset;
1182 log->Printf("EntityRegister::Materialize [address = 0x%" PRIx64
1183 ", m_register_info = %s]",
1184 (uint64_t)load_addr, m_register_info.name);
1187 RegisterValue reg_value;
1189 if (!frame_sp.get()) {
1190 err.SetErrorStringWithFormat(
1191 "couldn't materialize register %s without a stack frame",
1192 m_register_info.name);
1196 lldb::RegisterContextSP reg_context_sp = frame_sp->GetRegisterContext();
1198 if (!reg_context_sp->ReadRegister(&m_register_info, reg_value)) {
1199 err.SetErrorStringWithFormat("couldn't read the value of register %s",
1200 m_register_info.name);
1204 DataExtractor register_data;
1206 if (!reg_value.GetData(register_data)) {
1207 err.SetErrorStringWithFormat("couldn't get the data for register %s",
1208 m_register_info.name);
1212 if (register_data.GetByteSize() != m_register_info.byte_size) {
1213 err.SetErrorStringWithFormat(
1214 "data for register %s had size %llu but we expected %llu",
1215 m_register_info.name, (unsigned long long)register_data.GetByteSize(),
1216 (unsigned long long)m_register_info.byte_size);
1220 m_register_contents = std::make_shared<DataBufferHeap>(
1221 register_data.GetDataStart(), register_data.GetByteSize());
1225 map.WriteMemory(load_addr, register_data.GetDataStart(),
1226 register_data.GetByteSize(), write_error);
1228 if (!write_error.Success()) {
1229 err.SetErrorStringWithFormat(
1230 "couldn't write the contents of register %s: %s",
1231 m_register_info.name, write_error.AsCString());
1236 void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1237 lldb::addr_t process_address, lldb::addr_t frame_top,
1238 lldb::addr_t frame_bottom, Status &err) override {
1239 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
1241 const lldb::addr_t load_addr = process_address + m_offset;
1244 log->Printf("EntityRegister::Dematerialize [address = 0x%" PRIx64
1245 ", m_register_info = %s]",
1246 (uint64_t)load_addr, m_register_info.name);
1249 Status extract_error;
1251 DataExtractor register_data;
1253 if (!frame_sp.get()) {
1254 err.SetErrorStringWithFormat(
1255 "couldn't dematerialize register %s without a stack frame",
1256 m_register_info.name);
1260 lldb::RegisterContextSP reg_context_sp = frame_sp->GetRegisterContext();
1262 map.GetMemoryData(register_data, load_addr, m_register_info.byte_size,
1265 if (!extract_error.Success()) {
1266 err.SetErrorStringWithFormat("couldn't get the data for register %s: %s",
1267 m_register_info.name,
1268 extract_error.AsCString());
1272 if (!memcmp(register_data.GetDataStart(), m_register_contents->GetBytes(),
1273 register_data.GetByteSize())) {
1274 // No write required, and in particular we avoid errors if the register
1277 m_register_contents.reset();
1281 m_register_contents.reset();
1283 RegisterValue register_value(
1284 const_cast<uint8_t *>(register_data.GetDataStart()),
1285 register_data.GetByteSize(), register_data.GetByteOrder());
1287 if (!reg_context_sp->WriteRegister(&m_register_info, register_value)) {
1288 err.SetErrorStringWithFormat("couldn't write the value of register %s",
1289 m_register_info.name);
1294 void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
1295 Log *log) override {
1296 StreamString dump_stream;
1300 const lldb::addr_t load_addr = process_address + m_offset;
1302 dump_stream.Printf("0x%" PRIx64 ": EntityRegister (%s)\n", load_addr,
1303 m_register_info.name);
1306 dump_stream.Printf("Value:\n");
1308 DataBufferHeap data(m_size, 0);
1310 map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
1312 if (!err.Success()) {
1313 dump_stream.Printf(" <could not be read>\n");
1315 DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
1318 dump_stream.PutChar('\n');
1322 log->PutString(dump_stream.GetString());
1325 void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {}
1328 RegisterInfo m_register_info;
1329 lldb::DataBufferSP m_register_contents;
1332 uint32_t Materializer::AddRegister(const RegisterInfo ®ister_info,
1334 EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
1335 iter->reset(new EntityRegister(register_info));
1336 uint32_t ret = AddStructMember(**iter);
1337 (*iter)->SetOffset(ret);
1341 Materializer::Materializer()
1342 : m_dematerializer_wp(), m_current_offset(0), m_struct_alignment(8) {}
1344 Materializer::~Materializer() {
1345 DematerializerSP dematerializer_sp = m_dematerializer_wp.lock();
1347 if (dematerializer_sp)
1348 dematerializer_sp->Wipe();
1351 Materializer::DematerializerSP
1352 Materializer::Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1353 lldb::addr_t process_address, Status &error) {
1354 ExecutionContextScope *exe_scope = frame_sp.get();
1357 exe_scope = map.GetBestExecutionContextScope();
1359 DematerializerSP dematerializer_sp = m_dematerializer_wp.lock();
1361 if (dematerializer_sp) {
1362 error.SetErrorToGenericError();
1363 error.SetErrorString("Couldn't materialize: already materialized");
1366 DematerializerSP ret(
1367 new Dematerializer(*this, frame_sp, map, process_address));
1370 error.SetErrorToGenericError();
1371 error.SetErrorString("Couldn't materialize: target doesn't exist");
1374 for (EntityUP &entity_up : m_entities) {
1375 entity_up->Materialize(frame_sp, map, process_address, error);
1377 if (!error.Success())
1378 return DematerializerSP();
1382 lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)) {
1384 "Materializer::Materialize (frame_sp = %p, process_address = 0x%" PRIx64
1386 static_cast<void *>(frame_sp.get()), process_address);
1387 for (EntityUP &entity_up : m_entities)
1388 entity_up->DumpToLog(map, process_address, log);
1391 m_dematerializer_wp = ret;
1396 void Materializer::Dematerializer::Dematerialize(Status &error,
1397 lldb::addr_t frame_bottom,
1398 lldb::addr_t frame_top) {
1399 lldb::StackFrameSP frame_sp;
1401 lldb::ThreadSP thread_sp = m_thread_wp.lock();
1403 frame_sp = thread_sp->GetFrameWithStackID(m_stack_id);
1405 ExecutionContextScope *exe_scope = m_map->GetBestExecutionContextScope();
1408 error.SetErrorToGenericError();
1409 error.SetErrorString("Couldn't dematerialize: invalid dematerializer");
1413 error.SetErrorToGenericError();
1414 error.SetErrorString("Couldn't dematerialize: target is gone");
1417 lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)) {
1418 log->Printf("Materializer::Dematerialize (frame_sp = %p, process_address "
1419 "= 0x%" PRIx64 ") about to dematerialize:",
1420 static_cast<void *>(frame_sp.get()), m_process_address);
1421 for (EntityUP &entity_up : m_materializer->m_entities)
1422 entity_up->DumpToLog(*m_map, m_process_address, log);
1425 for (EntityUP &entity_up : m_materializer->m_entities) {
1426 entity_up->Dematerialize(frame_sp, *m_map, m_process_address, frame_top,
1427 frame_bottom, error);
1429 if (!error.Success())
1437 void Materializer::Dematerializer::Wipe() {
1441 for (EntityUP &entity_up : m_materializer->m_entities) {
1442 entity_up->Wipe(*m_map, m_process_address);
1445 m_materializer = nullptr;
1447 m_process_address = LLDB_INVALID_ADDRESS;
1450 Materializer::PersistentVariableDelegate::~PersistentVariableDelegate() =