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