1dda28197Spatrick //===-- Materializer.cpp --------------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick
9061da546Spatrick #include "lldb/Expression/Materializer.h"
10061da546Spatrick #include "lldb/Core/DumpDataExtractor.h"
11061da546Spatrick #include "lldb/Core/ValueObjectConstResult.h"
12061da546Spatrick #include "lldb/Core/ValueObjectVariable.h"
13061da546Spatrick #include "lldb/Expression/ExpressionVariable.h"
14061da546Spatrick #include "lldb/Symbol/Symbol.h"
15061da546Spatrick #include "lldb/Symbol/Type.h"
16061da546Spatrick #include "lldb/Symbol/Variable.h"
17061da546Spatrick #include "lldb/Target/ExecutionContext.h"
18061da546Spatrick #include "lldb/Target/RegisterContext.h"
19061da546Spatrick #include "lldb/Target/StackFrame.h"
20061da546Spatrick #include "lldb/Target/Target.h"
21061da546Spatrick #include "lldb/Target/Thread.h"
22*f6aab3d8Srobert #include "lldb/Utility/LLDBLog.h"
23061da546Spatrick #include "lldb/Utility/Log.h"
24061da546Spatrick #include "lldb/Utility/RegisterValue.h"
25*f6aab3d8Srobert #include "lldb/lldb-forward.h"
26061da546Spatrick
27061da546Spatrick #include <memory>
28*f6aab3d8Srobert #include <optional>
29061da546Spatrick
30061da546Spatrick using namespace lldb_private;
31061da546Spatrick
32*f6aab3d8Srobert // FIXME: these should be retrieved from the target
33*f6aab3d8Srobert // instead of being hard-coded. Currently we
34*f6aab3d8Srobert // assume that persistent vars are materialized
35*f6aab3d8Srobert // as references, and thus pick the size of a
36*f6aab3d8Srobert // 64-bit pointer.
37*f6aab3d8Srobert static constexpr uint32_t g_default_var_alignment = 8;
38*f6aab3d8Srobert static constexpr uint32_t g_default_var_byte_size = 8;
39*f6aab3d8Srobert
AddStructMember(Entity & entity)40061da546Spatrick uint32_t Materializer::AddStructMember(Entity &entity) {
41061da546Spatrick uint32_t size = entity.GetSize();
42061da546Spatrick uint32_t alignment = entity.GetAlignment();
43061da546Spatrick
44061da546Spatrick uint32_t ret;
45061da546Spatrick
46061da546Spatrick if (m_current_offset == 0)
47061da546Spatrick m_struct_alignment = alignment;
48061da546Spatrick
49061da546Spatrick if (m_current_offset % alignment)
50061da546Spatrick m_current_offset += (alignment - (m_current_offset % alignment));
51061da546Spatrick
52061da546Spatrick ret = m_current_offset;
53061da546Spatrick
54061da546Spatrick m_current_offset += size;
55061da546Spatrick
56061da546Spatrick return ret;
57061da546Spatrick }
58061da546Spatrick
59061da546Spatrick class EntityPersistentVariable : public Materializer::Entity {
60061da546Spatrick public:
EntityPersistentVariable(lldb::ExpressionVariableSP & persistent_variable_sp,Materializer::PersistentVariableDelegate * delegate)61061da546Spatrick EntityPersistentVariable(lldb::ExpressionVariableSP &persistent_variable_sp,
62061da546Spatrick Materializer::PersistentVariableDelegate *delegate)
63061da546Spatrick : Entity(), m_persistent_variable_sp(persistent_variable_sp),
64061da546Spatrick m_delegate(delegate) {
65061da546Spatrick // Hard-coding to maximum size of a pointer since persistent variables are
66061da546Spatrick // materialized by reference
67*f6aab3d8Srobert m_size = g_default_var_byte_size;
68*f6aab3d8Srobert m_alignment = g_default_var_alignment;
69061da546Spatrick }
70061da546Spatrick
MakeAllocation(IRMemoryMap & map,Status & err)71061da546Spatrick void MakeAllocation(IRMemoryMap &map, Status &err) {
72*f6aab3d8Srobert Log *log = GetLog(LLDBLog::Expressions);
73061da546Spatrick
74061da546Spatrick // Allocate a spare memory area to store the persistent variable's
75061da546Spatrick // contents.
76061da546Spatrick
77061da546Spatrick Status allocate_error;
78061da546Spatrick const bool zero_memory = false;
79061da546Spatrick
80061da546Spatrick lldb::addr_t mem = map.Malloc(
81*f6aab3d8Srobert m_persistent_variable_sp->GetByteSize().value_or(0), 8,
82061da546Spatrick lldb::ePermissionsReadable | lldb::ePermissionsWritable,
83061da546Spatrick IRMemoryMap::eAllocationPolicyMirror, zero_memory, allocate_error);
84061da546Spatrick
85061da546Spatrick if (!allocate_error.Success()) {
86061da546Spatrick err.SetErrorStringWithFormat(
87061da546Spatrick "couldn't allocate a memory area to store %s: %s",
88061da546Spatrick m_persistent_variable_sp->GetName().GetCString(),
89061da546Spatrick allocate_error.AsCString());
90061da546Spatrick return;
91061da546Spatrick }
92061da546Spatrick
93061da546Spatrick LLDB_LOGF(log, "Allocated %s (0x%" PRIx64 ") successfully",
94061da546Spatrick m_persistent_variable_sp->GetName().GetCString(), mem);
95061da546Spatrick
96061da546Spatrick // Put the location of the spare memory into the live data of the
97061da546Spatrick // ValueObject.
98061da546Spatrick
99061da546Spatrick m_persistent_variable_sp->m_live_sp = ValueObjectConstResult::Create(
100061da546Spatrick map.GetBestExecutionContextScope(),
101061da546Spatrick m_persistent_variable_sp->GetCompilerType(),
102061da546Spatrick m_persistent_variable_sp->GetName(), mem, eAddressTypeLoad,
103061da546Spatrick map.GetAddressByteSize());
104061da546Spatrick
105061da546Spatrick // Clear the flag if the variable will never be deallocated.
106061da546Spatrick
107061da546Spatrick if (m_persistent_variable_sp->m_flags &
108061da546Spatrick ExpressionVariable::EVKeepInTarget) {
109061da546Spatrick Status leak_error;
110061da546Spatrick map.Leak(mem, leak_error);
111061da546Spatrick m_persistent_variable_sp->m_flags &=
112061da546Spatrick ~ExpressionVariable::EVNeedsAllocation;
113061da546Spatrick }
114061da546Spatrick
115061da546Spatrick // Write the contents of the variable to the area.
116061da546Spatrick
117061da546Spatrick Status write_error;
118061da546Spatrick
119061da546Spatrick map.WriteMemory(mem, m_persistent_variable_sp->GetValueBytes(),
120*f6aab3d8Srobert m_persistent_variable_sp->GetByteSize().value_or(0),
121be691f3bSpatrick write_error);
122061da546Spatrick
123061da546Spatrick if (!write_error.Success()) {
124061da546Spatrick err.SetErrorStringWithFormat(
125061da546Spatrick "couldn't write %s to the target: %s",
126061da546Spatrick m_persistent_variable_sp->GetName().AsCString(),
127061da546Spatrick write_error.AsCString());
128061da546Spatrick return;
129061da546Spatrick }
130061da546Spatrick }
131061da546Spatrick
DestroyAllocation(IRMemoryMap & map,Status & err)132061da546Spatrick void DestroyAllocation(IRMemoryMap &map, Status &err) {
133061da546Spatrick Status deallocate_error;
134061da546Spatrick
135061da546Spatrick map.Free((lldb::addr_t)m_persistent_variable_sp->m_live_sp->GetValue()
136061da546Spatrick .GetScalar()
137061da546Spatrick .ULongLong(),
138061da546Spatrick deallocate_error);
139061da546Spatrick
140061da546Spatrick m_persistent_variable_sp->m_live_sp.reset();
141061da546Spatrick
142061da546Spatrick if (!deallocate_error.Success()) {
143061da546Spatrick err.SetErrorStringWithFormat(
144061da546Spatrick "couldn't deallocate memory for %s: %s",
145061da546Spatrick m_persistent_variable_sp->GetName().GetCString(),
146061da546Spatrick deallocate_error.AsCString());
147061da546Spatrick }
148061da546Spatrick }
149061da546Spatrick
Materialize(lldb::StackFrameSP & frame_sp,IRMemoryMap & map,lldb::addr_t process_address,Status & err)150061da546Spatrick void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
151061da546Spatrick lldb::addr_t process_address, Status &err) override {
152*f6aab3d8Srobert Log *log = GetLog(LLDBLog::Expressions);
153061da546Spatrick
154061da546Spatrick const lldb::addr_t load_addr = process_address + m_offset;
155061da546Spatrick
156061da546Spatrick if (log) {
157061da546Spatrick LLDB_LOGF(log,
158061da546Spatrick "EntityPersistentVariable::Materialize [address = 0x%" PRIx64
159061da546Spatrick ", m_name = %s, m_flags = 0x%hx]",
160061da546Spatrick (uint64_t)load_addr,
161061da546Spatrick m_persistent_variable_sp->GetName().AsCString(),
162061da546Spatrick m_persistent_variable_sp->m_flags);
163061da546Spatrick }
164061da546Spatrick
165061da546Spatrick if (m_persistent_variable_sp->m_flags &
166061da546Spatrick ExpressionVariable::EVNeedsAllocation) {
167061da546Spatrick MakeAllocation(map, err);
168061da546Spatrick m_persistent_variable_sp->m_flags |=
169061da546Spatrick ExpressionVariable::EVIsLLDBAllocated;
170061da546Spatrick
171061da546Spatrick if (!err.Success())
172061da546Spatrick return;
173061da546Spatrick }
174061da546Spatrick
175061da546Spatrick if ((m_persistent_variable_sp->m_flags &
176061da546Spatrick ExpressionVariable::EVIsProgramReference &&
177061da546Spatrick m_persistent_variable_sp->m_live_sp) ||
178061da546Spatrick m_persistent_variable_sp->m_flags &
179061da546Spatrick ExpressionVariable::EVIsLLDBAllocated) {
180061da546Spatrick Status write_error;
181061da546Spatrick
182061da546Spatrick map.WriteScalarToMemory(
183061da546Spatrick load_addr,
184061da546Spatrick m_persistent_variable_sp->m_live_sp->GetValue().GetScalar(),
185061da546Spatrick map.GetAddressByteSize(), write_error);
186061da546Spatrick
187061da546Spatrick if (!write_error.Success()) {
188061da546Spatrick err.SetErrorStringWithFormat(
189061da546Spatrick "couldn't write the location of %s to memory: %s",
190061da546Spatrick m_persistent_variable_sp->GetName().AsCString(),
191061da546Spatrick write_error.AsCString());
192061da546Spatrick }
193061da546Spatrick } else {
194061da546Spatrick err.SetErrorStringWithFormat(
195061da546Spatrick "no materialization happened for persistent variable %s",
196061da546Spatrick m_persistent_variable_sp->GetName().AsCString());
197061da546Spatrick return;
198061da546Spatrick }
199061da546Spatrick }
200061da546Spatrick
Dematerialize(lldb::StackFrameSP & frame_sp,IRMemoryMap & map,lldb::addr_t process_address,lldb::addr_t frame_top,lldb::addr_t frame_bottom,Status & err)201061da546Spatrick void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
202061da546Spatrick lldb::addr_t process_address, lldb::addr_t frame_top,
203061da546Spatrick lldb::addr_t frame_bottom, Status &err) override {
204*f6aab3d8Srobert Log *log = GetLog(LLDBLog::Expressions);
205061da546Spatrick
206061da546Spatrick const lldb::addr_t load_addr = process_address + m_offset;
207061da546Spatrick
208061da546Spatrick if (log) {
209061da546Spatrick LLDB_LOGF(log,
210061da546Spatrick "EntityPersistentVariable::Dematerialize [address = 0x%" PRIx64
211061da546Spatrick ", m_name = %s, m_flags = 0x%hx]",
212061da546Spatrick (uint64_t)process_address + m_offset,
213061da546Spatrick m_persistent_variable_sp->GetName().AsCString(),
214061da546Spatrick m_persistent_variable_sp->m_flags);
215061da546Spatrick }
216061da546Spatrick
217061da546Spatrick if (m_delegate) {
218061da546Spatrick m_delegate->DidDematerialize(m_persistent_variable_sp);
219061da546Spatrick }
220061da546Spatrick
221061da546Spatrick if ((m_persistent_variable_sp->m_flags &
222061da546Spatrick ExpressionVariable::EVIsLLDBAllocated) ||
223061da546Spatrick (m_persistent_variable_sp->m_flags &
224061da546Spatrick ExpressionVariable::EVIsProgramReference)) {
225061da546Spatrick if (m_persistent_variable_sp->m_flags &
226061da546Spatrick ExpressionVariable::EVIsProgramReference &&
227061da546Spatrick !m_persistent_variable_sp->m_live_sp) {
228061da546Spatrick // If the reference comes from the program, then the
229061da546Spatrick // ClangExpressionVariable's live variable data hasn't been set up yet.
230061da546Spatrick // Do this now.
231061da546Spatrick
232061da546Spatrick lldb::addr_t location;
233061da546Spatrick Status read_error;
234061da546Spatrick
235061da546Spatrick map.ReadPointerFromMemory(&location, load_addr, read_error);
236061da546Spatrick
237061da546Spatrick if (!read_error.Success()) {
238061da546Spatrick err.SetErrorStringWithFormat(
239061da546Spatrick "couldn't read the address of program-allocated variable %s: %s",
240061da546Spatrick m_persistent_variable_sp->GetName().GetCString(),
241061da546Spatrick read_error.AsCString());
242061da546Spatrick return;
243061da546Spatrick }
244061da546Spatrick
245061da546Spatrick m_persistent_variable_sp->m_live_sp = ValueObjectConstResult::Create(
246061da546Spatrick map.GetBestExecutionContextScope(),
247061da546Spatrick m_persistent_variable_sp.get()->GetCompilerType(),
248061da546Spatrick m_persistent_variable_sp->GetName(), location, eAddressTypeLoad,
249*f6aab3d8Srobert m_persistent_variable_sp->GetByteSize().value_or(0));
250061da546Spatrick
251061da546Spatrick if (frame_top != LLDB_INVALID_ADDRESS &&
252061da546Spatrick frame_bottom != LLDB_INVALID_ADDRESS && location >= frame_bottom &&
253061da546Spatrick location <= frame_top) {
254061da546Spatrick // If the variable is resident in the stack frame created by the
255061da546Spatrick // expression, then it cannot be relied upon to stay around. We
256061da546Spatrick // treat it as needing reallocation.
257061da546Spatrick m_persistent_variable_sp->m_flags |=
258061da546Spatrick ExpressionVariable::EVIsLLDBAllocated;
259061da546Spatrick m_persistent_variable_sp->m_flags |=
260061da546Spatrick ExpressionVariable::EVNeedsAllocation;
261061da546Spatrick m_persistent_variable_sp->m_flags |=
262061da546Spatrick ExpressionVariable::EVNeedsFreezeDry;
263061da546Spatrick m_persistent_variable_sp->m_flags &=
264061da546Spatrick ~ExpressionVariable::EVIsProgramReference;
265061da546Spatrick }
266061da546Spatrick }
267061da546Spatrick
268061da546Spatrick lldb::addr_t mem = m_persistent_variable_sp->m_live_sp->GetValue()
269061da546Spatrick .GetScalar()
270061da546Spatrick .ULongLong();
271061da546Spatrick
272061da546Spatrick if (!m_persistent_variable_sp->m_live_sp) {
273061da546Spatrick err.SetErrorStringWithFormat(
274061da546Spatrick "couldn't find the memory area used to store %s",
275061da546Spatrick m_persistent_variable_sp->GetName().GetCString());
276061da546Spatrick return;
277061da546Spatrick }
278061da546Spatrick
279061da546Spatrick if (m_persistent_variable_sp->m_live_sp->GetValue()
280061da546Spatrick .GetValueAddressType() != eAddressTypeLoad) {
281061da546Spatrick err.SetErrorStringWithFormat(
282061da546Spatrick "the address of the memory area for %s is in an incorrect format",
283061da546Spatrick m_persistent_variable_sp->GetName().GetCString());
284061da546Spatrick return;
285061da546Spatrick }
286061da546Spatrick
287061da546Spatrick if (m_persistent_variable_sp->m_flags &
288061da546Spatrick ExpressionVariable::EVNeedsFreezeDry ||
289061da546Spatrick m_persistent_variable_sp->m_flags &
290061da546Spatrick ExpressionVariable::EVKeepInTarget) {
291061da546Spatrick LLDB_LOGF(log, "Dematerializing %s from 0x%" PRIx64 " (size = %llu)",
292061da546Spatrick m_persistent_variable_sp->GetName().GetCString(),
293061da546Spatrick (uint64_t)mem,
294be691f3bSpatrick (unsigned long long)m_persistent_variable_sp->GetByteSize()
295*f6aab3d8Srobert .value_or(0));
296061da546Spatrick
297061da546Spatrick // Read the contents of the spare memory area
298061da546Spatrick
299061da546Spatrick m_persistent_variable_sp->ValueUpdated();
300061da546Spatrick
301061da546Spatrick Status read_error;
302061da546Spatrick
303061da546Spatrick map.ReadMemory(m_persistent_variable_sp->GetValueBytes(), mem,
304*f6aab3d8Srobert m_persistent_variable_sp->GetByteSize().value_or(0),
305*f6aab3d8Srobert read_error);
306061da546Spatrick
307061da546Spatrick if (!read_error.Success()) {
308061da546Spatrick err.SetErrorStringWithFormat(
309061da546Spatrick "couldn't read the contents of %s from memory: %s",
310061da546Spatrick m_persistent_variable_sp->GetName().GetCString(),
311061da546Spatrick read_error.AsCString());
312061da546Spatrick return;
313061da546Spatrick }
314061da546Spatrick
315061da546Spatrick m_persistent_variable_sp->m_flags &=
316061da546Spatrick ~ExpressionVariable::EVNeedsFreezeDry;
317061da546Spatrick }
318061da546Spatrick } else {
319061da546Spatrick err.SetErrorStringWithFormat(
320061da546Spatrick "no dematerialization happened for persistent variable %s",
321061da546Spatrick m_persistent_variable_sp->GetName().AsCString());
322061da546Spatrick return;
323061da546Spatrick }
324061da546Spatrick
325061da546Spatrick lldb::ProcessSP process_sp =
326061da546Spatrick map.GetBestExecutionContextScope()->CalculateProcess();
327061da546Spatrick if (!process_sp || !process_sp->CanJIT()) {
328061da546Spatrick // Allocations are not persistent so persistent variables cannot stay
329061da546Spatrick // materialized.
330061da546Spatrick
331061da546Spatrick m_persistent_variable_sp->m_flags |=
332061da546Spatrick ExpressionVariable::EVNeedsAllocation;
333061da546Spatrick
334061da546Spatrick DestroyAllocation(map, err);
335061da546Spatrick if (!err.Success())
336061da546Spatrick return;
337061da546Spatrick } else if (m_persistent_variable_sp->m_flags &
338061da546Spatrick ExpressionVariable::EVNeedsAllocation &&
339061da546Spatrick !(m_persistent_variable_sp->m_flags &
340061da546Spatrick ExpressionVariable::EVKeepInTarget)) {
341061da546Spatrick DestroyAllocation(map, err);
342061da546Spatrick if (!err.Success())
343061da546Spatrick return;
344061da546Spatrick }
345061da546Spatrick }
346061da546Spatrick
DumpToLog(IRMemoryMap & map,lldb::addr_t process_address,Log * log)347061da546Spatrick void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
348061da546Spatrick Log *log) override {
349061da546Spatrick StreamString dump_stream;
350061da546Spatrick
351061da546Spatrick Status err;
352061da546Spatrick
353061da546Spatrick const lldb::addr_t load_addr = process_address + m_offset;
354061da546Spatrick
355061da546Spatrick dump_stream.Printf("0x%" PRIx64 ": EntityPersistentVariable (%s)\n",
356061da546Spatrick load_addr,
357061da546Spatrick m_persistent_variable_sp->GetName().AsCString());
358061da546Spatrick
359061da546Spatrick {
360061da546Spatrick dump_stream.Printf("Pointer:\n");
361061da546Spatrick
362061da546Spatrick DataBufferHeap data(m_size, 0);
363061da546Spatrick
364061da546Spatrick map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
365061da546Spatrick
366061da546Spatrick if (!err.Success()) {
367061da546Spatrick dump_stream.Printf(" <could not be read>\n");
368061da546Spatrick } else {
369061da546Spatrick DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
370061da546Spatrick load_addr);
371061da546Spatrick
372061da546Spatrick dump_stream.PutChar('\n');
373061da546Spatrick }
374061da546Spatrick }
375061da546Spatrick
376061da546Spatrick {
377061da546Spatrick dump_stream.Printf("Target:\n");
378061da546Spatrick
379061da546Spatrick lldb::addr_t target_address;
380061da546Spatrick
381061da546Spatrick map.ReadPointerFromMemory(&target_address, load_addr, err);
382061da546Spatrick
383061da546Spatrick if (!err.Success()) {
384061da546Spatrick dump_stream.Printf(" <could not be read>\n");
385061da546Spatrick } else {
386*f6aab3d8Srobert DataBufferHeap data(m_persistent_variable_sp->GetByteSize().value_or(0),
387*f6aab3d8Srobert 0);
388061da546Spatrick
389061da546Spatrick map.ReadMemory(data.GetBytes(), target_address,
390*f6aab3d8Srobert m_persistent_variable_sp->GetByteSize().value_or(0),
391*f6aab3d8Srobert err);
392061da546Spatrick
393061da546Spatrick if (!err.Success()) {
394061da546Spatrick dump_stream.Printf(" <could not be read>\n");
395061da546Spatrick } else {
396061da546Spatrick DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
397061da546Spatrick target_address);
398061da546Spatrick
399061da546Spatrick dump_stream.PutChar('\n');
400061da546Spatrick }
401061da546Spatrick }
402061da546Spatrick }
403061da546Spatrick
404061da546Spatrick log->PutString(dump_stream.GetString());
405061da546Spatrick }
406061da546Spatrick
Wipe(IRMemoryMap & map,lldb::addr_t process_address)407061da546Spatrick void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {}
408061da546Spatrick
409061da546Spatrick private:
410061da546Spatrick lldb::ExpressionVariableSP m_persistent_variable_sp;
411061da546Spatrick Materializer::PersistentVariableDelegate *m_delegate;
412061da546Spatrick };
413061da546Spatrick
AddPersistentVariable(lldb::ExpressionVariableSP & persistent_variable_sp,PersistentVariableDelegate * delegate,Status & err)414061da546Spatrick uint32_t Materializer::AddPersistentVariable(
415061da546Spatrick lldb::ExpressionVariableSP &persistent_variable_sp,
416061da546Spatrick PersistentVariableDelegate *delegate, Status &err) {
417061da546Spatrick EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
418dda28197Spatrick *iter = std::make_unique<EntityPersistentVariable>(persistent_variable_sp,
419dda28197Spatrick delegate);
420061da546Spatrick uint32_t ret = AddStructMember(**iter);
421061da546Spatrick (*iter)->SetOffset(ret);
422061da546Spatrick return ret;
423061da546Spatrick }
424061da546Spatrick
425*f6aab3d8Srobert /// Base class for materialization of Variables and ValueObjects.
426*f6aab3d8Srobert ///
427*f6aab3d8Srobert /// Subclasses specify how to obtain the Value which is to be
428*f6aab3d8Srobert /// materialized.
429*f6aab3d8Srobert class EntityVariableBase : public Materializer::Entity {
430061da546Spatrick public:
431*f6aab3d8Srobert virtual ~EntityVariableBase() = default;
432*f6aab3d8Srobert
EntityVariableBase()433*f6aab3d8Srobert EntityVariableBase() {
434061da546Spatrick // Hard-coding to maximum size of a pointer since all variables are
435061da546Spatrick // materialized by reference
436*f6aab3d8Srobert m_size = g_default_var_byte_size;
437*f6aab3d8Srobert m_alignment = g_default_var_alignment;
438061da546Spatrick }
439061da546Spatrick
Materialize(lldb::StackFrameSP & frame_sp,IRMemoryMap & map,lldb::addr_t process_address,Status & err)440061da546Spatrick void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
441061da546Spatrick lldb::addr_t process_address, Status &err) override {
442*f6aab3d8Srobert Log *log = GetLog(LLDBLog::Expressions);
443061da546Spatrick
444061da546Spatrick const lldb::addr_t load_addr = process_address + m_offset;
445061da546Spatrick if (log) {
446061da546Spatrick LLDB_LOGF(log,
447061da546Spatrick "EntityVariable::Materialize [address = 0x%" PRIx64
448061da546Spatrick ", m_variable_sp = %s]",
449*f6aab3d8Srobert (uint64_t)load_addr, GetName().GetCString());
450061da546Spatrick }
451061da546Spatrick
452061da546Spatrick ExecutionContextScope *scope = frame_sp.get();
453061da546Spatrick
454061da546Spatrick if (!scope)
455061da546Spatrick scope = map.GetBestExecutionContextScope();
456061da546Spatrick
457*f6aab3d8Srobert lldb::ValueObjectSP valobj_sp = SetupValueObject(scope);
458061da546Spatrick
459061da546Spatrick if (!valobj_sp) {
460061da546Spatrick err.SetErrorStringWithFormat(
461*f6aab3d8Srobert "couldn't get a value object for variable %s", GetName().AsCString());
462061da546Spatrick return;
463061da546Spatrick }
464061da546Spatrick
465061da546Spatrick Status valobj_error = valobj_sp->GetError();
466061da546Spatrick
467061da546Spatrick if (valobj_error.Fail()) {
468061da546Spatrick err.SetErrorStringWithFormat("couldn't get the value of variable %s: %s",
469*f6aab3d8Srobert GetName().AsCString(),
470061da546Spatrick valobj_error.AsCString());
471061da546Spatrick return;
472061da546Spatrick }
473061da546Spatrick
474061da546Spatrick if (m_is_reference) {
475061da546Spatrick DataExtractor valobj_extractor;
476061da546Spatrick Status extract_error;
477061da546Spatrick valobj_sp->GetData(valobj_extractor, extract_error);
478061da546Spatrick
479061da546Spatrick if (!extract_error.Success()) {
480061da546Spatrick err.SetErrorStringWithFormat(
481061da546Spatrick "couldn't read contents of reference variable %s: %s",
482*f6aab3d8Srobert GetName().AsCString(), extract_error.AsCString());
483061da546Spatrick return;
484061da546Spatrick }
485061da546Spatrick
486061da546Spatrick lldb::offset_t offset = 0;
487061da546Spatrick lldb::addr_t reference_addr = valobj_extractor.GetAddress(&offset);
488061da546Spatrick
489061da546Spatrick Status write_error;
490061da546Spatrick map.WritePointerToMemory(load_addr, reference_addr, write_error);
491061da546Spatrick
492061da546Spatrick if (!write_error.Success()) {
493061da546Spatrick err.SetErrorStringWithFormat("couldn't write the contents of reference "
494061da546Spatrick "variable %s to memory: %s",
495*f6aab3d8Srobert GetName().AsCString(),
496061da546Spatrick write_error.AsCString());
497061da546Spatrick return;
498061da546Spatrick }
499061da546Spatrick } else {
500061da546Spatrick AddressType address_type = eAddressTypeInvalid;
501061da546Spatrick const bool scalar_is_load_address = false;
502061da546Spatrick lldb::addr_t addr_of_valobj =
503061da546Spatrick valobj_sp->GetAddressOf(scalar_is_load_address, &address_type);
504061da546Spatrick if (addr_of_valobj != LLDB_INVALID_ADDRESS) {
505061da546Spatrick Status write_error;
506061da546Spatrick map.WritePointerToMemory(load_addr, addr_of_valobj, write_error);
507061da546Spatrick
508061da546Spatrick if (!write_error.Success()) {
509061da546Spatrick err.SetErrorStringWithFormat(
510061da546Spatrick "couldn't write the address of variable %s to memory: %s",
511*f6aab3d8Srobert GetName().AsCString(), write_error.AsCString());
512061da546Spatrick return;
513061da546Spatrick }
514061da546Spatrick } else {
515061da546Spatrick DataExtractor data;
516061da546Spatrick Status extract_error;
517061da546Spatrick valobj_sp->GetData(data, extract_error);
518061da546Spatrick if (!extract_error.Success()) {
519061da546Spatrick err.SetErrorStringWithFormat("couldn't get the value of %s: %s",
520*f6aab3d8Srobert GetName().AsCString(),
521061da546Spatrick extract_error.AsCString());
522061da546Spatrick return;
523061da546Spatrick }
524061da546Spatrick
525061da546Spatrick if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
526061da546Spatrick err.SetErrorStringWithFormat(
527061da546Spatrick "trying to create a temporary region for %s but one exists",
528*f6aab3d8Srobert GetName().AsCString());
529061da546Spatrick return;
530061da546Spatrick }
531061da546Spatrick
532*f6aab3d8Srobert if (data.GetByteSize() < GetByteSize(scope)) {
533*f6aab3d8Srobert if (data.GetByteSize() == 0 && !LocationExpressionIsValid()) {
534061da546Spatrick err.SetErrorStringWithFormat("the variable '%s' has no location, "
535061da546Spatrick "it may have been optimized out",
536*f6aab3d8Srobert GetName().AsCString());
537061da546Spatrick } else {
538061da546Spatrick err.SetErrorStringWithFormat(
539061da546Spatrick "size of variable %s (%" PRIu64
540061da546Spatrick ") is larger than the ValueObject's size (%" PRIu64 ")",
541*f6aab3d8Srobert GetName().AsCString(), GetByteSize(scope).value_or(0),
542061da546Spatrick data.GetByteSize());
543061da546Spatrick }
544061da546Spatrick return;
545061da546Spatrick }
546061da546Spatrick
547*f6aab3d8Srobert std::optional<size_t> opt_bit_align = GetTypeBitAlign(scope);
548061da546Spatrick if (!opt_bit_align) {
549061da546Spatrick err.SetErrorStringWithFormat("can't get the type alignment for %s",
550*f6aab3d8Srobert GetName().AsCString());
551061da546Spatrick return;
552061da546Spatrick }
553061da546Spatrick
554061da546Spatrick size_t byte_align = (*opt_bit_align + 7) / 8;
555061da546Spatrick
556061da546Spatrick Status alloc_error;
557061da546Spatrick const bool zero_memory = false;
558061da546Spatrick
559061da546Spatrick m_temporary_allocation = map.Malloc(
560061da546Spatrick data.GetByteSize(), byte_align,
561061da546Spatrick lldb::ePermissionsReadable | lldb::ePermissionsWritable,
562061da546Spatrick IRMemoryMap::eAllocationPolicyMirror, zero_memory, alloc_error);
563061da546Spatrick
564061da546Spatrick m_temporary_allocation_size = data.GetByteSize();
565061da546Spatrick
566061da546Spatrick m_original_data = std::make_shared<DataBufferHeap>(data.GetDataStart(),
567061da546Spatrick data.GetByteSize());
568061da546Spatrick
569061da546Spatrick if (!alloc_error.Success()) {
570061da546Spatrick err.SetErrorStringWithFormat(
571061da546Spatrick "couldn't allocate a temporary region for %s: %s",
572*f6aab3d8Srobert GetName().AsCString(), alloc_error.AsCString());
573061da546Spatrick return;
574061da546Spatrick }
575061da546Spatrick
576061da546Spatrick Status write_error;
577061da546Spatrick
578061da546Spatrick map.WriteMemory(m_temporary_allocation, data.GetDataStart(),
579061da546Spatrick data.GetByteSize(), write_error);
580061da546Spatrick
581061da546Spatrick if (!write_error.Success()) {
582061da546Spatrick err.SetErrorStringWithFormat(
583061da546Spatrick "couldn't write to the temporary region for %s: %s",
584*f6aab3d8Srobert GetName().AsCString(), write_error.AsCString());
585061da546Spatrick return;
586061da546Spatrick }
587061da546Spatrick
588061da546Spatrick Status pointer_write_error;
589061da546Spatrick
590061da546Spatrick map.WritePointerToMemory(load_addr, m_temporary_allocation,
591061da546Spatrick pointer_write_error);
592061da546Spatrick
593061da546Spatrick if (!pointer_write_error.Success()) {
594061da546Spatrick err.SetErrorStringWithFormat(
595061da546Spatrick "couldn't write the address of the temporary region for %s: %s",
596*f6aab3d8Srobert GetName().AsCString(), pointer_write_error.AsCString());
597061da546Spatrick }
598061da546Spatrick }
599061da546Spatrick }
600061da546Spatrick }
601061da546Spatrick
Dematerialize(lldb::StackFrameSP & frame_sp,IRMemoryMap & map,lldb::addr_t process_address,lldb::addr_t frame_top,lldb::addr_t frame_bottom,Status & err)602061da546Spatrick void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
603061da546Spatrick lldb::addr_t process_address, lldb::addr_t frame_top,
604061da546Spatrick lldb::addr_t frame_bottom, Status &err) override {
605*f6aab3d8Srobert Log *log = GetLog(LLDBLog::Expressions);
606061da546Spatrick
607061da546Spatrick const lldb::addr_t load_addr = process_address + m_offset;
608061da546Spatrick if (log) {
609061da546Spatrick LLDB_LOGF(log,
610061da546Spatrick "EntityVariable::Dematerialize [address = 0x%" PRIx64
611061da546Spatrick ", m_variable_sp = %s]",
612*f6aab3d8Srobert (uint64_t)load_addr, GetName().AsCString());
613061da546Spatrick }
614061da546Spatrick
615061da546Spatrick if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
616061da546Spatrick ExecutionContextScope *scope = frame_sp.get();
617061da546Spatrick
618061da546Spatrick if (!scope)
619061da546Spatrick scope = map.GetBestExecutionContextScope();
620061da546Spatrick
621*f6aab3d8Srobert lldb::ValueObjectSP valobj_sp = SetupValueObject(scope);
622061da546Spatrick
623061da546Spatrick if (!valobj_sp) {
624061da546Spatrick err.SetErrorStringWithFormat(
625061da546Spatrick "couldn't get a value object for variable %s",
626*f6aab3d8Srobert GetName().AsCString());
627061da546Spatrick return;
628061da546Spatrick }
629061da546Spatrick
630061da546Spatrick lldb_private::DataExtractor data;
631061da546Spatrick
632061da546Spatrick Status extract_error;
633061da546Spatrick
634be691f3bSpatrick map.GetMemoryData(data, m_temporary_allocation,
635*f6aab3d8Srobert valobj_sp->GetByteSize().value_or(0), extract_error);
636061da546Spatrick
637061da546Spatrick if (!extract_error.Success()) {
638061da546Spatrick err.SetErrorStringWithFormat("couldn't get the data for variable %s",
639*f6aab3d8Srobert GetName().AsCString());
640061da546Spatrick return;
641061da546Spatrick }
642061da546Spatrick
643061da546Spatrick bool actually_write = true;
644061da546Spatrick
645061da546Spatrick if (m_original_data) {
646061da546Spatrick if ((data.GetByteSize() == m_original_data->GetByteSize()) &&
647061da546Spatrick !memcmp(m_original_data->GetBytes(), data.GetDataStart(),
648061da546Spatrick data.GetByteSize())) {
649061da546Spatrick actually_write = false;
650061da546Spatrick }
651061da546Spatrick }
652061da546Spatrick
653061da546Spatrick Status set_error;
654061da546Spatrick
655061da546Spatrick if (actually_write) {
656061da546Spatrick valobj_sp->SetData(data, set_error);
657061da546Spatrick
658061da546Spatrick if (!set_error.Success()) {
659061da546Spatrick err.SetErrorStringWithFormat(
660061da546Spatrick "couldn't write the new contents of %s back into the variable",
661*f6aab3d8Srobert GetName().AsCString());
662061da546Spatrick return;
663061da546Spatrick }
664061da546Spatrick }
665061da546Spatrick
666061da546Spatrick Status free_error;
667061da546Spatrick
668061da546Spatrick map.Free(m_temporary_allocation, free_error);
669061da546Spatrick
670061da546Spatrick if (!free_error.Success()) {
671061da546Spatrick err.SetErrorStringWithFormat(
672061da546Spatrick "couldn't free the temporary region for %s: %s",
673*f6aab3d8Srobert GetName().AsCString(), free_error.AsCString());
674061da546Spatrick return;
675061da546Spatrick }
676061da546Spatrick
677061da546Spatrick m_original_data.reset();
678061da546Spatrick m_temporary_allocation = LLDB_INVALID_ADDRESS;
679061da546Spatrick m_temporary_allocation_size = 0;
680061da546Spatrick }
681061da546Spatrick }
682061da546Spatrick
DumpToLog(IRMemoryMap & map,lldb::addr_t process_address,Log * log)683061da546Spatrick void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
684061da546Spatrick Log *log) override {
685061da546Spatrick StreamString dump_stream;
686061da546Spatrick
687061da546Spatrick const lldb::addr_t load_addr = process_address + m_offset;
688061da546Spatrick dump_stream.Printf("0x%" PRIx64 ": EntityVariable\n", load_addr);
689061da546Spatrick
690061da546Spatrick Status err;
691061da546Spatrick
692061da546Spatrick lldb::addr_t ptr = LLDB_INVALID_ADDRESS;
693061da546Spatrick
694061da546Spatrick {
695061da546Spatrick dump_stream.Printf("Pointer:\n");
696061da546Spatrick
697061da546Spatrick DataBufferHeap data(m_size, 0);
698061da546Spatrick
699061da546Spatrick map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
700061da546Spatrick
701061da546Spatrick if (!err.Success()) {
702061da546Spatrick dump_stream.Printf(" <could not be read>\n");
703061da546Spatrick } else {
704061da546Spatrick DataExtractor extractor(data.GetBytes(), data.GetByteSize(),
705061da546Spatrick map.GetByteOrder(), map.GetAddressByteSize());
706061da546Spatrick
707061da546Spatrick DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
708061da546Spatrick load_addr);
709061da546Spatrick
710*f6aab3d8Srobert lldb::offset_t offset = 0;
711061da546Spatrick
712dda28197Spatrick ptr = extractor.GetAddress(&offset);
713061da546Spatrick
714061da546Spatrick dump_stream.PutChar('\n');
715061da546Spatrick }
716061da546Spatrick }
717061da546Spatrick
718061da546Spatrick if (m_temporary_allocation == LLDB_INVALID_ADDRESS) {
719061da546Spatrick dump_stream.Printf("Points to process memory:\n");
720061da546Spatrick } else {
721061da546Spatrick dump_stream.Printf("Temporary allocation:\n");
722061da546Spatrick }
723061da546Spatrick
724061da546Spatrick if (ptr == LLDB_INVALID_ADDRESS) {
725061da546Spatrick dump_stream.Printf(" <could not be be found>\n");
726061da546Spatrick } else {
727061da546Spatrick DataBufferHeap data(m_temporary_allocation_size, 0);
728061da546Spatrick
729061da546Spatrick map.ReadMemory(data.GetBytes(), m_temporary_allocation,
730061da546Spatrick m_temporary_allocation_size, err);
731061da546Spatrick
732061da546Spatrick if (!err.Success()) {
733061da546Spatrick dump_stream.Printf(" <could not be read>\n");
734061da546Spatrick } else {
735061da546Spatrick DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
736061da546Spatrick load_addr);
737061da546Spatrick
738061da546Spatrick dump_stream.PutChar('\n');
739061da546Spatrick }
740061da546Spatrick }
741061da546Spatrick
742061da546Spatrick log->PutString(dump_stream.GetString());
743061da546Spatrick }
744061da546Spatrick
Wipe(IRMemoryMap & map,lldb::addr_t process_address)745061da546Spatrick void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {
746061da546Spatrick if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
747061da546Spatrick Status free_error;
748061da546Spatrick
749061da546Spatrick map.Free(m_temporary_allocation, free_error);
750061da546Spatrick
751061da546Spatrick m_temporary_allocation = LLDB_INVALID_ADDRESS;
752061da546Spatrick m_temporary_allocation_size = 0;
753061da546Spatrick }
754061da546Spatrick }
755061da546Spatrick
756061da546Spatrick private:
757*f6aab3d8Srobert virtual ConstString GetName() const = 0;
758*f6aab3d8Srobert
759*f6aab3d8Srobert /// Creates and returns ValueObject tied to this variable
760*f6aab3d8Srobert /// and prepares Entity for materialization.
761*f6aab3d8Srobert ///
762*f6aab3d8Srobert /// Called each time the Materializer (de)materializes a
763*f6aab3d8Srobert /// variable. We re-create the ValueObject based on the
764*f6aab3d8Srobert /// current ExecutionContextScope since clients such as
765*f6aab3d8Srobert /// conditional breakpoints may materialize the same
766*f6aab3d8Srobert /// EntityVariable multiple times with different frames.
767*f6aab3d8Srobert ///
768*f6aab3d8Srobert /// Each subsequent use of the EntityVariableBase interface
769*f6aab3d8Srobert /// will query the newly created ValueObject until this
770*f6aab3d8Srobert /// function is called again.
771*f6aab3d8Srobert virtual lldb::ValueObjectSP
772*f6aab3d8Srobert SetupValueObject(ExecutionContextScope *scope) = 0;
773*f6aab3d8Srobert
774*f6aab3d8Srobert /// Returns size in bytes of the type associated with this variable
775*f6aab3d8Srobert ///
776*f6aab3d8Srobert /// \returns On success, returns byte size of the type associated
777*f6aab3d8Srobert /// with this variable. Returns std::nullopt otherwise.
778*f6aab3d8Srobert virtual std::optional<uint64_t>
779*f6aab3d8Srobert GetByteSize(ExecutionContextScope *scope) const = 0;
780*f6aab3d8Srobert
781*f6aab3d8Srobert /// Returns 'true' if the location expression associated with this variable
782*f6aab3d8Srobert /// is valid.
783*f6aab3d8Srobert virtual bool LocationExpressionIsValid() const = 0;
784*f6aab3d8Srobert
785*f6aab3d8Srobert /// Returns alignment of the type associated with this variable in bits.
786*f6aab3d8Srobert ///
787*f6aab3d8Srobert /// \returns On success, returns alignment in bits for the type associated
788*f6aab3d8Srobert /// with this variable. Returns std::nullopt otherwise.
789*f6aab3d8Srobert virtual std::optional<size_t>
790*f6aab3d8Srobert GetTypeBitAlign(ExecutionContextScope *scope) const = 0;
791*f6aab3d8Srobert
792*f6aab3d8Srobert protected:
793*f6aab3d8Srobert bool m_is_reference = false;
794*f6aab3d8Srobert lldb::addr_t m_temporary_allocation = LLDB_INVALID_ADDRESS;
795*f6aab3d8Srobert size_t m_temporary_allocation_size = 0;
796061da546Spatrick lldb::DataBufferSP m_original_data;
797061da546Spatrick };
798061da546Spatrick
799*f6aab3d8Srobert /// Represents an Entity constructed from a VariableSP.
800*f6aab3d8Srobert ///
801*f6aab3d8Srobert /// This class is used for materialization of variables for which
802*f6aab3d8Srobert /// the user has a VariableSP on hand. The ValueObject is then
803*f6aab3d8Srobert /// derived from the associated DWARF location expression when needed
804*f6aab3d8Srobert /// by the Materializer.
805*f6aab3d8Srobert class EntityVariable : public EntityVariableBase {
806*f6aab3d8Srobert public:
EntityVariable(lldb::VariableSP & variable_sp)807*f6aab3d8Srobert EntityVariable(lldb::VariableSP &variable_sp) : m_variable_sp(variable_sp) {
808*f6aab3d8Srobert m_is_reference =
809*f6aab3d8Srobert m_variable_sp->GetType()->GetForwardCompilerType().IsReferenceType();
810*f6aab3d8Srobert }
811*f6aab3d8Srobert
GetName() const812*f6aab3d8Srobert ConstString GetName() const override { return m_variable_sp->GetName(); }
813*f6aab3d8Srobert
SetupValueObject(ExecutionContextScope * scope)814*f6aab3d8Srobert lldb::ValueObjectSP SetupValueObject(ExecutionContextScope *scope) override {
815*f6aab3d8Srobert assert(m_variable_sp != nullptr);
816*f6aab3d8Srobert return ValueObjectVariable::Create(scope, m_variable_sp);
817*f6aab3d8Srobert }
818*f6aab3d8Srobert
819*f6aab3d8Srobert std::optional<uint64_t>
GetByteSize(ExecutionContextScope * scope) const820*f6aab3d8Srobert GetByteSize(ExecutionContextScope *scope) const override {
821*f6aab3d8Srobert return m_variable_sp->GetType()->GetByteSize(scope);
822*f6aab3d8Srobert }
823*f6aab3d8Srobert
LocationExpressionIsValid() const824*f6aab3d8Srobert bool LocationExpressionIsValid() const override {
825*f6aab3d8Srobert return m_variable_sp->LocationExpressionList().IsValid();
826*f6aab3d8Srobert }
827*f6aab3d8Srobert
828*f6aab3d8Srobert std::optional<size_t>
GetTypeBitAlign(ExecutionContextScope * scope) const829*f6aab3d8Srobert GetTypeBitAlign(ExecutionContextScope *scope) const override {
830*f6aab3d8Srobert return m_variable_sp->GetType()->GetLayoutCompilerType().GetTypeBitAlign(
831*f6aab3d8Srobert scope);
832*f6aab3d8Srobert }
833*f6aab3d8Srobert
834*f6aab3d8Srobert private:
835*f6aab3d8Srobert lldb::VariableSP m_variable_sp; ///< Variable that this entity is based on.
836*f6aab3d8Srobert };
837*f6aab3d8Srobert
838*f6aab3d8Srobert /// Represents an Entity constructed from a VariableSP.
839*f6aab3d8Srobert ///
840*f6aab3d8Srobert /// This class is used for materialization of variables for
841*f6aab3d8Srobert /// which the user does not have a VariableSP available (e.g.,
842*f6aab3d8Srobert /// when materializing ivars).
843*f6aab3d8Srobert class EntityValueObject : public EntityVariableBase {
844*f6aab3d8Srobert public:
EntityValueObject(ConstString name,ValueObjectProviderTy provider)845*f6aab3d8Srobert EntityValueObject(ConstString name, ValueObjectProviderTy provider)
846*f6aab3d8Srobert : m_name(name), m_valobj_provider(std::move(provider)) {
847*f6aab3d8Srobert assert(m_valobj_provider);
848*f6aab3d8Srobert }
849*f6aab3d8Srobert
GetName() const850*f6aab3d8Srobert ConstString GetName() const override { return m_name; }
851*f6aab3d8Srobert
SetupValueObject(ExecutionContextScope * scope)852*f6aab3d8Srobert lldb::ValueObjectSP SetupValueObject(ExecutionContextScope *scope) override {
853*f6aab3d8Srobert m_valobj_sp =
854*f6aab3d8Srobert m_valobj_provider(GetName(), scope->CalculateStackFrame().get());
855*f6aab3d8Srobert
856*f6aab3d8Srobert if (m_valobj_sp)
857*f6aab3d8Srobert m_is_reference = m_valobj_sp->GetCompilerType().IsReferenceType();
858*f6aab3d8Srobert
859*f6aab3d8Srobert return m_valobj_sp;
860*f6aab3d8Srobert }
861*f6aab3d8Srobert
862*f6aab3d8Srobert std::optional<uint64_t>
GetByteSize(ExecutionContextScope * scope) const863*f6aab3d8Srobert GetByteSize(ExecutionContextScope *scope) const override {
864*f6aab3d8Srobert if (m_valobj_sp)
865*f6aab3d8Srobert return m_valobj_sp->GetCompilerType().GetByteSize(scope);
866*f6aab3d8Srobert
867*f6aab3d8Srobert return {};
868*f6aab3d8Srobert }
869*f6aab3d8Srobert
LocationExpressionIsValid() const870*f6aab3d8Srobert bool LocationExpressionIsValid() const override {
871*f6aab3d8Srobert if (m_valobj_sp)
872*f6aab3d8Srobert return m_valobj_sp->GetError().Success();
873*f6aab3d8Srobert
874*f6aab3d8Srobert return false;
875*f6aab3d8Srobert }
876*f6aab3d8Srobert
877*f6aab3d8Srobert std::optional<size_t>
GetTypeBitAlign(ExecutionContextScope * scope) const878*f6aab3d8Srobert GetTypeBitAlign(ExecutionContextScope *scope) const override {
879*f6aab3d8Srobert if (m_valobj_sp)
880*f6aab3d8Srobert return m_valobj_sp->GetCompilerType().GetTypeBitAlign(scope);
881*f6aab3d8Srobert
882*f6aab3d8Srobert return {};
883*f6aab3d8Srobert }
884*f6aab3d8Srobert
885*f6aab3d8Srobert private:
886*f6aab3d8Srobert ConstString m_name;
887*f6aab3d8Srobert lldb::ValueObjectSP m_valobj_sp;
888*f6aab3d8Srobert ValueObjectProviderTy m_valobj_provider;
889*f6aab3d8Srobert };
890*f6aab3d8Srobert
AddVariable(lldb::VariableSP & variable_sp,Status & err)891061da546Spatrick uint32_t Materializer::AddVariable(lldb::VariableSP &variable_sp, Status &err) {
892061da546Spatrick EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
893dda28197Spatrick *iter = std::make_unique<EntityVariable>(variable_sp);
894061da546Spatrick uint32_t ret = AddStructMember(**iter);
895061da546Spatrick (*iter)->SetOffset(ret);
896061da546Spatrick return ret;
897061da546Spatrick }
898061da546Spatrick
AddValueObject(ConstString name,ValueObjectProviderTy valobj_provider,Status & err)899*f6aab3d8Srobert uint32_t Materializer::AddValueObject(ConstString name,
900*f6aab3d8Srobert ValueObjectProviderTy valobj_provider,
901*f6aab3d8Srobert Status &err) {
902*f6aab3d8Srobert assert(valobj_provider);
903*f6aab3d8Srobert EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
904*f6aab3d8Srobert *iter = std::make_unique<EntityValueObject>(name, std::move(valobj_provider));
905*f6aab3d8Srobert uint32_t ret = AddStructMember(**iter);
906*f6aab3d8Srobert (*iter)->SetOffset(ret);
907*f6aab3d8Srobert return ret;
908*f6aab3d8Srobert }
909*f6aab3d8Srobert
910061da546Spatrick class EntityResultVariable : public Materializer::Entity {
911061da546Spatrick public:
EntityResultVariable(const CompilerType & type,bool is_program_reference,bool keep_in_memory,Materializer::PersistentVariableDelegate * delegate)912061da546Spatrick EntityResultVariable(const CompilerType &type, bool is_program_reference,
913061da546Spatrick bool keep_in_memory,
914061da546Spatrick Materializer::PersistentVariableDelegate *delegate)
915061da546Spatrick : Entity(), m_type(type), m_is_program_reference(is_program_reference),
916*f6aab3d8Srobert m_keep_in_memory(keep_in_memory), m_delegate(delegate) {
917061da546Spatrick // Hard-coding to maximum size of a pointer since all results are
918061da546Spatrick // materialized by reference
919*f6aab3d8Srobert m_size = g_default_var_byte_size;
920*f6aab3d8Srobert m_alignment = g_default_var_alignment;
921061da546Spatrick }
922061da546Spatrick
Materialize(lldb::StackFrameSP & frame_sp,IRMemoryMap & map,lldb::addr_t process_address,Status & err)923061da546Spatrick void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
924061da546Spatrick lldb::addr_t process_address, Status &err) override {
925061da546Spatrick if (!m_is_program_reference) {
926061da546Spatrick if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
927061da546Spatrick err.SetErrorString("Trying to create a temporary region for the result "
928061da546Spatrick "but one exists");
929061da546Spatrick return;
930061da546Spatrick }
931061da546Spatrick
932061da546Spatrick const lldb::addr_t load_addr = process_address + m_offset;
933061da546Spatrick
934dda28197Spatrick ExecutionContextScope *exe_scope = frame_sp.get();
935dda28197Spatrick if (!exe_scope)
936dda28197Spatrick exe_scope = map.GetBestExecutionContextScope();
937061da546Spatrick
938*f6aab3d8Srobert std::optional<uint64_t> byte_size = m_type.GetByteSize(exe_scope);
939061da546Spatrick if (!byte_size) {
940be691f3bSpatrick err.SetErrorStringWithFormat("can't get size of type \"%s\"",
941be691f3bSpatrick m_type.GetTypeName().AsCString());
942061da546Spatrick return;
943061da546Spatrick }
944061da546Spatrick
945*f6aab3d8Srobert std::optional<size_t> opt_bit_align = m_type.GetTypeBitAlign(exe_scope);
946061da546Spatrick if (!opt_bit_align) {
947be691f3bSpatrick err.SetErrorStringWithFormat("can't get the alignment of type \"%s\"",
948be691f3bSpatrick m_type.GetTypeName().AsCString());
949061da546Spatrick return;
950061da546Spatrick }
951061da546Spatrick
952061da546Spatrick size_t byte_align = (*opt_bit_align + 7) / 8;
953061da546Spatrick
954061da546Spatrick Status alloc_error;
955061da546Spatrick const bool zero_memory = true;
956061da546Spatrick
957061da546Spatrick m_temporary_allocation = map.Malloc(
958061da546Spatrick *byte_size, byte_align,
959061da546Spatrick lldb::ePermissionsReadable | lldb::ePermissionsWritable,
960061da546Spatrick IRMemoryMap::eAllocationPolicyMirror, zero_memory, alloc_error);
961061da546Spatrick m_temporary_allocation_size = *byte_size;
962061da546Spatrick
963061da546Spatrick if (!alloc_error.Success()) {
964061da546Spatrick err.SetErrorStringWithFormat(
965061da546Spatrick "couldn't allocate a temporary region for the result: %s",
966061da546Spatrick alloc_error.AsCString());
967061da546Spatrick return;
968061da546Spatrick }
969061da546Spatrick
970061da546Spatrick Status pointer_write_error;
971061da546Spatrick
972061da546Spatrick map.WritePointerToMemory(load_addr, m_temporary_allocation,
973061da546Spatrick pointer_write_error);
974061da546Spatrick
975061da546Spatrick if (!pointer_write_error.Success()) {
976061da546Spatrick err.SetErrorStringWithFormat("couldn't write the address of the "
977061da546Spatrick "temporary region for the result: %s",
978061da546Spatrick pointer_write_error.AsCString());
979061da546Spatrick }
980061da546Spatrick }
981061da546Spatrick }
982061da546Spatrick
Dematerialize(lldb::StackFrameSP & frame_sp,IRMemoryMap & map,lldb::addr_t process_address,lldb::addr_t frame_top,lldb::addr_t frame_bottom,Status & err)983061da546Spatrick void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
984061da546Spatrick lldb::addr_t process_address, lldb::addr_t frame_top,
985061da546Spatrick lldb::addr_t frame_bottom, Status &err) override {
986061da546Spatrick err.Clear();
987061da546Spatrick
988dda28197Spatrick ExecutionContextScope *exe_scope = frame_sp.get();
989dda28197Spatrick if (!exe_scope)
990dda28197Spatrick exe_scope = map.GetBestExecutionContextScope();
991061da546Spatrick
992061da546Spatrick if (!exe_scope) {
993061da546Spatrick err.SetErrorString("Couldn't dematerialize a result variable: invalid "
994061da546Spatrick "execution context scope");
995061da546Spatrick return;
996061da546Spatrick }
997061da546Spatrick
998061da546Spatrick lldb::addr_t address;
999061da546Spatrick Status read_error;
1000061da546Spatrick const lldb::addr_t load_addr = process_address + m_offset;
1001061da546Spatrick
1002061da546Spatrick map.ReadPointerFromMemory(&address, load_addr, read_error);
1003061da546Spatrick
1004061da546Spatrick if (!read_error.Success()) {
1005061da546Spatrick err.SetErrorString("Couldn't dematerialize a result variable: couldn't "
1006061da546Spatrick "read its address");
1007061da546Spatrick return;
1008061da546Spatrick }
1009061da546Spatrick
1010061da546Spatrick lldb::TargetSP target_sp = exe_scope->CalculateTarget();
1011061da546Spatrick
1012061da546Spatrick if (!target_sp) {
1013061da546Spatrick err.SetErrorString("Couldn't dematerialize a result variable: no target");
1014061da546Spatrick return;
1015061da546Spatrick }
1016061da546Spatrick
1017061da546Spatrick auto type_system_or_err =
1018061da546Spatrick target_sp->GetScratchTypeSystemForLanguage(m_type.GetMinimumLanguage());
1019061da546Spatrick
1020061da546Spatrick if (auto error = type_system_or_err.takeError()) {
1021061da546Spatrick err.SetErrorStringWithFormat("Couldn't dematerialize a result variable: "
1022061da546Spatrick "couldn't get the corresponding type "
1023061da546Spatrick "system: %s",
1024061da546Spatrick llvm::toString(std::move(error)).c_str());
1025061da546Spatrick return;
1026061da546Spatrick }
1027*f6aab3d8Srobert auto ts = *type_system_or_err;
1028*f6aab3d8Srobert if (!ts) {
1029*f6aab3d8Srobert err.SetErrorStringWithFormat("Couldn't dematerialize a result variable: "
1030*f6aab3d8Srobert "couldn't corresponding type system is "
1031*f6aab3d8Srobert "no longer live.");
1032*f6aab3d8Srobert return;
1033*f6aab3d8Srobert }
1034061da546Spatrick PersistentExpressionState *persistent_state =
1035*f6aab3d8Srobert ts->GetPersistentExpressionState();
1036061da546Spatrick
1037061da546Spatrick if (!persistent_state) {
1038061da546Spatrick err.SetErrorString("Couldn't dematerialize a result variable: "
1039061da546Spatrick "corresponding type system doesn't handle persistent "
1040061da546Spatrick "variables");
1041061da546Spatrick return;
1042061da546Spatrick }
1043061da546Spatrick
1044dda28197Spatrick ConstString name = m_delegate
1045061da546Spatrick ? m_delegate->GetName()
1046dda28197Spatrick : persistent_state->GetNextPersistentVariableName();
1047061da546Spatrick
1048061da546Spatrick lldb::ExpressionVariableSP ret = persistent_state->CreatePersistentVariable(
1049061da546Spatrick exe_scope, name, m_type, map.GetByteOrder(), map.GetAddressByteSize());
1050061da546Spatrick
1051061da546Spatrick if (!ret) {
1052061da546Spatrick err.SetErrorStringWithFormat("couldn't dematerialize a result variable: "
1053061da546Spatrick "failed to make persistent variable %s",
1054061da546Spatrick name.AsCString());
1055061da546Spatrick return;
1056061da546Spatrick }
1057061da546Spatrick
1058061da546Spatrick lldb::ProcessSP process_sp =
1059061da546Spatrick map.GetBestExecutionContextScope()->CalculateProcess();
1060061da546Spatrick
1061061da546Spatrick if (m_delegate) {
1062061da546Spatrick m_delegate->DidDematerialize(ret);
1063061da546Spatrick }
1064061da546Spatrick
1065061da546Spatrick bool can_persist =
1066061da546Spatrick (m_is_program_reference && process_sp && process_sp->CanJIT() &&
1067061da546Spatrick !(address >= frame_bottom && address < frame_top));
1068061da546Spatrick
1069061da546Spatrick if (can_persist && m_keep_in_memory) {
1070061da546Spatrick ret->m_live_sp = ValueObjectConstResult::Create(exe_scope, m_type, name,
1071061da546Spatrick address, eAddressTypeLoad,
1072061da546Spatrick map.GetAddressByteSize());
1073061da546Spatrick }
1074061da546Spatrick
1075061da546Spatrick ret->ValueUpdated();
1076061da546Spatrick
1077*f6aab3d8Srobert const size_t pvar_byte_size = ret->GetByteSize().value_or(0);
1078061da546Spatrick uint8_t *pvar_data = ret->GetValueBytes();
1079061da546Spatrick
1080061da546Spatrick map.ReadMemory(pvar_data, address, pvar_byte_size, read_error);
1081061da546Spatrick
1082061da546Spatrick if (!read_error.Success()) {
1083061da546Spatrick err.SetErrorString(
1084061da546Spatrick "Couldn't dematerialize a result variable: couldn't read its memory");
1085061da546Spatrick return;
1086061da546Spatrick }
1087061da546Spatrick
1088061da546Spatrick if (!can_persist || !m_keep_in_memory) {
1089061da546Spatrick ret->m_flags |= ExpressionVariable::EVNeedsAllocation;
1090061da546Spatrick
1091061da546Spatrick if (m_temporary_allocation != LLDB_INVALID_ADDRESS) {
1092061da546Spatrick Status free_error;
1093061da546Spatrick map.Free(m_temporary_allocation, free_error);
1094061da546Spatrick }
1095061da546Spatrick } else {
1096061da546Spatrick ret->m_flags |= ExpressionVariable::EVIsLLDBAllocated;
1097061da546Spatrick }
1098061da546Spatrick
1099061da546Spatrick m_temporary_allocation = LLDB_INVALID_ADDRESS;
1100061da546Spatrick m_temporary_allocation_size = 0;
1101061da546Spatrick }
1102061da546Spatrick
DumpToLog(IRMemoryMap & map,lldb::addr_t process_address,Log * log)1103061da546Spatrick void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
1104061da546Spatrick Log *log) override {
1105061da546Spatrick StreamString dump_stream;
1106061da546Spatrick
1107061da546Spatrick const lldb::addr_t load_addr = process_address + m_offset;
1108061da546Spatrick
1109061da546Spatrick dump_stream.Printf("0x%" PRIx64 ": EntityResultVariable\n", load_addr);
1110061da546Spatrick
1111061da546Spatrick Status err;
1112061da546Spatrick
1113061da546Spatrick lldb::addr_t ptr = LLDB_INVALID_ADDRESS;
1114061da546Spatrick
1115061da546Spatrick {
1116061da546Spatrick dump_stream.Printf("Pointer:\n");
1117061da546Spatrick
1118061da546Spatrick DataBufferHeap data(m_size, 0);
1119061da546Spatrick
1120061da546Spatrick map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
1121061da546Spatrick
1122061da546Spatrick if (!err.Success()) {
1123061da546Spatrick dump_stream.Printf(" <could not be read>\n");
1124061da546Spatrick } else {
1125061da546Spatrick DataExtractor extractor(data.GetBytes(), data.GetByteSize(),
1126061da546Spatrick map.GetByteOrder(), map.GetAddressByteSize());
1127061da546Spatrick
1128061da546Spatrick DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
1129061da546Spatrick load_addr);
1130061da546Spatrick
1131*f6aab3d8Srobert lldb::offset_t offset = 0;
1132061da546Spatrick
1133dda28197Spatrick ptr = extractor.GetAddress(&offset);
1134061da546Spatrick
1135061da546Spatrick dump_stream.PutChar('\n');
1136061da546Spatrick }
1137061da546Spatrick }
1138061da546Spatrick
1139061da546Spatrick if (m_temporary_allocation == LLDB_INVALID_ADDRESS) {
1140061da546Spatrick dump_stream.Printf("Points to process memory:\n");
1141061da546Spatrick } else {
1142061da546Spatrick dump_stream.Printf("Temporary allocation:\n");
1143061da546Spatrick }
1144061da546Spatrick
1145061da546Spatrick if (ptr == LLDB_INVALID_ADDRESS) {
1146061da546Spatrick dump_stream.Printf(" <could not be be found>\n");
1147061da546Spatrick } else {
1148061da546Spatrick DataBufferHeap data(m_temporary_allocation_size, 0);
1149061da546Spatrick
1150061da546Spatrick map.ReadMemory(data.GetBytes(), m_temporary_allocation,
1151061da546Spatrick m_temporary_allocation_size, err);
1152061da546Spatrick
1153061da546Spatrick if (!err.Success()) {
1154061da546Spatrick dump_stream.Printf(" <could not be read>\n");
1155061da546Spatrick } else {
1156061da546Spatrick DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
1157061da546Spatrick load_addr);
1158061da546Spatrick
1159061da546Spatrick dump_stream.PutChar('\n');
1160061da546Spatrick }
1161061da546Spatrick }
1162061da546Spatrick
1163061da546Spatrick log->PutString(dump_stream.GetString());
1164061da546Spatrick }
1165061da546Spatrick
Wipe(IRMemoryMap & map,lldb::addr_t process_address)1166061da546Spatrick void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {
1167061da546Spatrick if (!m_keep_in_memory && m_temporary_allocation != LLDB_INVALID_ADDRESS) {
1168061da546Spatrick Status free_error;
1169061da546Spatrick
1170061da546Spatrick map.Free(m_temporary_allocation, free_error);
1171061da546Spatrick }
1172061da546Spatrick
1173061da546Spatrick m_temporary_allocation = LLDB_INVALID_ADDRESS;
1174061da546Spatrick m_temporary_allocation_size = 0;
1175061da546Spatrick }
1176061da546Spatrick
1177061da546Spatrick private:
1178061da546Spatrick CompilerType m_type;
1179061da546Spatrick bool m_is_program_reference;
1180061da546Spatrick bool m_keep_in_memory;
1181061da546Spatrick
1182*f6aab3d8Srobert lldb::addr_t m_temporary_allocation = LLDB_INVALID_ADDRESS;
1183*f6aab3d8Srobert size_t m_temporary_allocation_size = 0;
1184061da546Spatrick Materializer::PersistentVariableDelegate *m_delegate;
1185061da546Spatrick };
1186061da546Spatrick
AddResultVariable(const CompilerType & type,bool is_program_reference,bool keep_in_memory,PersistentVariableDelegate * delegate,Status & err)1187061da546Spatrick uint32_t Materializer::AddResultVariable(const CompilerType &type,
1188061da546Spatrick bool is_program_reference,
1189061da546Spatrick bool keep_in_memory,
1190061da546Spatrick PersistentVariableDelegate *delegate,
1191061da546Spatrick Status &err) {
1192061da546Spatrick EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
1193dda28197Spatrick *iter = std::make_unique<EntityResultVariable>(type, is_program_reference,
1194dda28197Spatrick keep_in_memory, delegate);
1195061da546Spatrick uint32_t ret = AddStructMember(**iter);
1196061da546Spatrick (*iter)->SetOffset(ret);
1197061da546Spatrick return ret;
1198061da546Spatrick }
1199061da546Spatrick
1200061da546Spatrick class EntitySymbol : public Materializer::Entity {
1201061da546Spatrick public:
EntitySymbol(const Symbol & symbol)1202061da546Spatrick EntitySymbol(const Symbol &symbol) : Entity(), m_symbol(symbol) {
1203061da546Spatrick // Hard-coding to maximum size of a symbol
1204*f6aab3d8Srobert m_size = g_default_var_byte_size;
1205*f6aab3d8Srobert m_alignment = g_default_var_alignment;
1206061da546Spatrick }
1207061da546Spatrick
Materialize(lldb::StackFrameSP & frame_sp,IRMemoryMap & map,lldb::addr_t process_address,Status & err)1208061da546Spatrick void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1209061da546Spatrick lldb::addr_t process_address, Status &err) override {
1210*f6aab3d8Srobert Log *log = GetLog(LLDBLog::Expressions);
1211061da546Spatrick
1212061da546Spatrick const lldb::addr_t load_addr = process_address + m_offset;
1213061da546Spatrick
1214061da546Spatrick if (log) {
1215061da546Spatrick LLDB_LOGF(log,
1216061da546Spatrick "EntitySymbol::Materialize [address = 0x%" PRIx64
1217061da546Spatrick ", m_symbol = %s]",
1218061da546Spatrick (uint64_t)load_addr, m_symbol.GetName().AsCString());
1219061da546Spatrick }
1220061da546Spatrick
1221061da546Spatrick const Address sym_address = m_symbol.GetAddress();
1222061da546Spatrick
1223dda28197Spatrick ExecutionContextScope *exe_scope = frame_sp.get();
1224dda28197Spatrick if (!exe_scope)
1225dda28197Spatrick exe_scope = map.GetBestExecutionContextScope();
1226061da546Spatrick
1227061da546Spatrick lldb::TargetSP target_sp;
1228061da546Spatrick
1229061da546Spatrick if (exe_scope)
1230061da546Spatrick target_sp = map.GetBestExecutionContextScope()->CalculateTarget();
1231061da546Spatrick
1232061da546Spatrick if (!target_sp) {
1233061da546Spatrick err.SetErrorStringWithFormat(
1234061da546Spatrick "couldn't resolve symbol %s because there is no target",
1235061da546Spatrick m_symbol.GetName().AsCString());
1236061da546Spatrick return;
1237061da546Spatrick }
1238061da546Spatrick
1239061da546Spatrick lldb::addr_t resolved_address = sym_address.GetLoadAddress(target_sp.get());
1240061da546Spatrick
1241061da546Spatrick if (resolved_address == LLDB_INVALID_ADDRESS)
1242061da546Spatrick resolved_address = sym_address.GetFileAddress();
1243061da546Spatrick
1244061da546Spatrick Status pointer_write_error;
1245061da546Spatrick
1246061da546Spatrick map.WritePointerToMemory(load_addr, resolved_address, pointer_write_error);
1247061da546Spatrick
1248061da546Spatrick if (!pointer_write_error.Success()) {
1249061da546Spatrick err.SetErrorStringWithFormat(
1250061da546Spatrick "couldn't write the address of symbol %s: %s",
1251061da546Spatrick m_symbol.GetName().AsCString(), pointer_write_error.AsCString());
1252061da546Spatrick return;
1253061da546Spatrick }
1254061da546Spatrick }
1255061da546Spatrick
Dematerialize(lldb::StackFrameSP & frame_sp,IRMemoryMap & map,lldb::addr_t process_address,lldb::addr_t frame_top,lldb::addr_t frame_bottom,Status & err)1256061da546Spatrick void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1257061da546Spatrick lldb::addr_t process_address, lldb::addr_t frame_top,
1258061da546Spatrick lldb::addr_t frame_bottom, Status &err) override {
1259*f6aab3d8Srobert Log *log = GetLog(LLDBLog::Expressions);
1260061da546Spatrick
1261061da546Spatrick const lldb::addr_t load_addr = process_address + m_offset;
1262061da546Spatrick
1263061da546Spatrick if (log) {
1264061da546Spatrick LLDB_LOGF(log,
1265061da546Spatrick "EntitySymbol::Dematerialize [address = 0x%" PRIx64
1266061da546Spatrick ", m_symbol = %s]",
1267061da546Spatrick (uint64_t)load_addr, m_symbol.GetName().AsCString());
1268061da546Spatrick }
1269061da546Spatrick
1270061da546Spatrick // no work needs to be done
1271061da546Spatrick }
1272061da546Spatrick
DumpToLog(IRMemoryMap & map,lldb::addr_t process_address,Log * log)1273061da546Spatrick void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
1274061da546Spatrick Log *log) override {
1275061da546Spatrick StreamString dump_stream;
1276061da546Spatrick
1277061da546Spatrick Status err;
1278061da546Spatrick
1279061da546Spatrick const lldb::addr_t load_addr = process_address + m_offset;
1280061da546Spatrick
1281061da546Spatrick dump_stream.Printf("0x%" PRIx64 ": EntitySymbol (%s)\n", load_addr,
1282061da546Spatrick m_symbol.GetName().AsCString());
1283061da546Spatrick
1284061da546Spatrick {
1285061da546Spatrick dump_stream.Printf("Pointer:\n");
1286061da546Spatrick
1287061da546Spatrick DataBufferHeap data(m_size, 0);
1288061da546Spatrick
1289061da546Spatrick map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
1290061da546Spatrick
1291061da546Spatrick if (!err.Success()) {
1292061da546Spatrick dump_stream.Printf(" <could not be read>\n");
1293061da546Spatrick } else {
1294061da546Spatrick DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
1295061da546Spatrick load_addr);
1296061da546Spatrick
1297061da546Spatrick dump_stream.PutChar('\n');
1298061da546Spatrick }
1299061da546Spatrick }
1300061da546Spatrick
1301061da546Spatrick log->PutString(dump_stream.GetString());
1302061da546Spatrick }
1303061da546Spatrick
Wipe(IRMemoryMap & map,lldb::addr_t process_address)1304061da546Spatrick void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {}
1305061da546Spatrick
1306061da546Spatrick private:
1307061da546Spatrick Symbol m_symbol;
1308061da546Spatrick };
1309061da546Spatrick
AddSymbol(const Symbol & symbol_sp,Status & err)1310061da546Spatrick uint32_t Materializer::AddSymbol(const Symbol &symbol_sp, Status &err) {
1311061da546Spatrick EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
1312dda28197Spatrick *iter = std::make_unique<EntitySymbol>(symbol_sp);
1313061da546Spatrick uint32_t ret = AddStructMember(**iter);
1314061da546Spatrick (*iter)->SetOffset(ret);
1315061da546Spatrick return ret;
1316061da546Spatrick }
1317061da546Spatrick
1318061da546Spatrick class EntityRegister : public Materializer::Entity {
1319061da546Spatrick public:
EntityRegister(const RegisterInfo & register_info)1320061da546Spatrick EntityRegister(const RegisterInfo ®ister_info)
1321061da546Spatrick : Entity(), m_register_info(register_info) {
1322061da546Spatrick // Hard-coding alignment conservatively
1323061da546Spatrick m_size = m_register_info.byte_size;
1324061da546Spatrick m_alignment = m_register_info.byte_size;
1325061da546Spatrick }
1326061da546Spatrick
Materialize(lldb::StackFrameSP & frame_sp,IRMemoryMap & map,lldb::addr_t process_address,Status & err)1327061da546Spatrick void Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1328061da546Spatrick lldb::addr_t process_address, Status &err) override {
1329*f6aab3d8Srobert Log *log = GetLog(LLDBLog::Expressions);
1330061da546Spatrick
1331061da546Spatrick const lldb::addr_t load_addr = process_address + m_offset;
1332061da546Spatrick
1333061da546Spatrick if (log) {
1334061da546Spatrick LLDB_LOGF(log,
1335061da546Spatrick "EntityRegister::Materialize [address = 0x%" PRIx64
1336061da546Spatrick ", m_register_info = %s]",
1337061da546Spatrick (uint64_t)load_addr, m_register_info.name);
1338061da546Spatrick }
1339061da546Spatrick
1340061da546Spatrick RegisterValue reg_value;
1341061da546Spatrick
1342061da546Spatrick if (!frame_sp.get()) {
1343061da546Spatrick err.SetErrorStringWithFormat(
1344061da546Spatrick "couldn't materialize register %s without a stack frame",
1345061da546Spatrick m_register_info.name);
1346061da546Spatrick return;
1347061da546Spatrick }
1348061da546Spatrick
1349061da546Spatrick lldb::RegisterContextSP reg_context_sp = frame_sp->GetRegisterContext();
1350061da546Spatrick
1351061da546Spatrick if (!reg_context_sp->ReadRegister(&m_register_info, reg_value)) {
1352061da546Spatrick err.SetErrorStringWithFormat("couldn't read the value of register %s",
1353061da546Spatrick m_register_info.name);
1354061da546Spatrick return;
1355061da546Spatrick }
1356061da546Spatrick
1357061da546Spatrick DataExtractor register_data;
1358061da546Spatrick
1359061da546Spatrick if (!reg_value.GetData(register_data)) {
1360061da546Spatrick err.SetErrorStringWithFormat("couldn't get the data for register %s",
1361061da546Spatrick m_register_info.name);
1362061da546Spatrick return;
1363061da546Spatrick }
1364061da546Spatrick
1365061da546Spatrick if (register_data.GetByteSize() != m_register_info.byte_size) {
1366061da546Spatrick err.SetErrorStringWithFormat(
1367061da546Spatrick "data for register %s had size %llu but we expected %llu",
1368061da546Spatrick m_register_info.name, (unsigned long long)register_data.GetByteSize(),
1369061da546Spatrick (unsigned long long)m_register_info.byte_size);
1370061da546Spatrick return;
1371061da546Spatrick }
1372061da546Spatrick
1373061da546Spatrick m_register_contents = std::make_shared<DataBufferHeap>(
1374061da546Spatrick register_data.GetDataStart(), register_data.GetByteSize());
1375061da546Spatrick
1376061da546Spatrick Status write_error;
1377061da546Spatrick
1378061da546Spatrick map.WriteMemory(load_addr, register_data.GetDataStart(),
1379061da546Spatrick register_data.GetByteSize(), write_error);
1380061da546Spatrick
1381061da546Spatrick if (!write_error.Success()) {
1382061da546Spatrick err.SetErrorStringWithFormat(
1383061da546Spatrick "couldn't write the contents of register %s: %s",
1384061da546Spatrick m_register_info.name, write_error.AsCString());
1385061da546Spatrick return;
1386061da546Spatrick }
1387061da546Spatrick }
1388061da546Spatrick
Dematerialize(lldb::StackFrameSP & frame_sp,IRMemoryMap & map,lldb::addr_t process_address,lldb::addr_t frame_top,lldb::addr_t frame_bottom,Status & err)1389061da546Spatrick void Dematerialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1390061da546Spatrick lldb::addr_t process_address, lldb::addr_t frame_top,
1391061da546Spatrick lldb::addr_t frame_bottom, Status &err) override {
1392*f6aab3d8Srobert Log *log = GetLog(LLDBLog::Expressions);
1393061da546Spatrick
1394061da546Spatrick const lldb::addr_t load_addr = process_address + m_offset;
1395061da546Spatrick
1396061da546Spatrick if (log) {
1397061da546Spatrick LLDB_LOGF(log,
1398061da546Spatrick "EntityRegister::Dematerialize [address = 0x%" PRIx64
1399061da546Spatrick ", m_register_info = %s]",
1400061da546Spatrick (uint64_t)load_addr, m_register_info.name);
1401061da546Spatrick }
1402061da546Spatrick
1403061da546Spatrick Status extract_error;
1404061da546Spatrick
1405061da546Spatrick DataExtractor register_data;
1406061da546Spatrick
1407061da546Spatrick if (!frame_sp.get()) {
1408061da546Spatrick err.SetErrorStringWithFormat(
1409061da546Spatrick "couldn't dematerialize register %s without a stack frame",
1410061da546Spatrick m_register_info.name);
1411061da546Spatrick return;
1412061da546Spatrick }
1413061da546Spatrick
1414061da546Spatrick lldb::RegisterContextSP reg_context_sp = frame_sp->GetRegisterContext();
1415061da546Spatrick
1416061da546Spatrick map.GetMemoryData(register_data, load_addr, m_register_info.byte_size,
1417061da546Spatrick extract_error);
1418061da546Spatrick
1419061da546Spatrick if (!extract_error.Success()) {
1420061da546Spatrick err.SetErrorStringWithFormat("couldn't get the data for register %s: %s",
1421061da546Spatrick m_register_info.name,
1422061da546Spatrick extract_error.AsCString());
1423061da546Spatrick return;
1424061da546Spatrick }
1425061da546Spatrick
1426061da546Spatrick if (!memcmp(register_data.GetDataStart(), m_register_contents->GetBytes(),
1427061da546Spatrick register_data.GetByteSize())) {
1428061da546Spatrick // No write required, and in particular we avoid errors if the register
1429061da546Spatrick // wasn't writable
1430061da546Spatrick
1431061da546Spatrick m_register_contents.reset();
1432061da546Spatrick return;
1433061da546Spatrick }
1434061da546Spatrick
1435061da546Spatrick m_register_contents.reset();
1436061da546Spatrick
1437be691f3bSpatrick RegisterValue register_value(register_data.GetData(),
1438be691f3bSpatrick register_data.GetByteOrder());
1439061da546Spatrick
1440061da546Spatrick if (!reg_context_sp->WriteRegister(&m_register_info, register_value)) {
1441061da546Spatrick err.SetErrorStringWithFormat("couldn't write the value of register %s",
1442061da546Spatrick m_register_info.name);
1443061da546Spatrick return;
1444061da546Spatrick }
1445061da546Spatrick }
1446061da546Spatrick
DumpToLog(IRMemoryMap & map,lldb::addr_t process_address,Log * log)1447061da546Spatrick void DumpToLog(IRMemoryMap &map, lldb::addr_t process_address,
1448061da546Spatrick Log *log) override {
1449061da546Spatrick StreamString dump_stream;
1450061da546Spatrick
1451061da546Spatrick Status err;
1452061da546Spatrick
1453061da546Spatrick const lldb::addr_t load_addr = process_address + m_offset;
1454061da546Spatrick
1455061da546Spatrick dump_stream.Printf("0x%" PRIx64 ": EntityRegister (%s)\n", load_addr,
1456061da546Spatrick m_register_info.name);
1457061da546Spatrick
1458061da546Spatrick {
1459061da546Spatrick dump_stream.Printf("Value:\n");
1460061da546Spatrick
1461061da546Spatrick DataBufferHeap data(m_size, 0);
1462061da546Spatrick
1463061da546Spatrick map.ReadMemory(data.GetBytes(), load_addr, m_size, err);
1464061da546Spatrick
1465061da546Spatrick if (!err.Success()) {
1466061da546Spatrick dump_stream.Printf(" <could not be read>\n");
1467061da546Spatrick } else {
1468061da546Spatrick DumpHexBytes(&dump_stream, data.GetBytes(), data.GetByteSize(), 16,
1469061da546Spatrick load_addr);
1470061da546Spatrick
1471061da546Spatrick dump_stream.PutChar('\n');
1472061da546Spatrick }
1473061da546Spatrick }
1474061da546Spatrick
1475061da546Spatrick log->PutString(dump_stream.GetString());
1476061da546Spatrick }
1477061da546Spatrick
Wipe(IRMemoryMap & map,lldb::addr_t process_address)1478061da546Spatrick void Wipe(IRMemoryMap &map, lldb::addr_t process_address) override {}
1479061da546Spatrick
1480061da546Spatrick private:
1481061da546Spatrick RegisterInfo m_register_info;
1482061da546Spatrick lldb::DataBufferSP m_register_contents;
1483061da546Spatrick };
1484061da546Spatrick
AddRegister(const RegisterInfo & register_info,Status & err)1485061da546Spatrick uint32_t Materializer::AddRegister(const RegisterInfo ®ister_info,
1486061da546Spatrick Status &err) {
1487061da546Spatrick EntityVector::iterator iter = m_entities.insert(m_entities.end(), EntityUP());
1488dda28197Spatrick *iter = std::make_unique<EntityRegister>(register_info);
1489061da546Spatrick uint32_t ret = AddStructMember(**iter);
1490061da546Spatrick (*iter)->SetOffset(ret);
1491061da546Spatrick return ret;
1492061da546Spatrick }
1493061da546Spatrick
~Materializer()1494061da546Spatrick Materializer::~Materializer() {
1495061da546Spatrick DematerializerSP dematerializer_sp = m_dematerializer_wp.lock();
1496061da546Spatrick
1497061da546Spatrick if (dematerializer_sp)
1498061da546Spatrick dematerializer_sp->Wipe();
1499061da546Spatrick }
1500061da546Spatrick
1501061da546Spatrick Materializer::DematerializerSP
Materialize(lldb::StackFrameSP & frame_sp,IRMemoryMap & map,lldb::addr_t process_address,Status & error)1502061da546Spatrick Materializer::Materialize(lldb::StackFrameSP &frame_sp, IRMemoryMap &map,
1503061da546Spatrick lldb::addr_t process_address, Status &error) {
1504061da546Spatrick ExecutionContextScope *exe_scope = frame_sp.get();
1505061da546Spatrick if (!exe_scope)
1506061da546Spatrick exe_scope = map.GetBestExecutionContextScope();
1507061da546Spatrick
1508061da546Spatrick DematerializerSP dematerializer_sp = m_dematerializer_wp.lock();
1509061da546Spatrick
1510061da546Spatrick if (dematerializer_sp) {
1511061da546Spatrick error.SetErrorToGenericError();
1512061da546Spatrick error.SetErrorString("Couldn't materialize: already materialized");
1513061da546Spatrick }
1514061da546Spatrick
1515061da546Spatrick DematerializerSP ret(
1516061da546Spatrick new Dematerializer(*this, frame_sp, map, process_address));
1517061da546Spatrick
1518061da546Spatrick if (!exe_scope) {
1519061da546Spatrick error.SetErrorToGenericError();
1520061da546Spatrick error.SetErrorString("Couldn't materialize: target doesn't exist");
1521061da546Spatrick }
1522061da546Spatrick
1523061da546Spatrick for (EntityUP &entity_up : m_entities) {
1524061da546Spatrick entity_up->Materialize(frame_sp, map, process_address, error);
1525061da546Spatrick
1526061da546Spatrick if (!error.Success())
1527061da546Spatrick return DematerializerSP();
1528061da546Spatrick }
1529061da546Spatrick
1530*f6aab3d8Srobert if (Log *log = GetLog(LLDBLog::Expressions)) {
1531061da546Spatrick LLDB_LOGF(
1532061da546Spatrick log,
1533061da546Spatrick "Materializer::Materialize (frame_sp = %p, process_address = 0x%" PRIx64
1534061da546Spatrick ") materialized:",
1535061da546Spatrick static_cast<void *>(frame_sp.get()), process_address);
1536061da546Spatrick for (EntityUP &entity_up : m_entities)
1537061da546Spatrick entity_up->DumpToLog(map, process_address, log);
1538061da546Spatrick }
1539061da546Spatrick
1540061da546Spatrick m_dematerializer_wp = ret;
1541061da546Spatrick
1542061da546Spatrick return ret;
1543061da546Spatrick }
1544061da546Spatrick
Dematerialize(Status & error,lldb::addr_t frame_bottom,lldb::addr_t frame_top)1545061da546Spatrick void Materializer::Dematerializer::Dematerialize(Status &error,
1546061da546Spatrick lldb::addr_t frame_bottom,
1547061da546Spatrick lldb::addr_t frame_top) {
1548061da546Spatrick lldb::StackFrameSP frame_sp;
1549061da546Spatrick
1550061da546Spatrick lldb::ThreadSP thread_sp = m_thread_wp.lock();
1551061da546Spatrick if (thread_sp)
1552061da546Spatrick frame_sp = thread_sp->GetFrameWithStackID(m_stack_id);
1553061da546Spatrick
1554dda28197Spatrick ExecutionContextScope *exe_scope = frame_sp.get();
1555dda28197Spatrick if (!exe_scope)
1556dda28197Spatrick exe_scope = m_map->GetBestExecutionContextScope();
1557061da546Spatrick
1558061da546Spatrick if (!IsValid()) {
1559061da546Spatrick error.SetErrorToGenericError();
1560061da546Spatrick error.SetErrorString("Couldn't dematerialize: invalid dematerializer");
1561061da546Spatrick }
1562061da546Spatrick
1563061da546Spatrick if (!exe_scope) {
1564061da546Spatrick error.SetErrorToGenericError();
1565061da546Spatrick error.SetErrorString("Couldn't dematerialize: target is gone");
1566061da546Spatrick } else {
1567*f6aab3d8Srobert if (Log *log = GetLog(LLDBLog::Expressions)) {
1568061da546Spatrick LLDB_LOGF(log,
1569061da546Spatrick "Materializer::Dematerialize (frame_sp = %p, process_address "
1570061da546Spatrick "= 0x%" PRIx64 ") about to dematerialize:",
1571061da546Spatrick static_cast<void *>(frame_sp.get()), m_process_address);
1572061da546Spatrick for (EntityUP &entity_up : m_materializer->m_entities)
1573061da546Spatrick entity_up->DumpToLog(*m_map, m_process_address, log);
1574061da546Spatrick }
1575061da546Spatrick
1576061da546Spatrick for (EntityUP &entity_up : m_materializer->m_entities) {
1577061da546Spatrick entity_up->Dematerialize(frame_sp, *m_map, m_process_address, frame_top,
1578061da546Spatrick frame_bottom, error);
1579061da546Spatrick
1580061da546Spatrick if (!error.Success())
1581061da546Spatrick break;
1582061da546Spatrick }
1583061da546Spatrick }
1584061da546Spatrick
1585061da546Spatrick Wipe();
1586061da546Spatrick }
1587061da546Spatrick
Wipe()1588061da546Spatrick void Materializer::Dematerializer::Wipe() {
1589061da546Spatrick if (!IsValid())
1590061da546Spatrick return;
1591061da546Spatrick
1592061da546Spatrick for (EntityUP &entity_up : m_materializer->m_entities) {
1593061da546Spatrick entity_up->Wipe(*m_map, m_process_address);
1594061da546Spatrick }
1595061da546Spatrick
1596061da546Spatrick m_materializer = nullptr;
1597061da546Spatrick m_map = nullptr;
1598061da546Spatrick m_process_address = LLDB_INVALID_ADDRESS;
1599061da546Spatrick }
1600061da546Spatrick
1601061da546Spatrick Materializer::PersistentVariableDelegate::~PersistentVariableDelegate() =
1602061da546Spatrick default;
1603