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.SetErrorStringWithFormat("can't get size of type \"%s\"",
798                                      m_type.GetTypeName().AsCString());
799         return;
800       }
801 
802       llvm::Optional<size_t> opt_bit_align = m_type.GetTypeBitAlign(exe_scope);
803       if (!opt_bit_align) {
804         err.SetErrorStringWithFormat("can't get the alignment of type  \"%s\"",
805                                      m_type.GetTypeName().AsCString());
806         return;
807       }
808 
809       size_t byte_align = (*opt_bit_align + 7) / 8;
810 
811       Status alloc_error;
812       const bool zero_memory = true;
813 
814       m_temporary_allocation = map.Malloc(
815           *byte_size, byte_align,
816           lldb::ePermissionsReadable | lldb::ePermissionsWritable,
817           IRMemoryMap::eAllocationPolicyMirror, zero_memory, alloc_error);
818       m_temporary_allocation_size = *byte_size;
819 
820       if (!alloc_error.Success()) {
821         err.SetErrorStringWithFormat(
822             "couldn't allocate a temporary region for the result: %s",
823             alloc_error.AsCString());
824         return;
825       }
826 
827       Status pointer_write_error;
828 
829       map.WritePointerToMemory(load_addr, m_temporary_allocation,
830                                pointer_write_error);
831 
832       if (!pointer_write_error.Success()) {
833         err.SetErrorStringWithFormat("couldn't write the address of the "
834                                      "temporary region for the result: %s",
835                                      pointer_write_error.AsCString());
836       }
837     }
838   }
839 
Dematerialize(lldb::StackFrameSP & frame_sp,IRMemoryMap & map,lldb::addr_t process_address,lldb::addr_t frame_top,lldb::addr_t frame_bottom,Status & err)840   void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
841                      lldb::addr_t process_address, lldb::addr_t frame_top,
842                      lldb::addr_t frame_bottom, Status &err) override {
843     err.Clear();
844 
845     ExecutionContextScope *exe_scope = frame_sp.get();
846     if (!exe_scope)
847       exe_scope = map.GetBestExecutionContextScope();
848 
849     if (!exe_scope) {
850       err.SetErrorString("Couldn't dematerialize a result variable: invalid "
851                          "execution context scope");
852       return;
853     }
854 
855     lldb::addr_t address;
856     Status read_error;
857     const lldb::addr_t load_addr = process_address + m_offset;
858 
859     map.ReadPointerFromMemory(&address, load_addr, read_error);
860 
861     if (!read_error.Success()) {
862       err.SetErrorString("Couldn't dematerialize a result variable: couldn't "
863                          "read its address");
864       return;
865     }
866 
867     lldb::TargetSP target_sp = exe_scope->CalculateTarget();
868 
869     if (!target_sp) {
870       err.SetErrorString("Couldn't dematerialize a result variable: no target");
871       return;
872     }
873 
874     auto type_system_or_err =
875         target_sp->GetScratchTypeSystemForLanguage(m_type.GetMinimumLanguage());
876 
877     if (auto error = type_system_or_err.takeError()) {
878       err.SetErrorStringWithFormat("Couldn't dematerialize a result variable: "
879                                    "couldn't get the corresponding type "
880                                    "system: %s",
881                                    llvm::toString(std::move(error)).c_str());
882       return;
883     }
884     PersistentExpressionState *persistent_state =
885         type_system_or_err->GetPersistentExpressionState();
886 
887     if (!persistent_state) {
888       err.SetErrorString("Couldn't dematerialize a result variable: "
889                          "corresponding type system doesn't handle persistent "
890                          "variables");
891       return;
892     }
893 
894     ConstString name = m_delegate
895                            ? m_delegate->GetName()
896                            : persistent_state->GetNextPersistentVariableName();
897 
898     lldb::ExpressionVariableSP ret = persistent_state->CreatePersistentVariable(
899         exe_scope, name, m_type, map.GetByteOrder(), map.GetAddressByteSize());
900 
901     if (!ret) {
902       err.SetErrorStringWithFormat("couldn't dematerialize a result variable: "
903                                    "failed to make persistent variable %s",
904                                    name.AsCString());
905       return;
906     }
907 
908     lldb::ProcessSP process_sp =
909         map.GetBestExecutionContextScope()->CalculateProcess();
910 
911     if (m_delegate) {
912       m_delegate->DidDematerialize(ret);
913     }
914 
915     bool can_persist =
916         (m_is_program_reference && process_sp && process_sp->CanJIT() &&
917          !(address >= frame_bottom && address < frame_top));
918 
919     if (can_persist && m_keep_in_memory) {
920       ret->m_live_sp = ValueObjectConstResult::Create(exe_scope, m_type, name,
921                                                       address, eAddressTypeLoad,
922                                                       map.GetAddressByteSize());
923     }
924 
925     ret->ValueUpdated();
926 
927     const size_t pvar_byte_size = ret->GetByteSize().getValueOr(0);
928     uint8_t *pvar_data = ret->GetValueBytes();
929 
930     map.ReadMemory(pvar_data, address, pvar_byte_size, read_error);
931 
932     if (!read_error.Success()) {
933       err.SetErrorString(
934           "Couldn't dematerialize a result variable: couldn't read its memory");
935       return;
936     }
937 
938     if (!can_persist || !m_keep_in_memory) {
939       ret->m_flags |= ExpressionVariable::EVNeedsAllocation;
940 
941       if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
942         Status free_error;
943         map.Free(m_temporary_allocation, free_error);
944       }
945     } else {
946       ret->m_flags |= ExpressionVariable::EVIsLLDBAllocated;
947     }
948 
949     m_temporary_allocation = LLDB_INVALID_ADDRESS;
950     m_temporary_allocation_size = 0;
951   }
952 
DumpToLog(IRMemoryMap & map,lldb::addr_t process_address,Log * log)953   void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
954                  Log *log) override {
955     StreamString dump_stream;
956 
957     const lldb::addr_t load_addr = process_address + m_offset;
958 
959     dump_stream.Printf("0x%" PRIx64 ": EntityResultVariable\n", load_addr);
960 
961     Status err;
962 
963     lldb::addr_t ptr = LLDB_INVALID_ADDRESS;
964 
965     {
966       dump_stream.Printf("Pointer:\n");
967 
968       DataBufferHeap data(m_size, 0);
969 
970       map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
971 
972       if (!err.Success()) {
973         dump_stream.Printf("  <could not be read>\n");
974       } else {
975         DataExtractor extractor(data.GetBytes(), data.GetByteSize(),
976                                 map.GetByteOrder(), map.GetAddressByteSize());
977 
978         DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
979                      load_addr);
980 
981         lldb::offset_t offset;
982 
983         ptr = extractor.GetAddress(&offset);
984 
985         dump_stream.PutChar('\n');
986       }
987     }
988 
989     if (m_temporary_allocation == LLDB_INVALID_ADDRESS) {
990       dump_stream.Printf("Points to process memory:\n");
991     } else {
992       dump_stream.Printf("Temporary allocation:\n");
993     }
994 
995     if (ptr == LLDB_INVALID_ADDRESS) {
996       dump_stream.Printf("  <could not be be found>\n");
997     } else {
998       DataBufferHeap data(m_temporary_allocation_size, 0);
999 
1000       map.ReadMemory(data.GetBytes(), m_temporary_allocation,
1001                      m_temporary_allocation_size, err);
1002 
1003       if (!err.Success()) {
1004         dump_stream.Printf("  <could not be read>\n");
1005       } else {
1006         DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
1007                      load_addr);
1008 
1009         dump_stream.PutChar('\n');
1010       }
1011     }
1012 
1013     log->PutString(dump_stream.GetString());
1014   }
1015 
Wipe(IRMemoryMap & map,lldb::addr_t process_address)1016   void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {
1017     if (!m_keep_in_memory && m_temporary_allocation != LLDB_INVALID_ADDRESS) {
1018       Status free_error;
1019 
1020       map.Free(m_temporary_allocation, free_error);
1021     }
1022 
1023     m_temporary_allocation = LLDB_INVALID_ADDRESS;
1024     m_temporary_allocation_size = 0;
1025   }
1026 
1027 private:
1028   CompilerType m_type;
1029   bool m_is_program_reference;
1030   bool m_keep_in_memory;
1031 
1032   lldb::addr_t m_temporary_allocation;
1033   size_t m_temporary_allocation_size;
1034   Materializer::PersistentVariableDelegate *m_delegate;
1035 };
1036 
AddResultVariable(const CompilerType & type,bool is_program_reference,bool keep_in_memory,PersistentVariableDelegate * delegate,Status & err)1037 uint32_t Materializer::AddResultVariable(const CompilerType &type,
1038                                          bool is_program_reference,
1039                                          bool keep_in_memory,
1040                                          PersistentVariableDelegate *delegate,
1041                                          Status &err) {
1042   EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
1043   *iter = std::make_unique<EntityResultVariable>(type, is_program_reference,
1044                                                  keep_in_memory, delegate);
1045   uint32_t ret = AddStructMember(**iter);
1046   (*iter)->SetOffset(ret);
1047   return ret;
1048 }
1049 
1050 class EntitySymbol : public Materializer::Entity {
1051 public:
EntitySymbol(const Symbol & symbol)1052   EntitySymbol(const Symbol &symbol) : Entity(), m_symbol(symbol) {
1053     // Hard-coding to maximum size of a symbol
1054     m_size = 8;
1055     m_alignment = 8;
1056   }
1057 
Materialize(lldb::StackFrameSP & frame_sp,IRMemoryMap & map,lldb::addr_t process_address,Status & err)1058   void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1059                    lldb::addr_t process_address, Status &err) override {
1060     Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
1061 
1062     const lldb::addr_t load_addr = process_address + m_offset;
1063 
1064     if (log) {
1065       LLDB_LOGF(log,
1066                 "EntitySymbol::Materialize [address = 0x%" PRIx64
1067                 ", m_symbol = %s]",
1068                 (uint64_t)load_addr, m_symbol.GetName().AsCString());
1069     }
1070 
1071     const Address sym_address = m_symbol.GetAddress();
1072 
1073     ExecutionContextScope *exe_scope = frame_sp.get();
1074     if (!exe_scope)
1075       exe_scope = map.GetBestExecutionContextScope();
1076 
1077     lldb::TargetSP target_sp;
1078 
1079     if (exe_scope)
1080       target_sp = map.GetBestExecutionContextScope()->CalculateTarget();
1081 
1082     if (!target_sp) {
1083       err.SetErrorStringWithFormat(
1084           "couldn't resolve symbol %s because there is no target",
1085           m_symbol.GetName().AsCString());
1086       return;
1087     }
1088 
1089     lldb::addr_t resolved_address = sym_address.GetLoadAddress(target_sp.get());
1090 
1091     if (resolved_address == LLDB_INVALID_ADDRESS)
1092       resolved_address = sym_address.GetFileAddress();
1093 
1094     Status pointer_write_error;
1095 
1096     map.WritePointerToMemory(load_addr, resolved_address, pointer_write_error);
1097 
1098     if (!pointer_write_error.Success()) {
1099       err.SetErrorStringWithFormat(
1100           "couldn't write the address of symbol %s: %s",
1101           m_symbol.GetName().AsCString(), pointer_write_error.AsCString());
1102       return;
1103     }
1104   }
1105 
Dematerialize(lldb::StackFrameSP & frame_sp,IRMemoryMap & map,lldb::addr_t process_address,lldb::addr_t frame_top,lldb::addr_t frame_bottom,Status & err)1106   void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1107                      lldb::addr_t process_address, lldb::addr_t frame_top,
1108                      lldb::addr_t frame_bottom, Status &err) override {
1109     Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
1110 
1111     const lldb::addr_t load_addr = process_address + m_offset;
1112 
1113     if (log) {
1114       LLDB_LOGF(log,
1115                 "EntitySymbol::Dematerialize [address = 0x%" PRIx64
1116                 ", m_symbol = %s]",
1117                 (uint64_t)load_addr, m_symbol.GetName().AsCString());
1118     }
1119 
1120     // no work needs to be done
1121   }
1122 
DumpToLog(IRMemoryMap & map,lldb::addr_t process_address,Log * log)1123   void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
1124                  Log *log) override {
1125     StreamString dump_stream;
1126 
1127     Status err;
1128 
1129     const lldb::addr_t load_addr = process_address + m_offset;
1130 
1131     dump_stream.Printf("0x%" PRIx64 ": EntitySymbol (%s)\n", load_addr,
1132                        m_symbol.GetName().AsCString());
1133 
1134     {
1135       dump_stream.Printf("Pointer:\n");
1136 
1137       DataBufferHeap data(m_size, 0);
1138 
1139       map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
1140 
1141       if (!err.Success()) {
1142         dump_stream.Printf("  <could not be read>\n");
1143       } else {
1144         DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
1145                      load_addr);
1146 
1147         dump_stream.PutChar('\n');
1148       }
1149     }
1150 
1151     log->PutString(dump_stream.GetString());
1152   }
1153 
Wipe(IRMemoryMap & map,lldb::addr_t process_address)1154   void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {}
1155 
1156 private:
1157   Symbol m_symbol;
1158 };
1159 
AddSymbol(const Symbol & symbol_sp,Status & err)1160 uint32_t Materializer::AddSymbol(const Symbol &symbol_sp, Status &err) {
1161   EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
1162   *iter = std::make_unique<EntitySymbol>(symbol_sp);
1163   uint32_t ret = AddStructMember(**iter);
1164   (*iter)->SetOffset(ret);
1165   return ret;
1166 }
1167 
1168 class EntityRegister : public Materializer::Entity {
1169 public:
EntityRegister(const RegisterInfo & register_info)1170   EntityRegister(const RegisterInfo &register_info)
1171       : Entity(), m_register_info(register_info) {
1172     // Hard-coding alignment conservatively
1173     m_size = m_register_info.byte_size;
1174     m_alignment = m_register_info.byte_size;
1175   }
1176 
Materialize(lldb::StackFrameSP & frame_sp,IRMemoryMap & map,lldb::addr_t process_address,Status & err)1177   void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1178                    lldb::addr_t process_address, Status &err) override {
1179     Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
1180 
1181     const lldb::addr_t load_addr = process_address + m_offset;
1182 
1183     if (log) {
1184       LLDB_LOGF(log,
1185                 "EntityRegister::Materialize [address = 0x%" PRIx64
1186                 ", m_register_info = %s]",
1187                 (uint64_t)load_addr, m_register_info.name);
1188     }
1189 
1190     RegisterValue reg_value;
1191 
1192     if (!frame_sp.get()) {
1193       err.SetErrorStringWithFormat(
1194           "couldn't materialize register %s without a stack frame",
1195           m_register_info.name);
1196       return;
1197     }
1198 
1199     lldb::RegisterContextSP reg_context_sp = frame_sp->GetRegisterContext();
1200 
1201     if (!reg_context_sp->ReadRegister(&m_register_info, reg_value)) {
1202       err.SetErrorStringWithFormat("couldn't read the value of register %s",
1203                                    m_register_info.name);
1204       return;
1205     }
1206 
1207     DataExtractor register_data;
1208 
1209     if (!reg_value.GetData(register_data)) {
1210       err.SetErrorStringWithFormat("couldn't get the data for register %s",
1211                                    m_register_info.name);
1212       return;
1213     }
1214 
1215     if (register_data.GetByteSize() != m_register_info.byte_size) {
1216       err.SetErrorStringWithFormat(
1217           "data for register %s had size %llu but we expected %llu",
1218           m_register_info.name, (unsigned long long)register_data.GetByteSize(),
1219           (unsigned long long)m_register_info.byte_size);
1220       return;
1221     }
1222 
1223     m_register_contents = std::make_shared<DataBufferHeap>(
1224         register_data.GetDataStart(), register_data.GetByteSize());
1225 
1226     Status write_error;
1227 
1228     map.WriteMemory(load_addr, register_data.GetDataStart(),
1229                     register_data.GetByteSize(), write_error);
1230 
1231     if (!write_error.Success()) {
1232       err.SetErrorStringWithFormat(
1233           "couldn't write the contents of register %s: %s",
1234           m_register_info.name, write_error.AsCString());
1235       return;
1236     }
1237   }
1238 
Dematerialize(lldb::StackFrameSP & frame_sp,IRMemoryMap & map,lldb::addr_t process_address,lldb::addr_t frame_top,lldb::addr_t frame_bottom,Status & err)1239   void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1240                      lldb::addr_t process_address, lldb::addr_t frame_top,
1241                      lldb::addr_t frame_bottom, Status &err) override {
1242     Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
1243 
1244     const lldb::addr_t load_addr = process_address + m_offset;
1245 
1246     if (log) {
1247       LLDB_LOGF(log,
1248                 "EntityRegister::Dematerialize [address = 0x%" PRIx64
1249                 ", m_register_info = %s]",
1250                 (uint64_t)load_addr, m_register_info.name);
1251     }
1252 
1253     Status extract_error;
1254 
1255     DataExtractor register_data;
1256 
1257     if (!frame_sp.get()) {
1258       err.SetErrorStringWithFormat(
1259           "couldn't dematerialize register %s without a stack frame",
1260           m_register_info.name);
1261       return;
1262     }
1263 
1264     lldb::RegisterContextSP reg_context_sp = frame_sp->GetRegisterContext();
1265 
1266     map.GetMemoryData(register_data, load_addr, m_register_info.byte_size,
1267                       extract_error);
1268 
1269     if (!extract_error.Success()) {
1270       err.SetErrorStringWithFormat("couldn't get the data for register %s: %s",
1271                                    m_register_info.name,
1272                                    extract_error.AsCString());
1273       return;
1274     }
1275 
1276     if (!memcmp(register_data.GetDataStart(), m_register_contents->GetBytes(),
1277                 register_data.GetByteSize())) {
1278       // No write required, and in particular we avoid errors if the register
1279       // wasn't writable
1280 
1281       m_register_contents.reset();
1282       return;
1283     }
1284 
1285     m_register_contents.reset();
1286 
1287     RegisterValue register_value(register_data.GetData(),
1288                                  register_data.GetByteOrder());
1289 
1290     if (!reg_context_sp->WriteRegister(&m_register_info, register_value)) {
1291       err.SetErrorStringWithFormat("couldn't write the value of register %s",
1292                                    m_register_info.name);
1293       return;
1294     }
1295   }
1296 
DumpToLog(IRMemoryMap & map,lldb::addr_t process_address,Log * log)1297   void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
1298                  Log *log) override {
1299     StreamString dump_stream;
1300 
1301     Status err;
1302 
1303     const lldb::addr_t load_addr = process_address + m_offset;
1304 
1305     dump_stream.Printf("0x%" PRIx64 ": EntityRegister (%s)\n", load_addr,
1306                        m_register_info.name);
1307 
1308     {
1309       dump_stream.Printf("Value:\n");
1310 
1311       DataBufferHeap data(m_size, 0);
1312 
1313       map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
1314 
1315       if (!err.Success()) {
1316         dump_stream.Printf("  <could not be read>\n");
1317       } else {
1318         DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
1319                      load_addr);
1320 
1321         dump_stream.PutChar('\n');
1322       }
1323     }
1324 
1325     log->PutString(dump_stream.GetString());
1326   }
1327 
Wipe(IRMemoryMap & map,lldb::addr_t process_address)1328   void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {}
1329 
1330 private:
1331   RegisterInfo m_register_info;
1332   lldb::DataBufferSP m_register_contents;
1333 };
1334 
AddRegister(const RegisterInfo & register_info,Status & err)1335 uint32_t Materializer::AddRegister(const RegisterInfo &register_info,
1336                                    Status &err) {
1337   EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
1338   *iter = std::make_unique<EntityRegister>(register_info);
1339   uint32_t ret = AddStructMember(**iter);
1340   (*iter)->SetOffset(ret);
1341   return ret;
1342 }
1343 
~Materializer()1344 Materializer::~Materializer() {
1345   DematerializerSP dematerializer_sp = m_dematerializer_wp.lock();
1346 
1347   if (dematerializer_sp)
1348     dematerializer_sp->Wipe();
1349 }
1350 
1351 Materializer::DematerializerSP
Materialize(lldb::StackFrameSP & frame_sp,IRMemoryMap & map,lldb::addr_t process_address,Status & error)1352 Materializer::Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1353                           lldb::addr_t process_address, Status &error) {
1354   ExecutionContextScope *exe_scope = frame_sp.get();
1355   if (!exe_scope)
1356     exe_scope = map.GetBestExecutionContextScope();
1357 
1358   DematerializerSP dematerializer_sp = m_dematerializer_wp.lock();
1359 
1360   if (dematerializer_sp) {
1361     error.SetErrorToGenericError();
1362     error.SetErrorString("Couldn't materialize: already materialized");
1363   }
1364 
1365   DematerializerSP ret(
1366       new Dematerializer(*this, frame_sp, map, process_address));
1367 
1368   if (!exe_scope) {
1369     error.SetErrorToGenericError();
1370     error.SetErrorString("Couldn't materialize: target doesn't exist");
1371   }
1372 
1373   for (EntityUP &entity_up : m_entities) {
1374     entity_up->Materialize(frame_sp, map, process_address, error);
1375 
1376     if (!error.Success())
1377       return DematerializerSP();
1378   }
1379 
1380   if (Log *log =
1381           lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)) {
1382     LLDB_LOGF(
1383         log,
1384         "Materializer::Materialize (frame_sp = %p, process_address = 0x%" PRIx64
1385         ") materialized:",
1386         static_cast<void *>(frame_sp.get()), process_address);
1387     for (EntityUP &entity_up : m_entities)
1388       entity_up->DumpToLog(map, process_address, log);
1389   }
1390 
1391   m_dematerializer_wp = ret;
1392 
1393   return ret;
1394 }
1395 
Dematerialize(Status & error,lldb::addr_t frame_bottom,lldb::addr_t frame_top)1396 void Materializer::Dematerializer::Dematerialize(Status &error,
1397                                                  lldb::addr_t frame_bottom,
1398                                                  lldb::addr_t frame_top) {
1399   lldb::StackFrameSP frame_sp;
1400 
1401   lldb::ThreadSP thread_sp = m_thread_wp.lock();
1402   if (thread_sp)
1403     frame_sp = thread_sp->GetFrameWithStackID(m_stack_id);
1404 
1405   ExecutionContextScope *exe_scope = frame_sp.get();
1406   if (!exe_scope)
1407     exe_scope = m_map->GetBestExecutionContextScope();
1408 
1409   if (!IsValid()) {
1410     error.SetErrorToGenericError();
1411     error.SetErrorString("Couldn't dematerialize: invalid dematerializer");
1412   }
1413 
1414   if (!exe_scope) {
1415     error.SetErrorToGenericError();
1416     error.SetErrorString("Couldn't dematerialize: target is gone");
1417   } else {
1418     if (Log *log =
1419             lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)) {
1420       LLDB_LOGF(log,
1421                 "Materializer::Dematerialize (frame_sp = %p, process_address "
1422                 "= 0x%" PRIx64 ") about to dematerialize:",
1423                 static_cast<void *>(frame_sp.get()), m_process_address);
1424       for (EntityUP &entity_up : m_materializer->m_entities)
1425         entity_up->DumpToLog(*m_map, m_process_address, log);
1426     }
1427 
1428     for (EntityUP &entity_up : m_materializer->m_entities) {
1429       entity_up->Dematerialize(frame_sp, *m_map, m_process_address, frame_top,
1430                                frame_bottom, error);
1431 
1432       if (!error.Success())
1433         break;
1434     }
1435   }
1436 
1437   Wipe();
1438 }
1439 
Wipe()1440 void Materializer::Dematerializer::Wipe() {
1441   if (!IsValid())
1442     return;
1443 
1444   for (EntityUP &entity_up : m_materializer->m_entities) {
1445     entity_up->Wipe(*m_map, m_process_address);
1446   }
1447 
1448   m_materializer = nullptr;
1449   m_map = nullptr;
1450   m_process_address = LLDB_INVALID_ADDRESS;
1451 }
1452 
1453 Materializer::PersistentVariableDelegate::~PersistentVariableDelegate() =
1454     default;
1455