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