blob: 3945f3a70f7569ff61f6dd5c320c1217a49c1ebf [file] [log] [blame]
Thiébaud Weksteene40e7362020-10-28 15:03:00 +01001//===-- Materializer.cpp --------------------------------------------------===//
Inna Palantff3f07a2019-07-11 16:15:26 -07002//
Chih-Hung Hsieh08600532019-12-19 15:55:38 -08003// 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
Inna Palantff3f07a2019-07-11 16:15:26 -07006//
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"
Inna Palantff3f07a2019-07-11 16:15:26 -070014#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
Chih-Hung Hsieh08600532019-12-19 15:55:38 -080025#include <memory>
26
Inna Palantff3f07a2019-07-11 16:15:26 -070027using namespace lldb_private;
28
29uint32_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
Inna Palantff3f07a2019-07-11 16:15:26 -070048class EntityPersistentVariable : public Materializer::Entity {
49public:
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(
Chris Wailese3116c42021-07-13 14:40:48 -070070 m_persistent_variable_sp->GetByteSize().getValueOr(0), 8,
Inna Palantff3f07a2019-07-11 16:15:26 -070071 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
Jeff Vander Stoep247d86b2020-08-11 14:27:44 +020082 LLDB_LOGF(log, "Allocated %s (0x%" PRIx64 ") successfully",
83 m_persistent_variable_sp->GetName().GetCString(), mem);
Inna Palantff3f07a2019-07-11 16:15:26 -070084
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(),
Chris Wailese3116c42021-07-13 14:40:48 -0700109 m_persistent_variable_sp->GetByteSize().getValueOr(0),
110 write_error);
Inna Palantff3f07a2019-07-11 16:15:26 -0700111
112 if (!write_error.Success()) {
113 err.SetErrorStringWithFormat(
114 "couldn't write %s to the target: %s",
115 m_persistent_variable_sp->GetName().AsCString(),
116 write_error.AsCString());
117 return;
118 }
119 }
120
121 void DestroyAllocation(IRMemoryMap &map, Status &err) {
122 Status deallocate_error;
123
124 map.Free((lldb::addr_t)m_persistent_variable_sp->m_live_sp->GetValue()
125 .GetScalar()
126 .ULongLong(),
127 deallocate_error);
128
129 m_persistent_variable_sp->m_live_sp.reset();
130
131 if (!deallocate_error.Success()) {
132 err.SetErrorStringWithFormat(
133 "couldn't deallocate memory for %s: %s",
134 m_persistent_variable_sp->GetName().GetCString(),
135 deallocate_error.AsCString());
136 }
137 }
138
139 void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
140 lldb::addr_t process_address, Status &err) override {
141 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
142
143 const lldb::addr_t load_addr = process_address + m_offset;
144
145 if (log) {
Jeff Vander Stoep247d86b2020-08-11 14:27:44 +0200146 LLDB_LOGF(log,
147 "EntityPersistentVariable::Materialize [address = 0x%" PRIx64
148 ", m_name = %s, m_flags = 0x%hx]",
149 (uint64_t)load_addr,
150 m_persistent_variable_sp->GetName().AsCString(),
151 m_persistent_variable_sp->m_flags);
Inna Palantff3f07a2019-07-11 16:15:26 -0700152 }
153
154 if (m_persistent_variable_sp->m_flags &
155 ExpressionVariable::EVNeedsAllocation) {
156 MakeAllocation(map, err);
157 m_persistent_variable_sp->m_flags |=
158 ExpressionVariable::EVIsLLDBAllocated;
159
160 if (!err.Success())
161 return;
162 }
163
164 if ((m_persistent_variable_sp->m_flags &
165 ExpressionVariable::EVIsProgramReference &&
166 m_persistent_variable_sp->m_live_sp) ||
167 m_persistent_variable_sp->m_flags &
168 ExpressionVariable::EVIsLLDBAllocated) {
169 Status write_error;
170
171 map.WriteScalarToMemory(
172 load_addr,
173 m_persistent_variable_sp->m_live_sp->GetValue().GetScalar(),
174 map.GetAddressByteSize(), write_error);
175
176 if (!write_error.Success()) {
177 err.SetErrorStringWithFormat(
178 "couldn't write the location of %s to memory: %s",
179 m_persistent_variable_sp->GetName().AsCString(),
180 write_error.AsCString());
181 }
182 } else {
183 err.SetErrorStringWithFormat(
184 "no materialization happened for persistent variable %s",
185 m_persistent_variable_sp->GetName().AsCString());
186 return;
187 }
188 }
189
190 void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
191 lldb::addr_t process_address, lldb::addr_t frame_top,
192 lldb::addr_t frame_bottom, Status &err) override {
193 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
194
195 const lldb::addr_t load_addr = process_address + m_offset;
196
197 if (log) {
Jeff Vander Stoep247d86b2020-08-11 14:27:44 +0200198 LLDB_LOGF(log,
199 "EntityPersistentVariable::Dematerialize [address = 0x%" PRIx64
200 ", m_name = %s, m_flags = 0x%hx]",
201 (uint64_t)process_address + m_offset,
202 m_persistent_variable_sp->GetName().AsCString(),
203 m_persistent_variable_sp->m_flags);
Inna Palantff3f07a2019-07-11 16:15:26 -0700204 }
205
206 if (m_delegate) {
207 m_delegate->DidDematerialize(m_persistent_variable_sp);
208 }
209
210 if ((m_persistent_variable_sp->m_flags &
211 ExpressionVariable::EVIsLLDBAllocated) ||
212 (m_persistent_variable_sp->m_flags &
213 ExpressionVariable::EVIsProgramReference)) {
214 if (m_persistent_variable_sp->m_flags &
215 ExpressionVariable::EVIsProgramReference &&
216 !m_persistent_variable_sp->m_live_sp) {
217 // If the reference comes from the program, then the
218 // ClangExpressionVariable's live variable data hasn't been set up yet.
219 // Do this now.
220
221 lldb::addr_t location;
222 Status read_error;
223
224 map.ReadPointerFromMemory(&location, load_addr, read_error);
225
226 if (!read_error.Success()) {
227 err.SetErrorStringWithFormat(
228 "couldn't read the address of program-allocated variable %s: %s",
229 m_persistent_variable_sp->GetName().GetCString(),
230 read_error.AsCString());
231 return;
232 }
233
234 m_persistent_variable_sp->m_live_sp = ValueObjectConstResult::Create(
235 map.GetBestExecutionContextScope(),
236 m_persistent_variable_sp.get()->GetCompilerType(),
237 m_persistent_variable_sp->GetName(), location, eAddressTypeLoad,
Chris Wailese3116c42021-07-13 14:40:48 -0700238 m_persistent_variable_sp->GetByteSize().getValueOr(0));
Inna Palantff3f07a2019-07-11 16:15:26 -0700239
240 if (frame_top != LLDB_INVALID_ADDRESS &&
241 frame_bottom != LLDB_INVALID_ADDRESS && location >= frame_bottom &&
242 location <= frame_top) {
243 // If the variable is resident in the stack frame created by the
244 // expression, then it cannot be relied upon to stay around. We
245 // treat it as needing reallocation.
246 m_persistent_variable_sp->m_flags |=
247 ExpressionVariable::EVIsLLDBAllocated;
248 m_persistent_variable_sp->m_flags |=
249 ExpressionVariable::EVNeedsAllocation;
250 m_persistent_variable_sp->m_flags |=
251 ExpressionVariable::EVNeedsFreezeDry;
252 m_persistent_variable_sp->m_flags &=
253 ~ExpressionVariable::EVIsProgramReference;
254 }
255 }
256
257 lldb::addr_t mem = m_persistent_variable_sp->m_live_sp->GetValue()
258 .GetScalar()
259 .ULongLong();
260
261 if (!m_persistent_variable_sp->m_live_sp) {
262 err.SetErrorStringWithFormat(
263 "couldn't find the memory area used to store %s",
264 m_persistent_variable_sp->GetName().GetCString());
265 return;
266 }
267
268 if (m_persistent_variable_sp->m_live_sp->GetValue()
269 .GetValueAddressType() != eAddressTypeLoad) {
270 err.SetErrorStringWithFormat(
271 "the address of the memory area for %s is in an incorrect format",
272 m_persistent_variable_sp->GetName().GetCString());
273 return;
274 }
275
276 if (m_persistent_variable_sp->m_flags &
277 ExpressionVariable::EVNeedsFreezeDry ||
278 m_persistent_variable_sp->m_flags &
279 ExpressionVariable::EVKeepInTarget) {
Jeff Vander Stoep247d86b2020-08-11 14:27:44 +0200280 LLDB_LOGF(log, "Dematerializing %s from 0x%" PRIx64 " (size = %llu)",
281 m_persistent_variable_sp->GetName().GetCString(),
282 (uint64_t)mem,
Chris Wailese3116c42021-07-13 14:40:48 -0700283 (unsigned long long)m_persistent_variable_sp->GetByteSize()
284 .getValueOr(0));
Inna Palantff3f07a2019-07-11 16:15:26 -0700285
286 // Read the contents of the spare memory area
287
288 m_persistent_variable_sp->ValueUpdated();
289
290 Status read_error;
291
292 map.ReadMemory(m_persistent_variable_sp->GetValueBytes(), mem,
Chris Wailese3116c42021-07-13 14:40:48 -0700293 m_persistent_variable_sp->GetByteSize().getValueOr(0), read_error);
Inna Palantff3f07a2019-07-11 16:15:26 -0700294
295 if (!read_error.Success()) {
296 err.SetErrorStringWithFormat(
297 "couldn't read the contents of %s from memory: %s",
298 m_persistent_variable_sp->GetName().GetCString(),
299 read_error.AsCString());
300 return;
301 }
302
303 m_persistent_variable_sp->m_flags &=
304 ~ExpressionVariable::EVNeedsFreezeDry;
305 }
306 } else {
307 err.SetErrorStringWithFormat(
308 "no dematerialization happened for persistent variable %s",
309 m_persistent_variable_sp->GetName().AsCString());
310 return;
311 }
312
313 lldb::ProcessSP process_sp =
314 map.GetBestExecutionContextScope()->CalculateProcess();
315 if (!process_sp || !process_sp->CanJIT()) {
316 // Allocations are not persistent so persistent variables cannot stay
317 // materialized.
318
319 m_persistent_variable_sp->m_flags |=
320 ExpressionVariable::EVNeedsAllocation;
321
322 DestroyAllocation(map, err);
323 if (!err.Success())
324 return;
325 } else if (m_persistent_variable_sp->m_flags &
326 ExpressionVariable::EVNeedsAllocation &&
327 !(m_persistent_variable_sp->m_flags &
328 ExpressionVariable::EVKeepInTarget)) {
329 DestroyAllocation(map, err);
330 if (!err.Success())
331 return;
332 }
333 }
334
335 void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
336 Log *log) override {
337 StreamString dump_stream;
338
339 Status err;
340
341 const lldb::addr_t load_addr = process_address + m_offset;
342
343 dump_stream.Printf("0x%" PRIx64 ": EntityPersistentVariable (%s)\n",
344 load_addr,
345 m_persistent_variable_sp->GetName().AsCString());
346
347 {
348 dump_stream.Printf("Pointer:\n");
349
350 DataBufferHeap data(m_size, 0);
351
352 map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
353
354 if (!err.Success()) {
355 dump_stream.Printf(" <could not be read>\n");
356 } else {
357 DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
358 load_addr);
359
360 dump_stream.PutChar('\n');
361 }
362 }
363
364 {
365 dump_stream.Printf("Target:\n");
366
367 lldb::addr_t target_address;
368
369 map.ReadPointerFromMemory(&target_address, load_addr, err);
370
371 if (!err.Success()) {
372 dump_stream.Printf(" <could not be read>\n");
373 } else {
Chris Wailese3116c42021-07-13 14:40:48 -0700374 DataBufferHeap data(
375 m_persistent_variable_sp->GetByteSize().getValueOr(0), 0);
Inna Palantff3f07a2019-07-11 16:15:26 -0700376
377 map.ReadMemory(data.GetBytes(), target_address,
Chris Wailese3116c42021-07-13 14:40:48 -0700378 m_persistent_variable_sp->GetByteSize().getValueOr(0), err);
Inna Palantff3f07a2019-07-11 16:15:26 -0700379
380 if (!err.Success()) {
381 dump_stream.Printf(" <could not be read>\n");
382 } else {
383 DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
384 target_address);
385
386 dump_stream.PutChar('\n');
387 }
388 }
389 }
390
391 log->PutString(dump_stream.GetString());
392 }
393
394 void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {}
395
396private:
397 lldb::ExpressionVariableSP m_persistent_variable_sp;
398 Materializer::PersistentVariableDelegate *m_delegate;
399};
400
401uint32_t Materializer::AddPersistentVariable(
402 lldb::ExpressionVariableSP &persistent_variable_sp,
403 PersistentVariableDelegate *delegate, Status &err) {
404 EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
Thiébaud Weksteene40e7362020-10-28 15:03:00 +0100405 *iter = std::make_unique<EntityPersistentVariable>(persistent_variable_sp,
406 delegate);
Inna Palantff3f07a2019-07-11 16:15:26 -0700407 uint32_t ret = AddStructMember(**iter);
408 (*iter)->SetOffset(ret);
409 return ret;
410}
411
412class EntityVariable : public Materializer::Entity {
413public:
414 EntityVariable(lldb::VariableSP &variable_sp)
415 : Entity(), m_variable_sp(variable_sp), m_is_reference(false),
416 m_temporary_allocation(LLDB_INVALID_ADDRESS),
417 m_temporary_allocation_size(0) {
418 // Hard-coding to maximum size of a pointer since all variables are
419 // materialized by reference
420 m_size = 8;
421 m_alignment = 8;
422 m_is_reference =
423 m_variable_sp->GetType()->GetForwardCompilerType().IsReferenceType();
424 }
425
426 void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
427 lldb::addr_t process_address, Status &err) override {
428 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
429
430 const lldb::addr_t load_addr = process_address + m_offset;
431 if (log) {
Jeff Vander Stoep247d86b2020-08-11 14:27:44 +0200432 LLDB_LOGF(log,
433 "EntityVariable::Materialize [address = 0x%" PRIx64
434 ", m_variable_sp = %s]",
435 (uint64_t)load_addr, m_variable_sp->GetName().AsCString());
Inna Palantff3f07a2019-07-11 16:15:26 -0700436 }
437
438 ExecutionContextScope *scope = frame_sp.get();
439
440 if (!scope)
441 scope = map.GetBestExecutionContextScope();
442
443 lldb::ValueObjectSP valobj_sp =
444 ValueObjectVariable::Create(scope, m_variable_sp);
445
446 if (!valobj_sp) {
447 err.SetErrorStringWithFormat(
448 "couldn't get a value object for variable %s",
449 m_variable_sp->GetName().AsCString());
450 return;
451 }
452
453 Status valobj_error = valobj_sp->GetError();
454
455 if (valobj_error.Fail()) {
456 err.SetErrorStringWithFormat("couldn't get the value of variable %s: %s",
457 m_variable_sp->GetName().AsCString(),
458 valobj_error.AsCString());
459 return;
460 }
461
462 if (m_is_reference) {
463 DataExtractor valobj_extractor;
464 Status extract_error;
465 valobj_sp->GetData(valobj_extractor, extract_error);
466
467 if (!extract_error.Success()) {
468 err.SetErrorStringWithFormat(
469 "couldn't read contents of reference variable %s: %s",
470 m_variable_sp->GetName().AsCString(), extract_error.AsCString());
471 return;
472 }
473
474 lldb::offset_t offset = 0;
475 lldb::addr_t reference_addr = valobj_extractor.GetAddress(&offset);
476
477 Status write_error;
478 map.WritePointerToMemory(load_addr, reference_addr, write_error);
479
480 if (!write_error.Success()) {
481 err.SetErrorStringWithFormat("couldn't write the contents of reference "
482 "variable %s to memory: %s",
483 m_variable_sp->GetName().AsCString(),
484 write_error.AsCString());
485 return;
486 }
487 } else {
488 AddressType address_type = eAddressTypeInvalid;
489 const bool scalar_is_load_address = false;
490 lldb::addr_t addr_of_valobj =
491 valobj_sp->GetAddressOf(scalar_is_load_address, &address_type);
492 if (addr_of_valobj != LLDB_INVALID_ADDRESS) {
493 Status write_error;
494 map.WritePointerToMemory(load_addr, addr_of_valobj, write_error);
495
496 if (!write_error.Success()) {
497 err.SetErrorStringWithFormat(
498 "couldn't write the address of variable %s to memory: %s",
499 m_variable_sp->GetName().AsCString(), write_error.AsCString());
500 return;
501 }
502 } else {
503 DataExtractor data;
504 Status extract_error;
505 valobj_sp->GetData(data, extract_error);
506 if (!extract_error.Success()) {
507 err.SetErrorStringWithFormat("couldn't get the value of %s: %s",
508 m_variable_sp->GetName().AsCString(),
509 extract_error.AsCString());
510 return;
511 }
512
513 if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
514 err.SetErrorStringWithFormat(
515 "trying to create a temporary region for %s but one exists",
516 m_variable_sp->GetName().AsCString());
517 return;
518 }
519
Chris Wailese3116c42021-07-13 14:40:48 -0700520 if (data.GetByteSize() < m_variable_sp->GetType()->GetByteSize(scope)) {
Inna Palantff3f07a2019-07-11 16:15:26 -0700521 if (data.GetByteSize() == 0 &&
522 !m_variable_sp->LocationExpression().IsValid()) {
523 err.SetErrorStringWithFormat("the variable '%s' has no location, "
524 "it may have been optimized out",
525 m_variable_sp->GetName().AsCString());
526 } else {
527 err.SetErrorStringWithFormat(
528 "size of variable %s (%" PRIu64
529 ") is larger than the ValueObject's size (%" PRIu64 ")",
530 m_variable_sp->GetName().AsCString(),
Chris Wailese3116c42021-07-13 14:40:48 -0700531 m_variable_sp->GetType()->GetByteSize(scope).getValueOr(0),
Chih-Hung Hsieh08600532019-12-19 15:55:38 -0800532 data.GetByteSize());
Inna Palantff3f07a2019-07-11 16:15:26 -0700533 }
534 return;
535 }
536
Jeff Vander Stoep247d86b2020-08-11 14:27:44 +0200537 llvm::Optional<size_t> opt_bit_align =
538 m_variable_sp->GetType()->GetLayoutCompilerType().GetTypeBitAlign(scope);
539 if (!opt_bit_align) {
540 err.SetErrorStringWithFormat("can't get the type alignment for %s",
541 m_variable_sp->GetName().AsCString());
542 return;
543 }
Inna Palantff3f07a2019-07-11 16:15:26 -0700544
Jeff Vander Stoep247d86b2020-08-11 14:27:44 +0200545 size_t byte_align = (*opt_bit_align + 7) / 8;
Inna Palantff3f07a2019-07-11 16:15:26 -0700546
547 Status alloc_error;
548 const bool zero_memory = false;
549
550 m_temporary_allocation = map.Malloc(
551 data.GetByteSize(), byte_align,
552 lldb::ePermissionsReadable | lldb::ePermissionsWritable,
553 IRMemoryMap::eAllocationPolicyMirror, zero_memory, alloc_error);
554
555 m_temporary_allocation_size = data.GetByteSize();
556
Chih-Hung Hsieh08600532019-12-19 15:55:38 -0800557 m_original_data = std::make_shared<DataBufferHeap>(data.GetDataStart(),
558 data.GetByteSize());
Inna Palantff3f07a2019-07-11 16:15:26 -0700559
560 if (!alloc_error.Success()) {
561 err.SetErrorStringWithFormat(
562 "couldn't allocate a temporary region for %s: %s",
563 m_variable_sp->GetName().AsCString(), alloc_error.AsCString());
564 return;
565 }
566
567 Status write_error;
568
569 map.WriteMemory(m_temporary_allocation, data.GetDataStart(),
570 data.GetByteSize(), write_error);
571
572 if (!write_error.Success()) {
573 err.SetErrorStringWithFormat(
574 "couldn't write to the temporary region for %s: %s",
575 m_variable_sp->GetName().AsCString(), write_error.AsCString());
576 return;
577 }
578
579 Status pointer_write_error;
580
581 map.WritePointerToMemory(load_addr, m_temporary_allocation,
582 pointer_write_error);
583
584 if (!pointer_write_error.Success()) {
585 err.SetErrorStringWithFormat(
586 "couldn't write the address of the temporary region for %s: %s",
587 m_variable_sp->GetName().AsCString(),
588 pointer_write_error.AsCString());
589 }
590 }
591 }
592 }
593
594 void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
595 lldb::addr_t process_address, lldb::addr_t frame_top,
596 lldb::addr_t frame_bottom, Status &err) override {
597 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
598
599 const lldb::addr_t load_addr = process_address + m_offset;
600 if (log) {
Jeff Vander Stoep247d86b2020-08-11 14:27:44 +0200601 LLDB_LOGF(log,
602 "EntityVariable::Dematerialize [address = 0x%" PRIx64
603 ", m_variable_sp = %s]",
604 (uint64_t)load_addr, m_variable_sp->GetName().AsCString());
Inna Palantff3f07a2019-07-11 16:15:26 -0700605 }
606
607 if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
608 ExecutionContextScope *scope = frame_sp.get();
609
610 if (!scope)
611 scope = map.GetBestExecutionContextScope();
612
613 lldb::ValueObjectSP valobj_sp =
614 ValueObjectVariable::Create(scope, m_variable_sp);
615
616 if (!valobj_sp) {
617 err.SetErrorStringWithFormat(
618 "couldn't get a value object for variable %s",
619 m_variable_sp->GetName().AsCString());
620 return;
621 }
622
623 lldb_private::DataExtractor data;
624
625 Status extract_error;
626
Chris Wailese3116c42021-07-13 14:40:48 -0700627 map.GetMemoryData(data, m_temporary_allocation,
628 valobj_sp->GetByteSize().getValueOr(0), extract_error);
Inna Palantff3f07a2019-07-11 16:15:26 -0700629
630 if (!extract_error.Success()) {
631 err.SetErrorStringWithFormat("couldn't get the data for variable %s",
632 m_variable_sp->GetName().AsCString());
633 return;
634 }
635
636 bool actually_write = true;
637
638 if (m_original_data) {
639 if ((data.GetByteSize() == m_original_data->GetByteSize()) &&
640 !memcmp(m_original_data->GetBytes(), data.GetDataStart(),
641 data.GetByteSize())) {
642 actually_write = false;
643 }
644 }
645
646 Status set_error;
647
648 if (actually_write) {
649 valobj_sp->SetData(data, set_error);
650
651 if (!set_error.Success()) {
652 err.SetErrorStringWithFormat(
653 "couldn't write the new contents of %s back into the variable",
654 m_variable_sp->GetName().AsCString());
655 return;
656 }
657 }
658
659 Status free_error;
660
661 map.Free(m_temporary_allocation, free_error);
662
663 if (!free_error.Success()) {
664 err.SetErrorStringWithFormat(
665 "couldn't free the temporary region for %s: %s",
666 m_variable_sp->GetName().AsCString(), free_error.AsCString());
667 return;
668 }
669
670 m_original_data.reset();
671 m_temporary_allocation = LLDB_INVALID_ADDRESS;
672 m_temporary_allocation_size = 0;
673 }
674 }
675
676 void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
677 Log *log) override {
678 StreamString dump_stream;
679
680 const lldb::addr_t load_addr = process_address + m_offset;
681 dump_stream.Printf("0x%" PRIx64 ": EntityVariable\n", load_addr);
682
683 Status err;
684
685 lldb::addr_t ptr = LLDB_INVALID_ADDRESS;
686
687 {
688 dump_stream.Printf("Pointer:\n");
689
690 DataBufferHeap data(m_size, 0);
691
692 map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
693
694 if (!err.Success()) {
695 dump_stream.Printf(" <could not be read>\n");
696 } else {
697 DataExtractor extractor(data.GetBytes(), data.GetByteSize(),
698 map.GetByteOrder(), map.GetAddressByteSize());
699
700 DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
701 load_addr);
702
703 lldb::offset_t offset;
704
Thiébaud Weksteene40e7362020-10-28 15:03:00 +0100705 ptr = extractor.GetAddress(&offset);
Inna Palantff3f07a2019-07-11 16:15:26 -0700706
707 dump_stream.PutChar('\n');
708 }
709 }
710
711 if (m_temporary_allocation == LLDB_INVALID_ADDRESS) {
712 dump_stream.Printf("Points to process memory:\n");
713 } else {
714 dump_stream.Printf("Temporary allocation:\n");
715 }
716
717 if (ptr == LLDB_INVALID_ADDRESS) {
718 dump_stream.Printf(" <could not be be found>\n");
719 } else {
720 DataBufferHeap data(m_temporary_allocation_size, 0);
721
722 map.ReadMemory(data.GetBytes(), m_temporary_allocation,
723 m_temporary_allocation_size, err);
724
725 if (!err.Success()) {
726 dump_stream.Printf(" <could not be read>\n");
727 } else {
728 DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
729 load_addr);
730
731 dump_stream.PutChar('\n');
732 }
733 }
734
735 log->PutString(dump_stream.GetString());
736 }
737
738 void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {
739 if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
740 Status free_error;
741
742 map.Free(m_temporary_allocation, free_error);
743
744 m_temporary_allocation = LLDB_INVALID_ADDRESS;
745 m_temporary_allocation_size = 0;
746 }
747 }
748
749private:
750 lldb::VariableSP m_variable_sp;
751 bool m_is_reference;
752 lldb::addr_t m_temporary_allocation;
753 size_t m_temporary_allocation_size;
754 lldb::DataBufferSP m_original_data;
755};
756
757uint32_t Materializer::AddVariable(lldb::VariableSP &variable_sp, Status &err) {
758 EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
Thiébaud Weksteene40e7362020-10-28 15:03:00 +0100759 *iter = std::make_unique<EntityVariable>(variable_sp);
Inna Palantff3f07a2019-07-11 16:15:26 -0700760 uint32_t ret = AddStructMember(**iter);
761 (*iter)->SetOffset(ret);
762 return ret;
763}
764
765class EntityResultVariable : public Materializer::Entity {
766public:
767 EntityResultVariable(const CompilerType &type, bool is_program_reference,
768 bool keep_in_memory,
769 Materializer::PersistentVariableDelegate *delegate)
770 : Entity(), m_type(type), m_is_program_reference(is_program_reference),
771 m_keep_in_memory(keep_in_memory),
772 m_temporary_allocation(LLDB_INVALID_ADDRESS),
773 m_temporary_allocation_size(0), m_delegate(delegate) {
774 // Hard-coding to maximum size of a pointer since all results are
775 // materialized by reference
776 m_size = 8;
777 m_alignment = 8;
778 }
779
780 void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
781 lldb::addr_t process_address, Status &err) override {
782 if (!m_is_program_reference) {
783 if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
784 err.SetErrorString("Trying to create a temporary region for the result "
785 "but one exists");
786 return;
787 }
788
789 const lldb::addr_t load_addr = process_address + m_offset;
790
Thiébaud Weksteene40e7362020-10-28 15:03:00 +0100791 ExecutionContextScope *exe_scope = frame_sp.get();
792 if (!exe_scope)
793 exe_scope = map.GetBestExecutionContextScope();
Inna Palantff3f07a2019-07-11 16:15:26 -0700794
795 llvm::Optional<uint64_t> byte_size = m_type.GetByteSize(exe_scope);
796 if (!byte_size) {
Chris Wailesbcf972c2021-10-21 11:03:28 -0700797 err.SetErrorStringWithFormat("can't get size of type \"%s\"",
798 m_type.GetTypeName().AsCString());
Inna Palantff3f07a2019-07-11 16:15:26 -0700799 return;
800 }
Inna Palantff3f07a2019-07-11 16:15:26 -0700801
Jeff Vander Stoep247d86b2020-08-11 14:27:44 +0200802 llvm::Optional<size_t> opt_bit_align = m_type.GetTypeBitAlign(exe_scope);
803 if (!opt_bit_align) {
Chris Wailesbcf972c2021-10-21 11:03:28 -0700804 err.SetErrorStringWithFormat("can't get the alignment of type \"%s\"",
805 m_type.GetTypeName().AsCString());
Jeff Vander Stoep247d86b2020-08-11 14:27:44 +0200806 return;
807 }
808
809 size_t byte_align = (*opt_bit_align + 7) / 8;
Inna Palantff3f07a2019-07-11 16:15:26 -0700810
811 Status alloc_error;
812 const bool zero_memory = true;
813
814 m_temporary_allocation = map.Malloc(
815 *byte_size, byte_align,
816 lldb::ePermissionsReadable | lldb::ePermissionsWritable,
817 IRMemoryMap::eAllocationPolicyMirror, zero_memory, alloc_error);
818 m_temporary_allocation_size = *byte_size;
819
820 if (!alloc_error.Success()) {
821 err.SetErrorStringWithFormat(
822 "couldn't allocate a temporary region for the result: %s",
823 alloc_error.AsCString());
824 return;
825 }
826
827 Status pointer_write_error;
828
829 map.WritePointerToMemory(load_addr, m_temporary_allocation,
830 pointer_write_error);
831
832 if (!pointer_write_error.Success()) {
833 err.SetErrorStringWithFormat("couldn't write the address of the "
834 "temporary region for the result: %s",
835 pointer_write_error.AsCString());
836 }
837 }
838 }
839
840 void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
841 lldb::addr_t process_address, lldb::addr_t frame_top,
842 lldb::addr_t frame_bottom, Status &err) override {
843 err.Clear();
844
Thiébaud Weksteene40e7362020-10-28 15:03:00 +0100845 ExecutionContextScope *exe_scope = frame_sp.get();
846 if (!exe_scope)
847 exe_scope = map.GetBestExecutionContextScope();
Inna Palantff3f07a2019-07-11 16:15:26 -0700848
849 if (!exe_scope) {
850 err.SetErrorString("Couldn't dematerialize a result variable: invalid "
851 "execution context scope");
852 return;
853 }
854
855 lldb::addr_t address;
856 Status read_error;
857 const lldb::addr_t load_addr = process_address + m_offset;
858
859 map.ReadPointerFromMemory(&address, load_addr, read_error);
860
861 if (!read_error.Success()) {
862 err.SetErrorString("Couldn't dematerialize a result variable: couldn't "
863 "read its address");
864 return;
865 }
866
867 lldb::TargetSP target_sp = exe_scope->CalculateTarget();
868
869 if (!target_sp) {
870 err.SetErrorString("Couldn't dematerialize a result variable: no target");
871 return;
872 }
873
Jeff Vander Stoep247d86b2020-08-11 14:27:44 +0200874 auto type_system_or_err =
875 target_sp->GetScratchTypeSystemForLanguage(m_type.GetMinimumLanguage());
Inna Palantff3f07a2019-07-11 16:15:26 -0700876
Jeff Vander Stoep247d86b2020-08-11 14:27:44 +0200877 if (auto error = type_system_or_err.takeError()) {
Inna Palantff3f07a2019-07-11 16:15:26 -0700878 err.SetErrorStringWithFormat("Couldn't dematerialize a result variable: "
879 "couldn't get the corresponding type "
880 "system: %s",
Jeff Vander Stoep247d86b2020-08-11 14:27:44 +0200881 llvm::toString(std::move(error)).c_str());
Inna Palantff3f07a2019-07-11 16:15:26 -0700882 return;
883 }
Inna Palantff3f07a2019-07-11 16:15:26 -0700884 PersistentExpressionState *persistent_state =
Jeff Vander Stoep247d86b2020-08-11 14:27:44 +0200885 type_system_or_err->GetPersistentExpressionState();
Inna Palantff3f07a2019-07-11 16:15:26 -0700886
887 if (!persistent_state) {
888 err.SetErrorString("Couldn't dematerialize a result variable: "
889 "corresponding type system doesn't handle persistent "
890 "variables");
891 return;
892 }
893
Thiébaud Weksteene40e7362020-10-28 15:03:00 +0100894 ConstString name = m_delegate
895 ? m_delegate->GetName()
896 : persistent_state->GetNextPersistentVariableName();
Inna Palantff3f07a2019-07-11 16:15:26 -0700897
898 lldb::ExpressionVariableSP ret = persistent_state->CreatePersistentVariable(
899 exe_scope, name, m_type, map.GetByteOrder(), map.GetAddressByteSize());
900
901 if (!ret) {
902 err.SetErrorStringWithFormat("couldn't dematerialize a result variable: "
903 "failed to make persistent variable %s",
904 name.AsCString());
905 return;
906 }
907
908 lldb::ProcessSP process_sp =
909 map.GetBestExecutionContextScope()->CalculateProcess();
910
911 if (m_delegate) {
912 m_delegate->DidDematerialize(ret);
913 }
914
915 bool can_persist =
916 (m_is_program_reference && process_sp && process_sp->CanJIT() &&
917 !(address >= frame_bottom && address < frame_top));
918
919 if (can_persist && m_keep_in_memory) {
920 ret->m_live_sp = ValueObjectConstResult::Create(exe_scope, m_type, name,
921 address, eAddressTypeLoad,
922 map.GetAddressByteSize());
923 }
924
925 ret->ValueUpdated();
926
Chris Wailese3116c42021-07-13 14:40:48 -0700927 const size_t pvar_byte_size = ret->GetByteSize().getValueOr(0);
Inna Palantff3f07a2019-07-11 16:15:26 -0700928 uint8_t *pvar_data = ret->GetValueBytes();
929
930 map.ReadMemory(pvar_data, address, pvar_byte_size, read_error);
931
932 if (!read_error.Success()) {
933 err.SetErrorString(
934 "Couldn't dematerialize a result variable: couldn't read its memory");
935 return;
936 }
937
938 if (!can_persist || !m_keep_in_memory) {
939 ret->m_flags |= ExpressionVariable::EVNeedsAllocation;
940
941 if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
942 Status free_error;
943 map.Free(m_temporary_allocation, free_error);
944 }
945 } else {
946 ret->m_flags |= ExpressionVariable::EVIsLLDBAllocated;
947 }
948
949 m_temporary_allocation = LLDB_INVALID_ADDRESS;
950 m_temporary_allocation_size = 0;
951 }
952
953 void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
954 Log *log) override {
955 StreamString dump_stream;
956
957 const lldb::addr_t load_addr = process_address + m_offset;
958
959 dump_stream.Printf("0x%" PRIx64 ": EntityResultVariable\n", load_addr);
960
961 Status err;
962
963 lldb::addr_t ptr = LLDB_INVALID_ADDRESS;
964
965 {
966 dump_stream.Printf("Pointer:\n");
967
968 DataBufferHeap data(m_size, 0);
969
970 map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
971
972 if (!err.Success()) {
973 dump_stream.Printf(" <could not be read>\n");
974 } else {
975 DataExtractor extractor(data.GetBytes(), data.GetByteSize(),
976 map.GetByteOrder(), map.GetAddressByteSize());
977
978 DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
979 load_addr);
980
981 lldb::offset_t offset;
982
Thiébaud Weksteene40e7362020-10-28 15:03:00 +0100983 ptr = extractor.GetAddress(&offset);
Inna Palantff3f07a2019-07-11 16:15:26 -0700984
985 dump_stream.PutChar('\n');
986 }
987 }
988
989 if (m_temporary_allocation == LLDB_INVALID_ADDRESS) {
990 dump_stream.Printf("Points to process memory:\n");
991 } else {
992 dump_stream.Printf("Temporary allocation:\n");
993 }
994
995 if (ptr == LLDB_INVALID_ADDRESS) {
996 dump_stream.Printf(" <could not be be found>\n");
997 } else {
998 DataBufferHeap data(m_temporary_allocation_size, 0);
999
1000 map.ReadMemory(data.GetBytes(), m_temporary_allocation,
1001 m_temporary_allocation_size, err);
1002
1003 if (!err.Success()) {
1004 dump_stream.Printf(" <could not be read>\n");
1005 } else {
1006 DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
1007 load_addr);
1008
1009 dump_stream.PutChar('\n');
1010 }
1011 }
1012
1013 log->PutString(dump_stream.GetString());
1014 }
1015
1016 void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {
1017 if (!m_keep_in_memory && m_temporary_allocation != LLDB_INVALID_ADDRESS) {
1018 Status free_error;
1019
1020 map.Free(m_temporary_allocation, free_error);
1021 }
1022
1023 m_temporary_allocation = LLDB_INVALID_ADDRESS;
1024 m_temporary_allocation_size = 0;
1025 }
1026
1027private:
1028 CompilerType m_type;
1029 bool m_is_program_reference;
1030 bool m_keep_in_memory;
1031
1032 lldb::addr_t m_temporary_allocation;
1033 size_t m_temporary_allocation_size;
1034 Materializer::PersistentVariableDelegate *m_delegate;
1035};
1036
1037uint32_t Materializer::AddResultVariable(const CompilerType &type,
1038 bool is_program_reference,
1039 bool keep_in_memory,
1040 PersistentVariableDelegate *delegate,
1041 Status &err) {
1042 EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
Thiébaud Weksteene40e7362020-10-28 15:03:00 +01001043 *iter = std::make_unique<EntityResultVariable>(type, is_program_reference,
1044 keep_in_memory, delegate);
Inna Palantff3f07a2019-07-11 16:15:26 -07001045 uint32_t ret = AddStructMember(**iter);
1046 (*iter)->SetOffset(ret);
1047 return ret;
1048}
1049
1050class EntitySymbol : public Materializer::Entity {
1051public:
1052 EntitySymbol(const Symbol &symbol) : Entity(), m_symbol(symbol) {
1053 // Hard-coding to maximum size of a symbol
1054 m_size = 8;
1055 m_alignment = 8;
1056 }
1057
1058 void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1059 lldb::addr_t process_address, Status &err) override {
1060 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
1061
1062 const lldb::addr_t load_addr = process_address + m_offset;
1063
1064 if (log) {
Jeff Vander Stoep247d86b2020-08-11 14:27:44 +02001065 LLDB_LOGF(log,
1066 "EntitySymbol::Materialize [address = 0x%" PRIx64
1067 ", m_symbol = %s]",
1068 (uint64_t)load_addr, m_symbol.GetName().AsCString());
Inna Palantff3f07a2019-07-11 16:15:26 -07001069 }
1070
1071 const Address sym_address = m_symbol.GetAddress();
1072
Thiébaud Weksteene40e7362020-10-28 15:03:00 +01001073 ExecutionContextScope *exe_scope = frame_sp.get();
1074 if (!exe_scope)
1075 exe_scope = map.GetBestExecutionContextScope();
Inna Palantff3f07a2019-07-11 16:15:26 -07001076
1077 lldb::TargetSP target_sp;
1078
1079 if (exe_scope)
1080 target_sp = map.GetBestExecutionContextScope()->CalculateTarget();
1081
1082 if (!target_sp) {
1083 err.SetErrorStringWithFormat(
1084 "couldn't resolve symbol %s because there is no target",
1085 m_symbol.GetName().AsCString());
1086 return;
1087 }
1088
1089 lldb::addr_t resolved_address = sym_address.GetLoadAddress(target_sp.get());
1090
1091 if (resolved_address == LLDB_INVALID_ADDRESS)
1092 resolved_address = sym_address.GetFileAddress();
1093
1094 Status pointer_write_error;
1095
1096 map.WritePointerToMemory(load_addr, resolved_address, pointer_write_error);
1097
1098 if (!pointer_write_error.Success()) {
1099 err.SetErrorStringWithFormat(
1100 "couldn't write the address of symbol %s: %s",
1101 m_symbol.GetName().AsCString(), pointer_write_error.AsCString());
1102 return;
1103 }
1104 }
1105
1106 void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1107 lldb::addr_t process_address, lldb::addr_t frame_top,
1108 lldb::addr_t frame_bottom, Status &err) override {
1109 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
1110
1111 const lldb::addr_t load_addr = process_address + m_offset;
1112
1113 if (log) {
Jeff Vander Stoep247d86b2020-08-11 14:27:44 +02001114 LLDB_LOGF(log,
1115 "EntitySymbol::Dematerialize [address = 0x%" PRIx64
1116 ", m_symbol = %s]",
1117 (uint64_t)load_addr, m_symbol.GetName().AsCString());
Inna Palantff3f07a2019-07-11 16:15:26 -07001118 }
1119
1120 // no work needs to be done
1121 }
1122
1123 void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
1124 Log *log) override {
1125 StreamString dump_stream;
1126
1127 Status err;
1128
1129 const lldb::addr_t load_addr = process_address + m_offset;
1130
1131 dump_stream.Printf("0x%" PRIx64 ": EntitySymbol (%s)\n", load_addr,
1132 m_symbol.GetName().AsCString());
1133
1134 {
1135 dump_stream.Printf("Pointer:\n");
1136
1137 DataBufferHeap data(m_size, 0);
1138
1139 map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
1140
1141 if (!err.Success()) {
1142 dump_stream.Printf(" <could not be read>\n");
1143 } else {
1144 DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
1145 load_addr);
1146
1147 dump_stream.PutChar('\n');
1148 }
1149 }
1150
1151 log->PutString(dump_stream.GetString());
1152 }
1153
1154 void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {}
1155
1156private:
1157 Symbol m_symbol;
1158};
1159
1160uint32_t Materializer::AddSymbol(const Symbol &symbol_sp, Status &err) {
1161 EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
Thiébaud Weksteene40e7362020-10-28 15:03:00 +01001162 *iter = std::make_unique<EntitySymbol>(symbol_sp);
Inna Palantff3f07a2019-07-11 16:15:26 -07001163 uint32_t ret = AddStructMember(**iter);
1164 (*iter)->SetOffset(ret);
1165 return ret;
1166}
1167
1168class EntityRegister : public Materializer::Entity {
1169public:
1170 EntityRegister(const RegisterInfo &register_info)
1171 : Entity(), m_register_info(register_info) {
1172 // Hard-coding alignment conservatively
1173 m_size = m_register_info.byte_size;
1174 m_alignment = m_register_info.byte_size;
1175 }
1176
1177 void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1178 lldb::addr_t process_address, Status &err) override {
1179 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
1180
1181 const lldb::addr_t load_addr = process_address + m_offset;
1182
1183 if (log) {
Jeff Vander Stoep247d86b2020-08-11 14:27:44 +02001184 LLDB_LOGF(log,
1185 "EntityRegister::Materialize [address = 0x%" PRIx64
1186 ", m_register_info = %s]",
1187 (uint64_t)load_addr, m_register_info.name);
Inna Palantff3f07a2019-07-11 16:15:26 -07001188 }
1189
1190 RegisterValue reg_value;
1191
1192 if (!frame_sp.get()) {
1193 err.SetErrorStringWithFormat(
1194 "couldn't materialize register %s without a stack frame",
1195 m_register_info.name);
1196 return;
1197 }
1198
1199 lldb::RegisterContextSP reg_context_sp = frame_sp->GetRegisterContext();
1200
1201 if (!reg_context_sp->ReadRegister(&m_register_info, reg_value)) {
1202 err.SetErrorStringWithFormat("couldn't read the value of register %s",
1203 m_register_info.name);
1204 return;
1205 }
1206
1207 DataExtractor register_data;
1208
1209 if (!reg_value.GetData(register_data)) {
1210 err.SetErrorStringWithFormat("couldn't get the data for register %s",
1211 m_register_info.name);
1212 return;
1213 }
1214
1215 if (register_data.GetByteSize() != m_register_info.byte_size) {
1216 err.SetErrorStringWithFormat(
1217 "data for register %s had size %llu but we expected %llu",
1218 m_register_info.name, (unsigned long long)register_data.GetByteSize(),
1219 (unsigned long long)m_register_info.byte_size);
1220 return;
1221 }
1222
Chih-Hung Hsieh08600532019-12-19 15:55:38 -08001223 m_register_contents = std::make_shared<DataBufferHeap>(
1224 register_data.GetDataStart(), register_data.GetByteSize());
Inna Palantff3f07a2019-07-11 16:15:26 -07001225
1226 Status write_error;
1227
1228 map.WriteMemory(load_addr, register_data.GetDataStart(),
1229 register_data.GetByteSize(), write_error);
1230
1231 if (!write_error.Success()) {
1232 err.SetErrorStringWithFormat(
1233 "couldn't write the contents of register %s: %s",
1234 m_register_info.name, write_error.AsCString());
1235 return;
1236 }
1237 }
1238
1239 void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1240 lldb::addr_t process_address, lldb::addr_t frame_top,
1241 lldb::addr_t frame_bottom, Status &err) override {
1242 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
1243
1244 const lldb::addr_t load_addr = process_address + m_offset;
1245
1246 if (log) {
Jeff Vander Stoep247d86b2020-08-11 14:27:44 +02001247 LLDB_LOGF(log,
1248 "EntityRegister::Dematerialize [address = 0x%" PRIx64
1249 ", m_register_info = %s]",
1250 (uint64_t)load_addr, m_register_info.name);
Inna Palantff3f07a2019-07-11 16:15:26 -07001251 }
1252
1253 Status extract_error;
1254
1255 DataExtractor register_data;
1256
1257 if (!frame_sp.get()) {
1258 err.SetErrorStringWithFormat(
1259 "couldn't dematerialize register %s without a stack frame",
1260 m_register_info.name);
1261 return;
1262 }
1263
1264 lldb::RegisterContextSP reg_context_sp = frame_sp->GetRegisterContext();
1265
1266 map.GetMemoryData(register_data, load_addr, m_register_info.byte_size,
1267 extract_error);
1268
1269 if (!extract_error.Success()) {
1270 err.SetErrorStringWithFormat("couldn't get the data for register %s: %s",
1271 m_register_info.name,
1272 extract_error.AsCString());
1273 return;
1274 }
1275
1276 if (!memcmp(register_data.GetDataStart(), m_register_contents->GetBytes(),
1277 register_data.GetByteSize())) {
1278 // No write required, and in particular we avoid errors if the register
1279 // wasn't writable
1280
1281 m_register_contents.reset();
1282 return;
1283 }
1284
1285 m_register_contents.reset();
1286
Chris Wailese3116c42021-07-13 14:40:48 -07001287 RegisterValue register_value(register_data.GetData(),
1288 register_data.GetByteOrder());
Inna Palantff3f07a2019-07-11 16:15:26 -07001289
1290 if (!reg_context_sp->WriteRegister(&m_register_info, register_value)) {
1291 err.SetErrorStringWithFormat("couldn't write the value of register %s",
1292 m_register_info.name);
1293 return;
1294 }
1295 }
1296
1297 void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
1298 Log *log) override {
1299 StreamString dump_stream;
1300
1301 Status err;
1302
1303 const lldb::addr_t load_addr = process_address + m_offset;
1304
1305 dump_stream.Printf("0x%" PRIx64 ": EntityRegister (%s)\n", load_addr,
1306 m_register_info.name);
1307
1308 {
1309 dump_stream.Printf("Value:\n");
1310
1311 DataBufferHeap data(m_size, 0);
1312
1313 map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
1314
1315 if (!err.Success()) {
1316 dump_stream.Printf(" <could not be read>\n");
1317 } else {
1318 DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
1319 load_addr);
1320
1321 dump_stream.PutChar('\n');
1322 }
1323 }
1324
1325 log->PutString(dump_stream.GetString());
1326 }
1327
1328 void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {}
1329
1330private:
1331 RegisterInfo m_register_info;
1332 lldb::DataBufferSP m_register_contents;
1333};
1334
1335uint32_t Materializer::AddRegister(const RegisterInfo &register_info,
1336 Status &err) {
1337 EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
Thiébaud Weksteene40e7362020-10-28 15:03:00 +01001338 *iter = std::make_unique<EntityRegister>(register_info);
Inna Palantff3f07a2019-07-11 16:15:26 -07001339 uint32_t ret = AddStructMember(**iter);
1340 (*iter)->SetOffset(ret);
1341 return ret;
1342}
1343
Inna Palantff3f07a2019-07-11 16:15:26 -07001344Materializer::~Materializer() {
1345 DematerializerSP dematerializer_sp = m_dematerializer_wp.lock();
1346
1347 if (dematerializer_sp)
1348 dematerializer_sp->Wipe();
1349}
1350
1351Materializer::DematerializerSP
1352Materializer::Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1353 lldb::addr_t process_address, Status &error) {
1354 ExecutionContextScope *exe_scope = frame_sp.get();
Inna Palantff3f07a2019-07-11 16:15:26 -07001355 if (!exe_scope)
1356 exe_scope = map.GetBestExecutionContextScope();
1357
1358 DematerializerSP dematerializer_sp = m_dematerializer_wp.lock();
1359
1360 if (dematerializer_sp) {
1361 error.SetErrorToGenericError();
1362 error.SetErrorString("Couldn't materialize: already materialized");
1363 }
1364
1365 DematerializerSP ret(
1366 new Dematerializer(*this, frame_sp, map, process_address));
1367
1368 if (!exe_scope) {
1369 error.SetErrorToGenericError();
1370 error.SetErrorString("Couldn't materialize: target doesn't exist");
1371 }
1372
1373 for (EntityUP &entity_up : m_entities) {
1374 entity_up->Materialize(frame_sp, map, process_address, error);
1375
1376 if (!error.Success())
1377 return DematerializerSP();
1378 }
1379
1380 if (Log *log =
1381 lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)) {
Jeff Vander Stoep247d86b2020-08-11 14:27:44 +02001382 LLDB_LOGF(
1383 log,
Inna Palantff3f07a2019-07-11 16:15:26 -07001384 "Materializer::Materialize (frame_sp = %p, process_address = 0x%" PRIx64
1385 ") materialized:",
1386 static_cast<void *>(frame_sp.get()), process_address);
1387 for (EntityUP &entity_up : m_entities)
1388 entity_up->DumpToLog(map, process_address, log);
1389 }
1390
1391 m_dematerializer_wp = ret;
1392
1393 return ret;
1394}
1395
1396void Materializer::Dematerializer::Dematerialize(Status &error,
1397 lldb::addr_t frame_bottom,
1398 lldb::addr_t frame_top) {
1399 lldb::StackFrameSP frame_sp;
1400
1401 lldb::ThreadSP thread_sp = m_thread_wp.lock();
1402 if (thread_sp)
1403 frame_sp = thread_sp->GetFrameWithStackID(m_stack_id);
1404
Thiébaud Weksteene40e7362020-10-28 15:03:00 +01001405 ExecutionContextScope *exe_scope = frame_sp.get();
1406 if (!exe_scope)
1407 exe_scope = m_map->GetBestExecutionContextScope();
Inna Palantff3f07a2019-07-11 16:15:26 -07001408
1409 if (!IsValid()) {
1410 error.SetErrorToGenericError();
1411 error.SetErrorString("Couldn't dematerialize: invalid dematerializer");
1412 }
1413
1414 if (!exe_scope) {
1415 error.SetErrorToGenericError();
1416 error.SetErrorString("Couldn't dematerialize: target is gone");
1417 } else {
1418 if (Log *log =
1419 lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS)) {
Jeff Vander Stoep247d86b2020-08-11 14:27:44 +02001420 LLDB_LOGF(log,
1421 "Materializer::Dematerialize (frame_sp = %p, process_address "
1422 "= 0x%" PRIx64 ") about to dematerialize:",
1423 static_cast<void *>(frame_sp.get()), m_process_address);
Inna Palantff3f07a2019-07-11 16:15:26 -07001424 for (EntityUP &entity_up : m_materializer->m_entities)
1425 entity_up->DumpToLog(*m_map, m_process_address, log);
1426 }
1427
1428 for (EntityUP &entity_up : m_materializer->m_entities) {
1429 entity_up->Dematerialize(frame_sp, *m_map, m_process_address, frame_top,
1430 frame_bottom, error);
1431
1432 if (!error.Success())
1433 break;
1434 }
1435 }
1436
1437 Wipe();
1438}
1439
1440void Materializer::Dematerializer::Wipe() {
1441 if (!IsValid())
1442 return;
1443
1444 for (EntityUP &entity_up : m_materializer->m_entities) {
1445 entity_up->Wipe(*m_map, m_process_address);
1446 }
1447
1448 m_materializer = nullptr;
1449 m_map = nullptr;
1450 m_process_address = LLDB_INVALID_ADDRESS;
1451}
1452
1453Materializer::PersistentVariableDelegate::~PersistentVariableDelegate() =
1454 default;