1 | //===-- ValueObjectMemory.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/ValueObject/ValueObjectMemory.h" |
10 | #include "lldb/Core/Value.h" |
11 | #include "lldb/Symbol/Type.h" |
12 | #include "lldb/Target/ExecutionContext.h" |
13 | #include "lldb/Target/Target.h" |
14 | #include "lldb/Utility/DataExtractor.h" |
15 | #include "lldb/Utility/Scalar.h" |
16 | #include "lldb/Utility/Status.h" |
17 | #include "lldb/ValueObject/ValueObject.h" |
18 | #include "lldb/lldb-types.h" |
19 | #include "llvm/Support/ErrorHandling.h" |
20 | |
21 | #include <cassert> |
22 | #include <memory> |
23 | #include <optional> |
24 | |
25 | namespace lldb_private { |
26 | class ExecutionContextScope; |
27 | } |
28 | |
29 | using namespace lldb; |
30 | using namespace lldb_private; |
31 | |
32 | ValueObjectSP ValueObjectMemory::Create(ExecutionContextScope *exe_scope, |
33 | llvm::StringRef name, |
34 | const Address &address, |
35 | lldb::TypeSP &type_sp) { |
36 | auto manager_sp = ValueObjectManager::Create(); |
37 | return (new ValueObjectMemory(exe_scope, *manager_sp, name, address, type_sp)) |
38 | ->GetSP(); |
39 | } |
40 | |
41 | ValueObjectSP ValueObjectMemory::Create(ExecutionContextScope *exe_scope, |
42 | llvm::StringRef name, |
43 | const Address &address, |
44 | const CompilerType &ast_type) { |
45 | auto manager_sp = ValueObjectManager::Create(); |
46 | return (new ValueObjectMemory(exe_scope, *manager_sp, name, address, |
47 | ast_type)) |
48 | ->GetSP(); |
49 | } |
50 | |
51 | ValueObjectMemory::ValueObjectMemory(ExecutionContextScope *exe_scope, |
52 | ValueObjectManager &manager, |
53 | llvm::StringRef name, |
54 | const Address &address, |
55 | lldb::TypeSP &type_sp) |
56 | : ValueObject(exe_scope, manager), m_address(address), m_type_sp(type_sp), |
57 | m_compiler_type() { |
58 | // Do not attempt to construct one of these objects with no variable! |
59 | assert(m_type_sp.get() != nullptr); |
60 | SetName(ConstString(name)); |
61 | m_value.SetContext(context_type: Value::ContextType::LLDBType, p: m_type_sp.get()); |
62 | TargetSP target_sp(GetTargetSP()); |
63 | lldb::addr_t load_address = m_address.GetLoadAddress(target: target_sp.get()); |
64 | if (load_address != LLDB_INVALID_ADDRESS) { |
65 | m_value.SetValueType(Value::ValueType::LoadAddress); |
66 | m_value.GetScalar() = load_address; |
67 | } else { |
68 | lldb::addr_t file_address = m_address.GetFileAddress(); |
69 | if (file_address != LLDB_INVALID_ADDRESS) { |
70 | m_value.SetValueType(Value::ValueType::FileAddress); |
71 | m_value.GetScalar() = file_address; |
72 | } else { |
73 | m_value.GetScalar() = m_address.GetOffset(); |
74 | m_value.SetValueType(Value::ValueType::Scalar); |
75 | } |
76 | } |
77 | } |
78 | |
79 | ValueObjectMemory::ValueObjectMemory(ExecutionContextScope *exe_scope, |
80 | ValueObjectManager &manager, |
81 | llvm::StringRef name, |
82 | const Address &address, |
83 | const CompilerType &ast_type) |
84 | : ValueObject(exe_scope, manager), m_address(address), m_type_sp(), |
85 | m_compiler_type(ast_type) { |
86 | // Do not attempt to construct one of these objects with no variable! |
87 | assert(m_compiler_type.IsValid()); |
88 | |
89 | TargetSP target_sp(GetTargetSP()); |
90 | |
91 | SetName(ConstString(name)); |
92 | m_value.SetCompilerType(m_compiler_type); |
93 | lldb::addr_t load_address = m_address.GetLoadAddress(target: target_sp.get()); |
94 | if (load_address != LLDB_INVALID_ADDRESS) { |
95 | m_value.SetValueType(Value::ValueType::LoadAddress); |
96 | m_value.GetScalar() = load_address; |
97 | } else { |
98 | lldb::addr_t file_address = m_address.GetFileAddress(); |
99 | if (file_address != LLDB_INVALID_ADDRESS) { |
100 | m_value.SetValueType(Value::ValueType::FileAddress); |
101 | m_value.GetScalar() = file_address; |
102 | } else { |
103 | m_value.GetScalar() = m_address.GetOffset(); |
104 | m_value.SetValueType(Value::ValueType::Scalar); |
105 | } |
106 | } |
107 | } |
108 | |
109 | ValueObjectMemory::~ValueObjectMemory() = default; |
110 | |
111 | CompilerType ValueObjectMemory::GetCompilerTypeImpl() { |
112 | if (m_type_sp) |
113 | return m_type_sp->GetForwardCompilerType(); |
114 | return m_compiler_type; |
115 | } |
116 | |
117 | ConstString ValueObjectMemory::GetTypeName() { |
118 | if (m_type_sp) |
119 | return m_type_sp->GetName(); |
120 | return m_compiler_type.GetTypeName(); |
121 | } |
122 | |
123 | ConstString ValueObjectMemory::GetDisplayTypeName() { |
124 | if (m_type_sp) |
125 | return m_type_sp->GetForwardCompilerType().GetDisplayTypeName(); |
126 | return m_compiler_type.GetDisplayTypeName(); |
127 | } |
128 | |
129 | llvm::Expected<uint32_t> ValueObjectMemory::CalculateNumChildren(uint32_t max) { |
130 | if (m_type_sp) { |
131 | auto child_count = m_type_sp->GetNumChildren(omit_empty_base_classes: true); |
132 | if (!child_count) |
133 | return child_count; |
134 | return *child_count <= max ? *child_count : max; |
135 | } |
136 | |
137 | ExecutionContext exe_ctx(GetExecutionContextRef()); |
138 | const bool omit_empty_base_classes = true; |
139 | auto child_count = |
140 | m_compiler_type.GetNumChildren(omit_empty_base_classes, exe_ctx: &exe_ctx); |
141 | if (!child_count) |
142 | return child_count; |
143 | return *child_count <= max ? *child_count : max; |
144 | } |
145 | |
146 | llvm::Expected<uint64_t> ValueObjectMemory::GetByteSize() { |
147 | ExecutionContext exe_ctx(GetExecutionContextRef()); |
148 | if (m_type_sp) { |
149 | if (auto size = |
150 | m_type_sp->GetByteSize(exe_scope: exe_ctx.GetBestExecutionContextScope())) |
151 | return *size; |
152 | return llvm::createStringError(Fmt: "could not get byte size of memory object" ); |
153 | } |
154 | return m_compiler_type.GetByteSize(exe_scope: exe_ctx.GetBestExecutionContextScope()); |
155 | } |
156 | |
157 | lldb::ValueType ValueObjectMemory::GetValueType() const { |
158 | // RETHINK: Should this be inherited from somewhere? |
159 | return lldb::eValueTypeVariableGlobal; |
160 | } |
161 | |
162 | bool ValueObjectMemory::UpdateValue() { |
163 | SetValueIsValid(false); |
164 | m_error.Clear(); |
165 | |
166 | ExecutionContext exe_ctx(GetExecutionContextRef()); |
167 | |
168 | Target *target = exe_ctx.GetTargetPtr(); |
169 | if (target) { |
170 | m_data.SetByteOrder(target->GetArchitecture().GetByteOrder()); |
171 | m_data.SetAddressByteSize(target->GetArchitecture().GetAddressByteSize()); |
172 | } |
173 | |
174 | Value old_value(m_value); |
175 | if (m_address.IsValid()) { |
176 | Value::ValueType value_type = m_value.GetValueType(); |
177 | |
178 | switch (value_type) { |
179 | case Value::ValueType::Invalid: |
180 | m_error = Status::FromErrorString(str: "Invalid value" ); |
181 | return false; |
182 | case Value::ValueType::Scalar: |
183 | // The variable value is in the Scalar value inside the m_value. We can |
184 | // point our m_data right to it. |
185 | m_error = m_value.GetValueAsData(exe_ctx: &exe_ctx, data&: m_data, module: GetModule().get()); |
186 | break; |
187 | |
188 | case Value::ValueType::FileAddress: |
189 | case Value::ValueType::LoadAddress: |
190 | case Value::ValueType::HostAddress: |
191 | // The DWARF expression result was an address in the inferior process. If |
192 | // this variable is an aggregate type, we just need the address as the |
193 | // main value as all child variable objects will rely upon this location |
194 | // and add an offset and then read their own values as needed. If this |
195 | // variable is a simple type, we read all data for it into m_data. Make |
196 | // sure this type has a value before we try and read it |
197 | |
198 | // If we have a file address, convert it to a load address if we can. |
199 | if (value_type == Value::ValueType::FileAddress && |
200 | exe_ctx.GetProcessPtr()) { |
201 | lldb::addr_t load_addr = m_address.GetLoadAddress(target); |
202 | if (load_addr != LLDB_INVALID_ADDRESS) { |
203 | m_value.SetValueType(Value::ValueType::LoadAddress); |
204 | m_value.GetScalar() = load_addr; |
205 | } |
206 | } |
207 | |
208 | if (!CanProvideValue()) { |
209 | // this value object represents an aggregate type whose children have |
210 | // values, but this object does not. So we say we are changed if our |
211 | // location has changed. |
212 | SetValueDidChange(value_type != old_value.GetValueType() || |
213 | m_value.GetScalar() != old_value.GetScalar()); |
214 | } else { |
215 | // Copy the Value and set the context to use our Variable so it can |
216 | // extract read its value into m_data appropriately |
217 | Value value(m_value); |
218 | if (m_type_sp) |
219 | value.SetContext(context_type: Value::ContextType::LLDBType, p: m_type_sp.get()); |
220 | else { |
221 | value.SetCompilerType(m_compiler_type); |
222 | } |
223 | |
224 | m_error = value.GetValueAsData(exe_ctx: &exe_ctx, data&: m_data, module: GetModule().get()); |
225 | } |
226 | break; |
227 | } |
228 | |
229 | SetValueIsValid(m_error.Success()); |
230 | } |
231 | return m_error.Success(); |
232 | } |
233 | |
234 | bool ValueObjectMemory::IsInScope() { |
235 | // FIXME: Maybe try to read the memory address, and if that works, then |
236 | // we are in scope? |
237 | return true; |
238 | } |
239 | |
240 | lldb::ModuleSP ValueObjectMemory::GetModule() { return m_address.GetModule(); } |
241 | |