Materializer.cpp revision 276479
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 ") successfully", 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        Error valobj_error = valobj_sp->GetError();
447
448        if (valobj_error.Fail())
449        {
450            err.SetErrorStringWithFormat("couldn't get the value of variable %s: %s", m_variable_sp->GetName().AsCString(), valobj_error.AsCString());
451            return;
452        }
453
454        if (m_is_reference)
455        {
456            DataExtractor valobj_extractor;
457            Error extract_error;
458            valobj_sp->GetData(valobj_extractor, extract_error);
459
460            if (!extract_error.Success())
461            {
462                err.SetErrorStringWithFormat("couldn't read contents of reference variable %s: %s", m_variable_sp->GetName().AsCString(), extract_error.AsCString());
463                return;
464            }
465
466            lldb::offset_t offset = 0;
467            lldb::addr_t reference_addr = valobj_extractor.GetAddress(&offset);
468
469            Error write_error;
470            map.WritePointerToMemory(load_addr, reference_addr, write_error);
471
472            if (!write_error.Success())
473            {
474                err.SetErrorStringWithFormat("couldn't write the contents of reference variable %s to memory: %s", m_variable_sp->GetName().AsCString(), write_error.AsCString());
475                return;
476            }
477        }
478        else
479        {
480            AddressType address_type = eAddressTypeInvalid;
481            const bool scalar_is_load_address = false;
482            lldb::addr_t addr_of_valobj = valobj_sp->GetAddressOf(scalar_is_load_address, &address_type);
483            if (addr_of_valobj != LLDB_INVALID_ADDRESS)
484            {
485                Error write_error;
486                map.WritePointerToMemory(load_addr, addr_of_valobj, write_error);
487
488                if (!write_error.Success())
489                {
490                    err.SetErrorStringWithFormat("couldn't write the address of variable %s to memory: %s", m_variable_sp->GetName().AsCString(), write_error.AsCString());
491                    return;
492                }
493            }
494            else
495            {
496                DataExtractor data;
497                Error extract_error;
498                valobj_sp->GetData(data, extract_error);
499                if (!extract_error.Success())
500                {
501                    err.SetErrorStringWithFormat("couldn't get the value of %s: %s", m_variable_sp->GetName().AsCString(), extract_error.AsCString());
502                    return;
503                }
504
505                if (m_temporary_allocation != LLDB_INVALID_ADDRESS)
506                {
507                    err.SetErrorStringWithFormat("trying to create a temporary region for %s but one exists", m_variable_sp->GetName().AsCString());
508                    return;
509                }
510
511                if (data.GetByteSize() != m_variable_sp->GetType()->GetByteSize())
512                {
513                    if (data.GetByteSize() == 0 && m_variable_sp->LocationExpression().IsValid() == false)
514                    {
515                        err.SetErrorStringWithFormat("the variable '%s' has no location, it may have been optimized out", m_variable_sp->GetName().AsCString());
516                    }
517                    else
518                    {
519                        err.SetErrorStringWithFormat("size of variable %s (%" PRIu64 ") disagrees with the ValueObject's size (%" PRIu64 ")",
520                                                     m_variable_sp->GetName().AsCString(),
521                                                     m_variable_sp->GetType()->GetByteSize(),
522                                                     data.GetByteSize());
523                    }
524                    return;
525                }
526
527                size_t bit_align = m_variable_sp->GetType()->GetClangLayoutType().GetTypeBitAlign();
528                size_t byte_align = (bit_align + 7) / 8;
529
530                if (!byte_align)
531                    byte_align = 1;
532
533                Error alloc_error;
534
535                m_temporary_allocation = map.Malloc(data.GetByteSize(), byte_align, lldb::ePermissionsReadable | lldb::ePermissionsWritable, IRMemoryMap::eAllocationPolicyMirror, alloc_error);
536                m_temporary_allocation_size = data.GetByteSize();
537
538                m_original_data.reset(new DataBufferHeap(data.GetDataStart(), data.GetByteSize()));
539
540                if (!alloc_error.Success())
541                {
542                    err.SetErrorStringWithFormat("couldn't allocate a temporary region for %s: %s", m_variable_sp->GetName().AsCString(), alloc_error.AsCString());
543                    return;
544                }
545
546                Error write_error;
547
548                map.WriteMemory(m_temporary_allocation, data.GetDataStart(), data.GetByteSize(), write_error);
549
550                if (!write_error.Success())
551                {
552                    err.SetErrorStringWithFormat("couldn't write to the temporary region for %s: %s", m_variable_sp->GetName().AsCString(), write_error.AsCString());
553                    return;
554                }
555
556                Error pointer_write_error;
557
558                map.WritePointerToMemory(load_addr, m_temporary_allocation, pointer_write_error);
559
560                if (!pointer_write_error.Success())
561                {
562                    err.SetErrorStringWithFormat("couldn't write the address of the temporary region for %s: %s", m_variable_sp->GetName().AsCString(), pointer_write_error.AsCString());
563                }
564            }
565        }
566    }
567
568    void Dematerialize (lldb::StackFrameSP &frame_sp,
569                        IRMemoryMap &map,
570                        lldb::addr_t process_address,
571                        lldb::addr_t frame_top,
572                        lldb::addr_t frame_bottom,
573                        Error &err)
574    {
575        Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
576
577        const lldb::addr_t load_addr = process_address + m_offset;
578        if (log)
579        {
580            log->Printf("EntityVariable::Dematerialize [address = 0x%" PRIx64 ", m_variable_sp = %s]",
581                        (uint64_t)load_addr,
582                        m_variable_sp->GetName().AsCString());
583        }
584
585        if (m_temporary_allocation != LLDB_INVALID_ADDRESS)
586        {
587            ExecutionContextScope *scope = frame_sp.get();
588
589            if (!scope)
590                scope = map.GetBestExecutionContextScope();
591
592            lldb::ValueObjectSP valobj_sp = ValueObjectVariable::Create(scope, m_variable_sp);
593
594            if (!valobj_sp)
595            {
596                err.SetErrorStringWithFormat("couldn't get a value object for variable %s", m_variable_sp->GetName().AsCString());
597                return;
598            }
599
600            lldb_private::DataExtractor data;
601
602            Error extract_error;
603
604            map.GetMemoryData(data, m_temporary_allocation, valobj_sp->GetByteSize(), extract_error);
605
606            if (!extract_error.Success())
607            {
608                err.SetErrorStringWithFormat("couldn't get the data for variable %s", m_variable_sp->GetName().AsCString());
609                return;
610            }
611
612            bool actually_write = true;
613
614            if (m_original_data)
615            {
616                if ((data.GetByteSize() == m_original_data->GetByteSize()) &&
617                    !memcmp(m_original_data->GetBytes(), data.GetDataStart(), data.GetByteSize()))
618                {
619                    actually_write = false;
620                }
621            }
622
623            Error set_error;
624
625            if (actually_write)
626            {
627                valobj_sp->SetData(data, set_error);
628
629                if (!set_error.Success())
630                {
631                    err.SetErrorStringWithFormat("couldn't write the new contents of %s back into the variable", m_variable_sp->GetName().AsCString());
632                    return;
633                }
634            }
635
636            Error free_error;
637
638            map.Free(m_temporary_allocation, free_error);
639
640            if (!free_error.Success())
641            {
642                err.SetErrorStringWithFormat("couldn't free the temporary region for %s: %s", m_variable_sp->GetName().AsCString(), free_error.AsCString());
643                return;
644            }
645
646            m_original_data.reset();
647            m_temporary_allocation = LLDB_INVALID_ADDRESS;
648            m_temporary_allocation_size = 0;
649        }
650    }
651
652    void DumpToLog (IRMemoryMap &map, lldb::addr_t process_address, Log *log)
653    {
654        StreamString dump_stream;
655
656        const lldb::addr_t load_addr = process_address + m_offset;
657        dump_stream.Printf("0x%" PRIx64 ": EntityVariable\n", load_addr);
658
659        Error err;
660
661        lldb::addr_t ptr = LLDB_INVALID_ADDRESS;
662
663        {
664            dump_stream.Printf("Pointer:\n");
665
666            DataBufferHeap data (m_size, 0);
667
668            map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
669
670            if (!err.Success())
671            {
672                dump_stream.Printf("  <could not be read>\n");
673            }
674            else
675            {
676                DataExtractor extractor (data.GetBytes(), data.GetByteSize(), map.GetByteOrder(), map.GetAddressByteSize());
677
678                extractor.DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, load_addr);
679
680                lldb::offset_t offset;
681
682                ptr = extractor.GetPointer(&offset);
683
684                dump_stream.PutChar('\n');
685            }
686        }
687
688        if (m_temporary_allocation == LLDB_INVALID_ADDRESS)
689        {
690            dump_stream.Printf("Points to process memory:\n");
691        }
692        else
693        {
694            dump_stream.Printf("Temporary allocation:\n");
695        }
696
697        if (ptr == LLDB_INVALID_ADDRESS)
698        {
699            dump_stream.Printf("  <could not be be found>\n");
700        }
701        else
702        {
703            DataBufferHeap data (m_temporary_allocation_size, 0);
704
705            map.ReadMemory(data.GetBytes(), m_temporary_allocation, m_temporary_allocation_size, err);
706
707            if (!err.Success())
708            {
709                dump_stream.Printf("  <could not be read>\n");
710            }
711            else
712            {
713                DataExtractor extractor (data.GetBytes(), data.GetByteSize(), map.GetByteOrder(), map.GetAddressByteSize());
714
715                extractor.DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, load_addr);
716
717                dump_stream.PutChar('\n');
718            }
719        }
720
721        log->PutCString(dump_stream.GetData());
722    }
723
724    void Wipe (IRMemoryMap &map, lldb::addr_t process_address)
725    {
726        if (m_temporary_allocation != LLDB_INVALID_ADDRESS)
727        {
728            Error free_error;
729
730            map.Free(m_temporary_allocation, free_error);
731
732            m_temporary_allocation = LLDB_INVALID_ADDRESS;
733            m_temporary_allocation_size = 0;
734        }
735
736    }
737private:
738    lldb::VariableSP    m_variable_sp;
739    bool                m_is_reference;
740    lldb::addr_t        m_temporary_allocation;
741    size_t              m_temporary_allocation_size;
742    lldb::DataBufferSP  m_original_data;
743};
744
745uint32_t
746Materializer::AddVariable (lldb::VariableSP &variable_sp, Error &err)
747{
748    EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
749    iter->reset (new EntityVariable (variable_sp));
750    uint32_t ret = AddStructMember(**iter);
751    (*iter)->SetOffset(ret);
752    return ret;
753}
754
755class EntityResultVariable : public Materializer::Entity
756{
757public:
758    EntityResultVariable (const TypeFromUser &type, bool is_program_reference, bool keep_in_memory) :
759        Entity(),
760        m_type(type),
761        m_is_program_reference(is_program_reference),
762        m_keep_in_memory(keep_in_memory),
763        m_temporary_allocation(LLDB_INVALID_ADDRESS),
764        m_temporary_allocation_size(0)
765    {
766        // Hard-coding to maximum size of a pointer since all results are materialized by reference
767        m_size = 8;
768        m_alignment = 8;
769    }
770
771    void Materialize (lldb::StackFrameSP &frame_sp, IRMemoryMap &map, lldb::addr_t process_address, Error &err)
772    {
773        if (!m_is_program_reference)
774        {
775            if (m_temporary_allocation != LLDB_INVALID_ADDRESS)
776            {
777                err.SetErrorString("Trying to create a temporary region for the result but one exists");
778                return;
779            }
780
781            const lldb::addr_t load_addr = process_address + m_offset;
782
783            size_t byte_size = m_type.GetByteSize();
784            size_t bit_align = m_type.GetTypeBitAlign();
785            size_t byte_align = (bit_align + 7) / 8;
786
787            if (!byte_align)
788                byte_align = 1;
789
790            Error alloc_error;
791
792            m_temporary_allocation = map.Malloc(byte_size, byte_align, lldb::ePermissionsReadable | lldb::ePermissionsWritable, IRMemoryMap::eAllocationPolicyMirror, alloc_error);
793            m_temporary_allocation_size = byte_size;
794
795            if (!alloc_error.Success())
796            {
797                err.SetErrorStringWithFormat("couldn't allocate a temporary region for the result: %s", alloc_error.AsCString());
798                return;
799            }
800
801            Error pointer_write_error;
802
803            map.WritePointerToMemory(load_addr, m_temporary_allocation, pointer_write_error);
804
805            if (!pointer_write_error.Success())
806            {
807                err.SetErrorStringWithFormat("couldn't write the address of the temporary region for the result: %s", pointer_write_error.AsCString());
808            }
809        }
810    }
811
812    void Dematerialize (lldb::StackFrameSP &frame_sp,
813                        IRMemoryMap &map,
814                        lldb::addr_t process_address,
815                        lldb::addr_t frame_top,
816                        lldb::addr_t frame_bottom,
817                        Error &err)
818    {
819        err.SetErrorString("Tried to detmaterialize a result variable with the normal Dematerialize method");
820    }
821
822    void Dematerialize (lldb::ClangExpressionVariableSP &result_variable_sp,
823                        lldb::StackFrameSP &frame_sp,
824                        IRMemoryMap &map,
825                        lldb::addr_t process_address,
826                        lldb::addr_t frame_top,
827                        lldb::addr_t frame_bottom,
828                        Error &err)
829    {
830        err.Clear();
831
832        ExecutionContextScope *exe_scope = map.GetBestExecutionContextScope();
833
834        if (!exe_scope)
835        {
836            err.SetErrorString("Couldn't dematerialize a result variable: invalid execution context scope");
837            return;
838        }
839
840        lldb::addr_t address;
841        Error read_error;
842        const lldb::addr_t load_addr = process_address + m_offset;
843
844        map.ReadPointerFromMemory (&address, load_addr, read_error);
845
846        if (!read_error.Success())
847        {
848            err.SetErrorString("Couldn't dematerialize a result variable: couldn't read its address");
849            return;
850        }
851
852        lldb::TargetSP target_sp = exe_scope->CalculateTarget();
853
854        if (!target_sp)
855        {
856            err.SetErrorString("Couldn't dematerialize a result variable: no target");
857            return;
858        }
859
860        ConstString name = target_sp->GetPersistentVariables().GetNextPersistentVariableName();
861
862        lldb::ClangExpressionVariableSP ret;
863
864        ret = target_sp->GetPersistentVariables().CreateVariable(exe_scope,
865                                                                 name,
866                                                                 m_type,
867                                                                 map.GetByteOrder(),
868                                                                 map.GetAddressByteSize());
869
870        if (!ret)
871        {
872            err.SetErrorStringWithFormat("couldn't dematerialize a result variable: failed to make persistent variable %s", name.AsCString());
873            return;
874        }
875
876        lldb::ProcessSP process_sp = map.GetBestExecutionContextScope()->CalculateProcess();
877
878        bool can_persist = (m_is_program_reference && process_sp && process_sp->CanJIT() && !(address >= frame_bottom && address < frame_top));
879
880        if (can_persist && m_keep_in_memory)
881        {
882            ret->m_live_sp = ValueObjectConstResult::Create(exe_scope,
883                                                            m_type,
884                                                            name,
885                                                            address,
886                                                            eAddressTypeLoad,
887                                                            map.GetAddressByteSize());
888        }
889
890        ret->ValueUpdated();
891
892        const size_t pvar_byte_size = ret->GetByteSize();
893        uint8_t *pvar_data = ret->GetValueBytes();
894
895        map.ReadMemory(pvar_data, address, pvar_byte_size, read_error);
896
897        if (!read_error.Success())
898        {
899            err.SetErrorString("Couldn't dematerialize a result variable: couldn't read its memory");
900            return;
901        }
902
903        result_variable_sp = ret;
904
905        if (!can_persist || !m_keep_in_memory)
906        {
907            ret->m_flags |= ClangExpressionVariable::EVNeedsAllocation;
908
909            if (m_temporary_allocation != LLDB_INVALID_ADDRESS)
910            {
911                Error free_error;
912                map.Free(m_temporary_allocation, free_error);
913            }
914        }
915        else
916        {
917            ret->m_flags |= ClangExpressionVariable::EVIsLLDBAllocated;
918        }
919
920        m_temporary_allocation = LLDB_INVALID_ADDRESS;
921        m_temporary_allocation_size = 0;
922    }
923
924    void DumpToLog (IRMemoryMap &map, lldb::addr_t process_address, Log *log)
925    {
926        StreamString dump_stream;
927
928        const lldb::addr_t load_addr = process_address + m_offset;
929
930        dump_stream.Printf("0x%" PRIx64 ": EntityResultVariable\n", load_addr);
931
932        Error err;
933
934        lldb::addr_t ptr = LLDB_INVALID_ADDRESS;
935
936        {
937            dump_stream.Printf("Pointer:\n");
938
939            DataBufferHeap data (m_size, 0);
940
941            map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
942
943            if (!err.Success())
944            {
945                dump_stream.Printf("  <could not be read>\n");
946            }
947            else
948            {
949                DataExtractor extractor (data.GetBytes(), data.GetByteSize(), map.GetByteOrder(), map.GetAddressByteSize());
950
951                extractor.DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, load_addr);
952
953                lldb::offset_t offset;
954
955                ptr = extractor.GetPointer(&offset);
956
957                dump_stream.PutChar('\n');
958            }
959        }
960
961        if (m_temporary_allocation == LLDB_INVALID_ADDRESS)
962        {
963            dump_stream.Printf("Points to process memory:\n");
964        }
965        else
966        {
967            dump_stream.Printf("Temporary allocation:\n");
968        }
969
970        if (ptr == LLDB_INVALID_ADDRESS)
971        {
972            dump_stream.Printf("  <could not be be found>\n");
973        }
974        else
975        {
976            DataBufferHeap data (m_temporary_allocation_size, 0);
977
978            map.ReadMemory(data.GetBytes(), m_temporary_allocation, m_temporary_allocation_size, err);
979
980            if (!err.Success())
981            {
982                dump_stream.Printf("  <could not be read>\n");
983            }
984            else
985            {
986                DataExtractor extractor (data.GetBytes(), data.GetByteSize(), map.GetByteOrder(), map.GetAddressByteSize());
987
988                extractor.DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, load_addr);
989
990                dump_stream.PutChar('\n');
991            }
992        }
993
994        log->PutCString(dump_stream.GetData());
995    }
996
997    void Wipe (IRMemoryMap &map, lldb::addr_t process_address)
998    {
999        if (!m_keep_in_memory && m_temporary_allocation != LLDB_INVALID_ADDRESS)
1000        {
1001            Error free_error;
1002
1003            map.Free(m_temporary_allocation, free_error);
1004        }
1005
1006        m_temporary_allocation = LLDB_INVALID_ADDRESS;
1007        m_temporary_allocation_size = 0;
1008    }
1009private:
1010    TypeFromUser    m_type;
1011    bool            m_is_program_reference;
1012    bool            m_keep_in_memory;
1013
1014    lldb::addr_t    m_temporary_allocation;
1015    size_t          m_temporary_allocation_size;
1016};
1017
1018uint32_t
1019Materializer::AddResultVariable (const TypeFromUser &type, bool is_program_reference, bool keep_in_memory, Error &err)
1020{
1021    EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
1022    iter->reset (new EntityResultVariable (type, is_program_reference, keep_in_memory));
1023    uint32_t ret = AddStructMember(**iter);
1024    (*iter)->SetOffset(ret);
1025    m_result_entity = iter->get();
1026    return ret;
1027}
1028
1029class EntitySymbol : public Materializer::Entity
1030{
1031public:
1032    EntitySymbol (const Symbol &symbol) :
1033        Entity(),
1034        m_symbol(symbol)
1035    {
1036        // Hard-coding to maximum size of a symbol
1037        m_size = 8;
1038        m_alignment = 8;
1039    }
1040
1041    void Materialize (lldb::StackFrameSP &frame_sp, IRMemoryMap &map, lldb::addr_t process_address, Error &err)
1042    {
1043        Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
1044
1045        const lldb::addr_t load_addr = process_address + m_offset;
1046
1047        if (log)
1048        {
1049            log->Printf("EntitySymbol::Materialize [address = 0x%" PRIx64 ", m_symbol = %s]",
1050                        (uint64_t)load_addr,
1051                        m_symbol.GetName().AsCString());
1052        }
1053
1054        Address &sym_address = m_symbol.GetAddress();
1055
1056        ExecutionContextScope *exe_scope = map.GetBestExecutionContextScope();
1057
1058        lldb::TargetSP target_sp;
1059
1060        if (exe_scope)
1061            target_sp = map.GetBestExecutionContextScope()->CalculateTarget();
1062
1063        if (!target_sp)
1064        {
1065            err.SetErrorStringWithFormat("couldn't resolve symbol %s because there is no target", m_symbol.GetName().AsCString());
1066            return;
1067        }
1068
1069        lldb::addr_t resolved_address = sym_address.GetLoadAddress(target_sp.get());
1070
1071        if (resolved_address == LLDB_INVALID_ADDRESS)
1072            resolved_address = sym_address.GetFileAddress();
1073
1074        Error pointer_write_error;
1075
1076        map.WritePointerToMemory(load_addr, resolved_address, pointer_write_error);
1077
1078        if (!pointer_write_error.Success())
1079        {
1080            err.SetErrorStringWithFormat("couldn't write the address of symbol %s: %s", m_symbol.GetName().AsCString(), pointer_write_error.AsCString());
1081            return;
1082        }
1083    }
1084
1085    void Dematerialize (lldb::StackFrameSP &frame_sp,
1086                        IRMemoryMap &map,
1087                        lldb::addr_t process_address,
1088                        lldb::addr_t frame_top,
1089                        lldb::addr_t frame_bottom,
1090                        Error &err)
1091    {
1092        Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
1093
1094        const lldb::addr_t load_addr = process_address + m_offset;
1095
1096        if (log)
1097        {
1098            log->Printf("EntitySymbol::Dematerialize [address = 0x%" PRIx64 ", m_symbol = %s]",
1099                        (uint64_t)load_addr,
1100                        m_symbol.GetName().AsCString());
1101        }
1102
1103        // no work needs to be done
1104    }
1105
1106    void DumpToLog (IRMemoryMap &map, lldb::addr_t process_address, Log *log)
1107    {
1108        StreamString dump_stream;
1109
1110        Error err;
1111
1112        const lldb::addr_t load_addr = process_address + m_offset;
1113
1114        dump_stream.Printf("0x%" PRIx64 ": EntitySymbol (%s)\n", load_addr, m_symbol.GetName().AsCString());
1115
1116        {
1117            dump_stream.Printf("Pointer:\n");
1118
1119            DataBufferHeap data (m_size, 0);
1120
1121            map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
1122
1123            if (!err.Success())
1124            {
1125                dump_stream.Printf("  <could not be read>\n");
1126            }
1127            else
1128            {
1129                DataExtractor extractor (data.GetBytes(), data.GetByteSize(), map.GetByteOrder(), map.GetAddressByteSize());
1130
1131                extractor.DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, load_addr);
1132
1133                dump_stream.PutChar('\n');
1134            }
1135        }
1136
1137        log->PutCString(dump_stream.GetData());
1138    }
1139
1140    void Wipe (IRMemoryMap &map, lldb::addr_t process_address)
1141    {
1142    }
1143private:
1144    Symbol m_symbol;
1145};
1146
1147uint32_t
1148Materializer::AddSymbol (const Symbol &symbol_sp, Error &err)
1149{
1150    EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
1151    iter->reset (new EntitySymbol (symbol_sp));
1152    uint32_t ret = AddStructMember(**iter);
1153    (*iter)->SetOffset(ret);
1154    return ret;
1155}
1156
1157class EntityRegister : public Materializer::Entity
1158{
1159public:
1160    EntityRegister (const RegisterInfo &register_info) :
1161        Entity(),
1162        m_register_info(register_info)
1163    {
1164        // Hard-coding alignment conservatively
1165        m_size = m_register_info.byte_size;
1166        m_alignment = m_register_info.byte_size;
1167    }
1168
1169    void Materialize (lldb::StackFrameSP &frame_sp, IRMemoryMap &map, lldb::addr_t process_address, Error &err)
1170    {
1171        Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
1172
1173        const lldb::addr_t load_addr = process_address + m_offset;
1174
1175        if (log)
1176        {
1177            log->Printf("EntityRegister::Materialize [address = 0x%" PRIx64 ", m_register_info = %s]",
1178                        (uint64_t)load_addr,
1179                        m_register_info.name);
1180        }
1181
1182        RegisterValue reg_value;
1183
1184        if (!frame_sp.get())
1185        {
1186            err.SetErrorStringWithFormat("couldn't materialize register %s without a stack frame", m_register_info.name);
1187            return;
1188        }
1189
1190        lldb::RegisterContextSP reg_context_sp = frame_sp->GetRegisterContext();
1191
1192        if (!reg_context_sp->ReadRegister(&m_register_info, reg_value))
1193        {
1194            err.SetErrorStringWithFormat("couldn't read the value of register %s", m_register_info.name);
1195            return;
1196        }
1197
1198        DataExtractor register_data;
1199
1200        if (!reg_value.GetData(register_data))
1201        {
1202            err.SetErrorStringWithFormat("couldn't get the data for register %s", m_register_info.name);
1203            return;
1204        }
1205
1206        if (register_data.GetByteSize() != m_register_info.byte_size)
1207        {
1208            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);
1209            return;
1210        }
1211
1212        m_register_contents.reset(new DataBufferHeap(register_data.GetDataStart(), register_data.GetByteSize()));
1213
1214        Error write_error;
1215
1216        map.WriteMemory(load_addr, register_data.GetDataStart(), register_data.GetByteSize(), write_error);
1217
1218        if (!write_error.Success())
1219        {
1220            err.SetErrorStringWithFormat("couldn't write the contents of register %s: %s", m_register_info.name, write_error.AsCString());
1221            return;
1222        }
1223    }
1224
1225    void Dematerialize (lldb::StackFrameSP &frame_sp,
1226                        IRMemoryMap &map,
1227                        lldb::addr_t process_address,
1228                        lldb::addr_t frame_top,
1229                        lldb::addr_t frame_bottom,
1230                        Error &err)
1231    {
1232        Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
1233
1234        const lldb::addr_t load_addr = process_address + m_offset;
1235
1236        if (log)
1237        {
1238            log->Printf("EntityRegister::Dematerialize [address = 0x%" PRIx64 ", m_register_info = %s]",
1239                        (uint64_t)load_addr,
1240                        m_register_info.name);
1241        }
1242
1243        Error extract_error;
1244
1245        DataExtractor register_data;
1246
1247        if (!frame_sp.get())
1248        {
1249            err.SetErrorStringWithFormat("couldn't dematerialize 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        map.GetMemoryData(register_data, load_addr, m_register_info.byte_size, extract_error);
1256
1257        if (!extract_error.Success())
1258        {
1259            err.SetErrorStringWithFormat("couldn't get the data for register %s: %s", m_register_info.name, extract_error.AsCString());
1260            return;
1261        }
1262
1263        if (!memcmp(register_data.GetDataStart(), m_register_contents->GetBytes(), register_data.GetByteSize()))
1264        {
1265            // No write required, and in particular we avoid errors if the register wasn't writable
1266
1267            m_register_contents.reset();
1268            return;
1269        }
1270
1271        m_register_contents.reset();
1272
1273        RegisterValue register_value (const_cast<uint8_t*>(register_data.GetDataStart()), register_data.GetByteSize(), register_data.GetByteOrder());
1274
1275        if (!reg_context_sp->WriteRegister(&m_register_info, register_value))
1276        {
1277            err.SetErrorStringWithFormat("couldn't write the value of register %s", m_register_info.name);
1278            return;
1279        }
1280    }
1281
1282    void DumpToLog (IRMemoryMap &map, lldb::addr_t process_address, Log *log)
1283    {
1284        StreamString dump_stream;
1285
1286        Error err;
1287
1288        const lldb::addr_t load_addr = process_address + m_offset;
1289
1290
1291        dump_stream.Printf("0x%" PRIx64 ": EntityRegister (%s)\n", load_addr, m_register_info.name);
1292
1293        {
1294            dump_stream.Printf("Value:\n");
1295
1296            DataBufferHeap data (m_size, 0);
1297
1298            map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
1299
1300            if (!err.Success())
1301            {
1302                dump_stream.Printf("  <could not be read>\n");
1303            }
1304            else
1305            {
1306                DataExtractor extractor (data.GetBytes(), data.GetByteSize(), map.GetByteOrder(), map.GetAddressByteSize());
1307
1308                extractor.DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16, load_addr);
1309
1310                dump_stream.PutChar('\n');
1311            }
1312        }
1313
1314        log->PutCString(dump_stream.GetData());
1315    }
1316
1317    void Wipe (IRMemoryMap &map, lldb::addr_t process_address)
1318    {
1319    }
1320private:
1321    RegisterInfo m_register_info;
1322    lldb::DataBufferSP m_register_contents;
1323};
1324
1325uint32_t
1326Materializer::AddRegister (const RegisterInfo &register_info, Error &err)
1327{
1328    EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
1329    iter->reset (new EntityRegister (register_info));
1330    uint32_t ret = AddStructMember(**iter);
1331    (*iter)->SetOffset(ret);
1332    return ret;
1333}
1334
1335Materializer::Materializer () :
1336    m_dematerializer_wp(),
1337    m_result_entity(NULL),
1338    m_current_offset(0),
1339    m_struct_alignment(8)
1340{
1341}
1342
1343Materializer::~Materializer ()
1344{
1345    DematerializerSP dematerializer_sp = m_dematerializer_wp.lock();
1346
1347    if (dematerializer_sp)
1348        dematerializer_sp->Wipe();
1349}
1350
1351Materializer::DematerializerSP
1352Materializer::Materialize (lldb::StackFrameSP &frame_sp, IRMemoryMap &map, lldb::addr_t process_address, Error &error)
1353{
1354    ExecutionContextScope *exe_scope = frame_sp.get();
1355
1356    if (!exe_scope)
1357        exe_scope = map.GetBestExecutionContextScope();
1358
1359    DematerializerSP dematerializer_sp = m_dematerializer_wp.lock();
1360
1361    if (dematerializer_sp)
1362    {
1363        error.SetErrorToGenericError();
1364        error.SetErrorString("Couldn't materialize: already materialized");
1365    }
1366
1367    DematerializerSP ret(new Dematerializer(*this, frame_sp, map, process_address));
1368
1369    if (!exe_scope)
1370    {
1371        error.SetErrorToGenericError();
1372        error.SetErrorString("Couldn't materialize: target doesn't exist");
1373    }
1374
1375    for (EntityUP &entity_up : m_entities)
1376    {
1377        entity_up->Materialize(frame_sp, map, process_address, error);
1378
1379        if (!error.Success())
1380            return DematerializerSP();
1381    }
1382
1383    if (Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS))
1384    {
1385        log->Printf("Materializer::Materialize (frame_sp = %p, process_address = 0x%" PRIx64 ") materialized:",
1386                    static_cast<void*>(frame_sp.get()), process_address);
1387        for (EntityUP &entity_up : m_entities)
1388            entity_up->DumpToLog(map, process_address, log);
1389    }
1390
1391    m_dematerializer_wp = ret;
1392
1393    return ret;
1394}
1395
1396void
1397Materializer::Dematerializer::Dematerialize (Error &error, lldb::ClangExpressionVariableSP &result_sp, lldb::addr_t frame_bottom, lldb::addr_t frame_top)
1398{
1399    lldb::StackFrameSP frame_sp;
1400
1401    lldb::ThreadSP thread_sp = m_thread_wp.lock();
1402    if (thread_sp)
1403        frame_sp = thread_sp->GetFrameWithStackID(m_stack_id);
1404
1405    ExecutionContextScope *exe_scope = m_map->GetBestExecutionContextScope();
1406
1407    if (!IsValid())
1408    {
1409        error.SetErrorToGenericError();
1410        error.SetErrorString("Couldn't dematerialize: invalid dematerializer");
1411    }
1412
1413    if (!exe_scope)
1414    {
1415        error.SetErrorToGenericError();
1416        error.SetErrorString("Couldn't dematerialize: target is gone");
1417    }
1418    else
1419    {
1420        if (Log *log =lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS))
1421        {
1422            log->Printf("Materializer::Dematerialize (frame_sp = %p, process_address = 0x%" PRIx64 ") about to dematerialize:",
1423                        static_cast<void*>(frame_sp.get()), m_process_address);
1424            for (EntityUP &entity_up : m_materializer->m_entities)
1425                entity_up->DumpToLog(*m_map, m_process_address, log);
1426        }
1427
1428        for (EntityUP &entity_up : m_materializer->m_entities)
1429        {
1430            if (entity_up.get() == m_materializer->m_result_entity)
1431            {
1432                static_cast<EntityResultVariable*>(m_materializer->m_result_entity)->Dematerialize (result_sp, frame_sp, *m_map, m_process_address, frame_top, frame_bottom, error);
1433            }
1434            else
1435            {
1436                entity_up->Dematerialize (frame_sp, *m_map, m_process_address, frame_top, frame_bottom, error);
1437            }
1438
1439            if (!error.Success())
1440                break;
1441        }
1442    }
1443
1444    Wipe();
1445}
1446
1447void
1448Materializer::Dematerializer::Wipe ()
1449{
1450    if (!IsValid())
1451        return;
1452
1453    for (EntityUP &entity_up : m_materializer->m_entities)
1454    {
1455        entity_up->Wipe (*m_map, m_process_address);
1456    }
1457
1458    m_materializer = NULL;
1459    m_map = NULL;
1460    m_process_address = LLDB_INVALID_ADDRESS;
1461}
1462