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