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