• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 &register_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 &register_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