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