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