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
AddStructMember(Entity & entity)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:
EntityPersistentVariable(lldb::ExpressionVariableSP & persistent_variable_sp,Materializer::PersistentVariableDelegate * delegate)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
MakeAllocation(IRMemoryMap & map,Status & err)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
DestroyAllocation(IRMemoryMap & map,Status & err)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
Materialize(lldb::StackFrameSP & frame_sp,IRMemoryMap & map,lldb::addr_t process_address,Status & err)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
Dematerialize(lldb::StackFrameSP & frame_sp,IRMemoryMap & map,lldb::addr_t process_address,lldb::addr_t frame_top,lldb::addr_t frame_bottom,Status & err)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
DumpToLog(IRMemoryMap & map,lldb::addr_t process_address,Log * log)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
Wipe(IRMemoryMap & map,lldb::addr_t process_address)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
AddPersistentVariable(lldb::ExpressionVariableSP & persistent_variable_sp,PersistentVariableDelegate * delegate,Status & err)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
EntityVariableBase()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
Materialize(lldb::StackFrameSP & frame_sp,IRMemoryMap & map,lldb::addr_t process_address,Status & err)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
Dematerialize(lldb::StackFrameSP & frame_sp,IRMemoryMap & map,lldb::addr_t process_address,lldb::addr_t frame_top,lldb::addr_t frame_bottom,Status & err)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
DumpToLog(IRMemoryMap & map,lldb::addr_t process_address,Log * log)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
Wipe(IRMemoryMap & map,lldb::addr_t process_address)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:
EntityVariable(lldb::VariableSP & variable_sp)806 EntityVariable(lldb::VariableSP &variable_sp) : m_variable_sp(variable_sp) {
807 m_is_reference =
808 m_variable_sp->GetType()->GetForwardCompilerType().IsReferenceType();
809 }
810
GetName() const811 ConstString GetName() const override { return m_variable_sp->GetName(); }
812
SetupValueObject(ExecutionContextScope * scope)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>
GetByteSize(ExecutionContextScope * scope) const819 GetByteSize(ExecutionContextScope *scope) const override {
820 return m_variable_sp->GetType()->GetByteSize(scope);
821 }
822
LocationExpressionIsValid() const823 bool LocationExpressionIsValid() const override {
824 return m_variable_sp->LocationExpressionList().IsValid();
825 }
826
827 llvm::Optional<size_t>
GetTypeBitAlign(ExecutionContextScope * scope) const828 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:
EntityValueObject(ConstString name,ValueObjectProviderTy provider)844 EntityValueObject(ConstString name, ValueObjectProviderTy provider)
845 : m_name(name), m_valobj_provider(std::move(provider)) {
846 assert(m_valobj_provider);
847 }
848
GetName() const849 ConstString GetName() const override { return m_name; }
850
SetupValueObject(ExecutionContextScope * scope)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>
GetByteSize(ExecutionContextScope * scope) const862 GetByteSize(ExecutionContextScope *scope) const override {
863 if (m_valobj_sp)
864 return m_valobj_sp->GetCompilerType().GetByteSize(scope);
865
866 return {};
867 }
868
LocationExpressionIsValid() const869 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>
GetTypeBitAlign(ExecutionContextScope * scope) const877 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
AddVariable(lldb::VariableSP & variable_sp,Status & err)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
AddValueObject(ConstString name,ValueObjectProviderTy valobj_provider,Status & err)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:
EntityResultVariable(const CompilerType & type,bool is_program_reference,bool keep_in_memory,Materializer::PersistentVariableDelegate * delegate)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
Materialize(lldb::StackFrameSP & frame_sp,IRMemoryMap & map,lldb::addr_t process_address,Status & err)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
Dematerialize(lldb::StackFrameSP & frame_sp,IRMemoryMap & map,lldb::addr_t process_address,lldb::addr_t frame_top,lldb::addr_t frame_bottom,Status & err)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
DumpToLog(IRMemoryMap & map,lldb::addr_t process_address,Log * log)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
Wipe(IRMemoryMap & map,lldb::addr_t process_address)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
AddResultVariable(const CompilerType & type,bool is_program_reference,bool keep_in_memory,PersistentVariableDelegate * delegate,Status & err)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:
EntitySymbol(const Symbol & symbol)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
Materialize(lldb::StackFrameSP & frame_sp,IRMemoryMap & map,lldb::addr_t process_address,Status & err)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
Dematerialize(lldb::StackFrameSP & frame_sp,IRMemoryMap & map,lldb::addr_t process_address,lldb::addr_t frame_top,lldb::addr_t frame_bottom,Status & err)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
DumpToLog(IRMemoryMap & map,lldb::addr_t process_address,Log * log)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
Wipe(IRMemoryMap & map,lldb::addr_t process_address)1296 void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {}
1297
1298 private:
1299 Symbol m_symbol;
1300 };
1301
AddSymbol(const Symbol & symbol_sp,Status & err)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:
EntityRegister(const RegisterInfo & register_info)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
Materialize(lldb::StackFrameSP & frame_sp,IRMemoryMap & map,lldb::addr_t process_address,Status & err)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
Dematerialize(lldb::StackFrameSP & frame_sp,IRMemoryMap & map,lldb::addr_t process_address,lldb::addr_t frame_top,lldb::addr_t frame_bottom,Status & err)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
DumpToLog(IRMemoryMap & map,lldb::addr_t process_address,Log * log)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
Wipe(IRMemoryMap & map,lldb::addr_t process_address)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
AddRegister(const RegisterInfo & register_info,Status & err)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
~Materializer()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
Materialize(lldb::StackFrameSP & frame_sp,IRMemoryMap & map,lldb::addr_t process_address,Status & error)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
Dematerialize(Status & error,lldb::addr_t frame_bottom,lldb::addr_t frame_top)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
Wipe()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