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