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