/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/source/Core/Value.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===-- Value.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/Core/Value.h" |
10 | | |
11 | | #include "lldb/Core/Address.h" |
12 | | #include "lldb/Core/Module.h" |
13 | | #include "lldb/Symbol/CompilerType.h" |
14 | | #include "lldb/Symbol/ObjectFile.h" |
15 | | #include "lldb/Symbol/SymbolContext.h" |
16 | | #include "lldb/Symbol/Type.h" |
17 | | #include "lldb/Symbol/Variable.h" |
18 | | #include "lldb/Target/ExecutionContext.h" |
19 | | #include "lldb/Target/Process.h" |
20 | | #include "lldb/Target/SectionLoadList.h" |
21 | | #include "lldb/Target/Target.h" |
22 | | #include "lldb/Utility/ConstString.h" |
23 | | #include "lldb/Utility/DataBufferHeap.h" |
24 | | #include "lldb/Utility/DataExtractor.h" |
25 | | #include "lldb/Utility/Endian.h" |
26 | | #include "lldb/Utility/FileSpec.h" |
27 | | #include "lldb/Utility/State.h" |
28 | | #include "lldb/Utility/Stream.h" |
29 | | #include "lldb/lldb-defines.h" |
30 | | #include "lldb/lldb-forward.h" |
31 | | #include "lldb/lldb-types.h" |
32 | | |
33 | | #include <memory> |
34 | | #include <optional> |
35 | | #include <string> |
36 | | |
37 | | #include <cinttypes> |
38 | | |
39 | | using namespace lldb; |
40 | | using namespace lldb_private; |
41 | | |
42 | 223k | Value::Value() : m_value(), m_compiler_type(), m_data_buffer() {} |
43 | | |
44 | | Value::Value(const Scalar &scalar) |
45 | 14.6k | : m_value(scalar), m_compiler_type(), m_data_buffer() {} |
46 | | |
47 | | Value::Value(const void *bytes, int len) |
48 | 22 | : m_value(), m_compiler_type(), m_value_type(ValueType::HostAddress), |
49 | 22 | m_data_buffer() { |
50 | 22 | SetBytes(bytes, len); |
51 | 22 | } |
52 | | |
53 | | Value::Value(const Value &v) |
54 | 181k | : m_value(v.m_value), m_compiler_type(v.m_compiler_type), |
55 | 181k | m_context(v.m_context), m_value_type(v.m_value_type), |
56 | 181k | m_context_type(v.m_context_type), m_data_buffer() { |
57 | 181k | const uintptr_t rhs_value = |
58 | 181k | (uintptr_t)v.m_value.ULongLong(LLDB_INVALID_ADDRESS); |
59 | 181k | if ((rhs_value != 0) && |
60 | 181k | (rhs_value == (uintptr_t)v.m_data_buffer.GetBytes())181k ) { |
61 | 878 | m_data_buffer.CopyData(v.m_data_buffer.GetBytes(), |
62 | 878 | v.m_data_buffer.GetByteSize()); |
63 | | |
64 | 878 | m_value = (uintptr_t)m_data_buffer.GetBytes(); |
65 | 878 | } |
66 | 181k | } |
67 | | |
68 | 50.7k | Value &Value::operator=(const Value &rhs) { |
69 | 50.7k | if (this != &rhs) { |
70 | 50.7k | m_value = rhs.m_value; |
71 | 50.7k | m_compiler_type = rhs.m_compiler_type; |
72 | 50.7k | m_context = rhs.m_context; |
73 | 50.7k | m_value_type = rhs.m_value_type; |
74 | 50.7k | m_context_type = rhs.m_context_type; |
75 | 50.7k | const uintptr_t rhs_value = |
76 | 50.7k | (uintptr_t)rhs.m_value.ULongLong(LLDB_INVALID_ADDRESS); |
77 | 50.7k | if ((rhs_value != 0) && |
78 | 50.7k | (rhs_value == (uintptr_t)rhs.m_data_buffer.GetBytes())50.6k ) { |
79 | 468 | m_data_buffer.CopyData(rhs.m_data_buffer.GetBytes(), |
80 | 468 | rhs.m_data_buffer.GetByteSize()); |
81 | | |
82 | 468 | m_value = (uintptr_t)m_data_buffer.GetBytes(); |
83 | 468 | } |
84 | 50.7k | } |
85 | 50.7k | return *this; |
86 | 50.7k | } |
87 | | |
88 | 60 | void Value::SetBytes(const void *bytes, int len) { |
89 | 60 | m_value_type = ValueType::HostAddress; |
90 | 60 | m_data_buffer.CopyData(bytes, len); |
91 | 60 | m_value = (uintptr_t)m_data_buffer.GetBytes(); |
92 | 60 | } |
93 | | |
94 | 0 | void Value::AppendBytes(const void *bytes, int len) { |
95 | 0 | m_value_type = ValueType::HostAddress; |
96 | 0 | m_data_buffer.AppendData(bytes, len); |
97 | 0 | m_value = (uintptr_t)m_data_buffer.GetBytes(); |
98 | 0 | } |
99 | | |
100 | 0 | void Value::Dump(Stream *strm) { |
101 | 0 | if (!strm) |
102 | 0 | return; |
103 | 0 | m_value.GetValue(*strm, true); |
104 | 0 | strm->Printf(", value_type = %s, context = %p, context_type = %s", |
105 | 0 | Value::GetValueTypeAsCString(m_value_type), m_context, |
106 | 0 | Value::GetContextTypeAsCString(m_context_type)); |
107 | 0 | } |
108 | | |
109 | 260k | Value::ValueType Value::GetValueType() const { return m_value_type; } |
110 | | |
111 | 6.76k | AddressType Value::GetValueAddressType() const { |
112 | 6.76k | switch (m_value_type) { |
113 | 0 | case ValueType::Invalid: |
114 | 0 | case ValueType::Scalar: |
115 | 0 | break; |
116 | 6.40k | case ValueType::LoadAddress: |
117 | 6.40k | return eAddressTypeLoad; |
118 | 174 | case ValueType::FileAddress: |
119 | 174 | return eAddressTypeFile; |
120 | 184 | case ValueType::HostAddress: |
121 | 184 | return eAddressTypeHost; |
122 | 6.76k | } |
123 | 0 | return eAddressTypeInvalid; |
124 | 6.76k | } |
125 | | |
126 | 0 | Value::ValueType Value::GetValueTypeFromAddressType(AddressType address_type) { |
127 | 0 | switch (address_type) { |
128 | 0 | case eAddressTypeFile: |
129 | 0 | return Value::ValueType::FileAddress; |
130 | 0 | case eAddressTypeLoad: |
131 | 0 | return Value::ValueType::LoadAddress; |
132 | 0 | case eAddressTypeHost: |
133 | 0 | return Value::ValueType::HostAddress; |
134 | 0 | case eAddressTypeInvalid: |
135 | 0 | return Value::ValueType::Invalid; |
136 | 0 | } |
137 | 0 | llvm_unreachable("Unexpected address type!"); |
138 | 0 | } |
139 | | |
140 | 22.2k | RegisterInfo *Value::GetRegisterInfo() const { |
141 | 22.2k | if (m_context_type == ContextType::RegisterInfo) |
142 | 9.63k | return static_cast<RegisterInfo *>(m_context); |
143 | 12.5k | return nullptr; |
144 | 22.2k | } |
145 | | |
146 | 0 | Type *Value::GetType() { |
147 | 0 | if (m_context_type == ContextType::LLDBType) |
148 | 0 | return static_cast<Type *>(m_context); |
149 | 0 | return nullptr; |
150 | 0 | } |
151 | | |
152 | 29 | size_t Value::AppendDataToHostBuffer(const Value &rhs) { |
153 | 29 | if (this == &rhs) |
154 | 0 | return 0; |
155 | | |
156 | 29 | size_t curr_size = m_data_buffer.GetByteSize(); |
157 | 29 | Status error; |
158 | 29 | switch (rhs.GetValueType()) { |
159 | 0 | case ValueType::Invalid: |
160 | 0 | return 0; |
161 | 20 | case ValueType::Scalar: { |
162 | 20 | const size_t scalar_size = rhs.m_value.GetByteSize(); |
163 | 20 | if (scalar_size > 0) { |
164 | 20 | const size_t new_size = curr_size + scalar_size; |
165 | 20 | if (ResizeData(new_size) == new_size) { |
166 | 20 | rhs.m_value.GetAsMemoryData(m_data_buffer.GetBytes() + curr_size, |
167 | 20 | scalar_size, endian::InlHostByteOrder(), |
168 | 20 | error); |
169 | 20 | return scalar_size; |
170 | 20 | } |
171 | 20 | } |
172 | 20 | } break0 ; |
173 | 0 | case ValueType::FileAddress: |
174 | 0 | case ValueType::LoadAddress: |
175 | 9 | case ValueType::HostAddress: { |
176 | 9 | const uint8_t *src = rhs.GetBuffer().GetBytes(); |
177 | 9 | const size_t src_len = rhs.GetBuffer().GetByteSize(); |
178 | 9 | if (src && src_len > 0) { |
179 | 9 | const size_t new_size = curr_size + src_len; |
180 | 9 | if (ResizeData(new_size) == new_size) { |
181 | 9 | ::memcpy(m_data_buffer.GetBytes() + curr_size, src, src_len); |
182 | 9 | return src_len; |
183 | 9 | } |
184 | 9 | } |
185 | 9 | } break0 ; |
186 | 29 | } |
187 | 0 | return 0; |
188 | 29 | } |
189 | | |
190 | 6.91k | size_t Value::ResizeData(size_t len) { |
191 | 6.91k | m_value_type = ValueType::HostAddress; |
192 | 6.91k | m_data_buffer.SetByteSize(len); |
193 | 6.91k | m_value = (uintptr_t)m_data_buffer.GetBytes(); |
194 | 6.91k | return m_data_buffer.GetByteSize(); |
195 | 6.91k | } |
196 | | |
197 | 0 | bool Value::ValueOf(ExecutionContext *exe_ctx) { |
198 | 0 | switch (m_context_type) { |
199 | 0 | case ContextType::Invalid: |
200 | 0 | case ContextType::RegisterInfo: // RegisterInfo * |
201 | 0 | case ContextType::LLDBType: // Type * |
202 | 0 | break; |
203 | | |
204 | 0 | case ContextType::Variable: // Variable * |
205 | 0 | ResolveValue(exe_ctx); |
206 | 0 | return true; |
207 | 0 | } |
208 | 0 | return false; |
209 | 0 | } |
210 | | |
211 | 116k | uint64_t Value::GetValueByteSize(Status *error_ptr, ExecutionContext *exe_ctx) { |
212 | 116k | switch (m_context_type) { |
213 | 1.33k | case ContextType::RegisterInfo: // RegisterInfo * |
214 | 1.33k | if (GetRegisterInfo()) { |
215 | 1.33k | if (error_ptr) |
216 | 1.33k | error_ptr->Clear(); |
217 | 1.33k | return GetRegisterInfo()->byte_size; |
218 | 1.33k | } |
219 | 0 | break; |
220 | | |
221 | 95.2k | case ContextType::Invalid: |
222 | 95.2k | case ContextType::LLDBType: // Type * |
223 | 115k | case ContextType::Variable: // Variable * |
224 | 115k | { |
225 | 115k | auto *scope = exe_ctx ? exe_ctx->GetBestExecutionContextScope() : nullptr0 ; |
226 | 115k | if (std::optional<uint64_t> size = GetCompilerType().GetByteSize(scope)) { |
227 | 115k | if (error_ptr) |
228 | 115k | error_ptr->Clear(); |
229 | 115k | return *size; |
230 | 115k | } |
231 | 1 | break; |
232 | 115k | } |
233 | 116k | } |
234 | 1 | if (error_ptr && error_ptr->Success()) |
235 | 1 | error_ptr->SetErrorString("Unable to determine byte size."); |
236 | 1 | return 0; |
237 | 116k | } |
238 | | |
239 | 1.16M | const CompilerType &Value::GetCompilerType() { |
240 | 1.16M | if (!m_compiler_type.IsValid()) { |
241 | 5.39k | switch (m_context_type) { |
242 | 417 | case ContextType::Invalid: |
243 | 417 | break; |
244 | | |
245 | 4.93k | case ContextType::RegisterInfo: |
246 | 4.93k | break; // TODO: Eventually convert into a compiler type? |
247 | | |
248 | 0 | case ContextType::LLDBType: { |
249 | 0 | Type *lldb_type = GetType(); |
250 | 0 | if (lldb_type) |
251 | 0 | m_compiler_type = lldb_type->GetForwardCompilerType(); |
252 | 0 | } break; |
253 | | |
254 | 40 | case ContextType::Variable: { |
255 | 40 | Variable *variable = GetVariable(); |
256 | 40 | if (variable) { |
257 | 40 | Type *variable_type = variable->GetType(); |
258 | 40 | if (variable_type) |
259 | 38 | m_compiler_type = variable_type->GetForwardCompilerType(); |
260 | 40 | } |
261 | 40 | } break; |
262 | 5.39k | } |
263 | 5.39k | } |
264 | | |
265 | 1.16M | return m_compiler_type; |
266 | 1.16M | } |
267 | | |
268 | 121k | void Value::SetCompilerType(const CompilerType &compiler_type) { |
269 | 121k | m_compiler_type = compiler_type; |
270 | 121k | } |
271 | | |
272 | 0 | lldb::Format Value::GetValueDefaultFormat() { |
273 | 0 | switch (m_context_type) { |
274 | 0 | case ContextType::RegisterInfo: |
275 | 0 | if (GetRegisterInfo()) |
276 | 0 | return GetRegisterInfo()->format; |
277 | 0 | break; |
278 | | |
279 | 0 | case ContextType::Invalid: |
280 | 0 | case ContextType::LLDBType: |
281 | 0 | case ContextType::Variable: { |
282 | 0 | const CompilerType &ast_type = GetCompilerType(); |
283 | 0 | if (ast_type.IsValid()) |
284 | 0 | return ast_type.GetFormat(); |
285 | 0 | } break; |
286 | 0 | } |
287 | | |
288 | | // Return a good default in case we can't figure anything out |
289 | 0 | return eFormatHex; |
290 | 0 | } |
291 | | |
292 | 6.87k | bool Value::GetData(DataExtractor &data) { |
293 | 6.87k | switch (m_value_type) { |
294 | 0 | case ValueType::Invalid: |
295 | 0 | return false; |
296 | 0 | case ValueType::Scalar: |
297 | 0 | if (m_value.GetData(data)) |
298 | 0 | return true; |
299 | 0 | break; |
300 | | |
301 | 0 | case ValueType::LoadAddress: |
302 | 0 | case ValueType::FileAddress: |
303 | 6.87k | case ValueType::HostAddress: |
304 | 6.87k | if (m_data_buffer.GetByteSize()) { |
305 | 6.87k | data.SetData(m_data_buffer.GetBytes(), m_data_buffer.GetByteSize(), |
306 | 6.87k | data.GetByteOrder()); |
307 | 6.87k | return true; |
308 | 6.87k | } |
309 | 0 | break; |
310 | 6.87k | } |
311 | | |
312 | 0 | return false; |
313 | 6.87k | } |
314 | | |
315 | | Status Value::GetValueAsData(ExecutionContext *exe_ctx, DataExtractor &data, |
316 | 119k | Module *module) { |
317 | 119k | data.Clear(); |
318 | | |
319 | 119k | Status error; |
320 | 119k | lldb::addr_t address = LLDB_INVALID_ADDRESS; |
321 | 119k | AddressType address_type = eAddressTypeFile; |
322 | 119k | Address file_so_addr; |
323 | 119k | const CompilerType &ast_type = GetCompilerType(); |
324 | 119k | std::optional<uint64_t> type_size = ast_type.GetByteSize( |
325 | 119k | exe_ctx ? exe_ctx->GetBestExecutionContextScope() : nullptr0 ); |
326 | | // Nothing to be done for a zero-sized type. |
327 | 119k | if (type_size && *type_size == 0118k ) |
328 | 16 | return error; |
329 | | |
330 | 119k | switch (m_value_type) { |
331 | 0 | case ValueType::Invalid: |
332 | 0 | error.SetErrorString("invalid value"); |
333 | 0 | break; |
334 | 3.04k | case ValueType::Scalar: { |
335 | 3.04k | data.SetByteOrder(endian::InlHostByteOrder()); |
336 | 3.04k | if (ast_type.IsValid()) |
337 | 3.04k | data.SetAddressByteSize(ast_type.GetPointerByteSize()); |
338 | 0 | else |
339 | 0 | data.SetAddressByteSize(sizeof(void *)); |
340 | | |
341 | 3.04k | uint32_t limit_byte_size = UINT32_MAX; |
342 | | |
343 | 3.04k | if (type_size) |
344 | 3.04k | limit_byte_size = *type_size; |
345 | | |
346 | 3.04k | if (limit_byte_size <= m_value.GetByteSize()) { |
347 | 3.04k | if (m_value.GetData(data, limit_byte_size)) |
348 | 3.04k | return error; // Success; |
349 | 3.04k | } |
350 | | |
351 | 0 | error.SetErrorString("extracting data from value failed"); |
352 | 0 | break; |
353 | 3.04k | } |
354 | 77.2k | case ValueType::LoadAddress: |
355 | 77.2k | if (exe_ctx == nullptr) { |
356 | 0 | error.SetErrorString("can't read load address (no execution context)"); |
357 | 77.2k | } else { |
358 | 77.2k | Process *process = exe_ctx->GetProcessPtr(); |
359 | 77.2k | if (process == nullptr || !process->IsAlive()77.2k ) { |
360 | 5 | Target *target = exe_ctx->GetTargetPtr(); |
361 | 5 | if (target) { |
362 | | // Allow expressions to run and evaluate things when the target has |
363 | | // memory sections loaded. This allows you to use "target modules |
364 | | // load" to load your executable and any shared libraries, then |
365 | | // execute commands where you can look at types in data sections. |
366 | 5 | const SectionLoadList &target_sections = target->GetSectionLoadList(); |
367 | 5 | if (!target_sections.IsEmpty()) { |
368 | 0 | address = m_value.ULongLong(LLDB_INVALID_ADDRESS); |
369 | 0 | if (target_sections.ResolveLoadAddress(address, file_so_addr)) { |
370 | 0 | address_type = eAddressTypeLoad; |
371 | 0 | data.SetByteOrder(target->GetArchitecture().GetByteOrder()); |
372 | 0 | data.SetAddressByteSize( |
373 | 0 | target->GetArchitecture().GetAddressByteSize()); |
374 | 0 | } else |
375 | 0 | address = LLDB_INVALID_ADDRESS; |
376 | 0 | } |
377 | 5 | } else { |
378 | 0 | error.SetErrorString("can't read load address (invalid process)"); |
379 | 0 | } |
380 | 77.2k | } else { |
381 | 77.2k | address = m_value.ULongLong(LLDB_INVALID_ADDRESS); |
382 | 77.2k | address_type = eAddressTypeLoad; |
383 | 77.2k | data.SetByteOrder( |
384 | 77.2k | process->GetTarget().GetArchitecture().GetByteOrder()); |
385 | 77.2k | data.SetAddressByteSize( |
386 | 77.2k | process->GetTarget().GetArchitecture().GetAddressByteSize()); |
387 | 77.2k | } |
388 | 77.2k | } |
389 | 77.2k | break; |
390 | | |
391 | 1.13k | case ValueType::FileAddress: |
392 | 1.13k | if (exe_ctx == nullptr) { |
393 | 0 | error.SetErrorString("can't read file address (no execution context)"); |
394 | 1.13k | } else if (exe_ctx->GetTargetPtr() == nullptr) { |
395 | 0 | error.SetErrorString("can't read file address (invalid target)"); |
396 | 1.13k | } else { |
397 | 1.13k | address = m_value.ULongLong(LLDB_INVALID_ADDRESS); |
398 | 1.13k | if (address == LLDB_INVALID_ADDRESS) { |
399 | 0 | error.SetErrorString("invalid file address"); |
400 | 1.13k | } else { |
401 | 1.13k | if (module == nullptr) { |
402 | | // The only thing we can currently lock down to a module so that we |
403 | | // can resolve a file address, is a variable. |
404 | 0 | Variable *variable = GetVariable(); |
405 | 0 | if (variable) { |
406 | 0 | SymbolContext var_sc; |
407 | 0 | variable->CalculateSymbolContext(&var_sc); |
408 | 0 | module = var_sc.module_sp.get(); |
409 | 0 | } |
410 | 0 | } |
411 | | |
412 | 1.13k | if (module) { |
413 | 1.13k | bool resolved = false; |
414 | 1.13k | ObjectFile *objfile = module->GetObjectFile(); |
415 | 1.13k | if (objfile) { |
416 | 1.13k | Address so_addr(address, objfile->GetSectionList()); |
417 | 1.13k | addr_t load_address = |
418 | 1.13k | so_addr.GetLoadAddress(exe_ctx->GetTargetPtr()); |
419 | 1.13k | bool process_launched_and_stopped = |
420 | 1.13k | exe_ctx->GetProcessPtr() |
421 | 1.13k | ? StateIsStoppedState(exe_ctx->GetProcessPtr()->GetState(), |
422 | 0 | true /* must_exist */) |
423 | 1.13k | : false; |
424 | | // Don't use the load address if the process has exited. |
425 | 1.13k | if (load_address != LLDB_INVALID_ADDRESS && |
426 | 1.13k | process_launched_and_stopped0 ) { |
427 | 0 | resolved = true; |
428 | 0 | address = load_address; |
429 | 0 | address_type = eAddressTypeLoad; |
430 | 0 | data.SetByteOrder( |
431 | 0 | exe_ctx->GetTargetRef().GetArchitecture().GetByteOrder()); |
432 | 0 | data.SetAddressByteSize(exe_ctx->GetTargetRef() |
433 | 0 | .GetArchitecture() |
434 | 0 | .GetAddressByteSize()); |
435 | 1.13k | } else { |
436 | 1.13k | if (so_addr.IsSectionOffset()) { |
437 | 1.13k | resolved = true; |
438 | 1.13k | file_so_addr = so_addr; |
439 | 1.13k | data.SetByteOrder(objfile->GetByteOrder()); |
440 | 1.13k | data.SetAddressByteSize(objfile->GetAddressByteSize()); |
441 | 1.13k | } |
442 | 1.13k | } |
443 | 1.13k | } |
444 | 1.13k | if (!resolved) { |
445 | 0 | Variable *variable = GetVariable(); |
446 | |
|
447 | 0 | if (module) { |
448 | 0 | if (variable) |
449 | 0 | error.SetErrorStringWithFormat( |
450 | 0 | "unable to resolve the module for file address 0x%" PRIx64 |
451 | 0 | " for variable '%s' in %s", |
452 | 0 | address, variable->GetName().AsCString(""), |
453 | 0 | module->GetFileSpec().GetPath().c_str()); |
454 | 0 | else |
455 | 0 | error.SetErrorStringWithFormat( |
456 | 0 | "unable to resolve the module for file address 0x%" PRIx64 |
457 | 0 | " in %s", |
458 | 0 | address, module->GetFileSpec().GetPath().c_str()); |
459 | 0 | } else { |
460 | 0 | if (variable) |
461 | 0 | error.SetErrorStringWithFormat( |
462 | 0 | "unable to resolve the module for file address 0x%" PRIx64 |
463 | 0 | " for variable '%s'", |
464 | 0 | address, variable->GetName().AsCString("")); |
465 | 0 | else |
466 | 0 | error.SetErrorStringWithFormat( |
467 | 0 | "unable to resolve the module for file address 0x%" PRIx64, |
468 | 0 | address); |
469 | 0 | } |
470 | 0 | } |
471 | 1.13k | } else { |
472 | | // Can't convert a file address to anything valid without more |
473 | | // context (which Module it came from) |
474 | 0 | error.SetErrorString( |
475 | 0 | "can't read memory from file address without more context"); |
476 | 0 | } |
477 | 1.13k | } |
478 | 1.13k | } |
479 | 1.13k | break; |
480 | | |
481 | 38.4k | case ValueType::HostAddress: |
482 | 38.4k | address = m_value.ULongLong(LLDB_INVALID_ADDRESS); |
483 | 38.4k | address_type = eAddressTypeHost; |
484 | 38.4k | if (exe_ctx) { |
485 | 38.4k | Target *target = exe_ctx->GetTargetPtr(); |
486 | 38.4k | if (target) { |
487 | 38.4k | data.SetByteOrder(target->GetArchitecture().GetByteOrder()); |
488 | 38.4k | data.SetAddressByteSize(target->GetArchitecture().GetAddressByteSize()); |
489 | 38.4k | break; |
490 | 38.4k | } |
491 | 38.4k | } |
492 | | // fallback to host settings |
493 | 0 | data.SetByteOrder(endian::InlHostByteOrder()); |
494 | 0 | data.SetAddressByteSize(sizeof(void *)); |
495 | 0 | break; |
496 | 119k | } |
497 | | |
498 | | // Bail if we encountered any errors |
499 | 116k | if (error.Fail()) |
500 | 0 | return error; |
501 | | |
502 | 116k | if (address == LLDB_INVALID_ADDRESS) { |
503 | 5 | error.SetErrorStringWithFormat("invalid %s address", |
504 | 5 | address_type == eAddressTypeHost ? "host"0 |
505 | 5 | : "load"); |
506 | 5 | return error; |
507 | 5 | } |
508 | | |
509 | | // If we got here, we need to read the value from memory. |
510 | 116k | size_t byte_size = GetValueByteSize(&error, exe_ctx); |
511 | | |
512 | | // Bail if we encountered any errors getting the byte size. |
513 | 116k | if (error.Fail()) |
514 | 1 | return error; |
515 | | |
516 | | // No memory to read for zero-sized types. |
517 | 116k | if (byte_size == 0) |
518 | 0 | return error; |
519 | | |
520 | | // Make sure we have enough room within "data", and if we don't make |
521 | | // something large enough that does |
522 | 116k | if (!data.ValidOffsetForDataOfSize(0, byte_size)) { |
523 | 116k | auto data_sp = std::make_shared<DataBufferHeap>(byte_size, '\0'); |
524 | 116k | data.SetData(data_sp); |
525 | 116k | } |
526 | | |
527 | 116k | uint8_t *dst = const_cast<uint8_t *>(data.PeekData(0, byte_size)); |
528 | 116k | if (dst != nullptr) { |
529 | 116k | if (address_type == eAddressTypeHost) { |
530 | | // The address is an address in this process, so just copy it. |
531 | 38.4k | if (address == 0) { |
532 | 0 | error.SetErrorString("trying to read from host address of 0."); |
533 | 0 | return error; |
534 | 0 | } |
535 | 38.4k | memcpy(dst, reinterpret_cast<uint8_t *>(address), byte_size); |
536 | 78.3k | } else if ((address_type == eAddressTypeLoad) || |
537 | 78.3k | (address_type == eAddressTypeFile)1.13k ) { |
538 | 78.3k | if (file_so_addr.IsValid()) { |
539 | 1.13k | const bool force_live_memory = true; |
540 | 1.13k | if (exe_ctx->GetTargetRef().ReadMemory(file_so_addr, dst, byte_size, |
541 | 1.13k | error, force_live_memory) != |
542 | 1.13k | byte_size) { |
543 | 0 | error.SetErrorStringWithFormat( |
544 | 0 | "read memory from 0x%" PRIx64 " failed", (uint64_t)address); |
545 | 0 | } |
546 | 77.2k | } else { |
547 | | // The execution context might have a NULL process, but it might have a |
548 | | // valid process in the exe_ctx->target, so use the |
549 | | // ExecutionContext::GetProcess accessor to ensure we get the process |
550 | | // if there is one. |
551 | 77.2k | Process *process = exe_ctx->GetProcessPtr(); |
552 | | |
553 | 77.2k | if (process) { |
554 | 77.2k | const size_t bytes_read = |
555 | 77.2k | process->ReadMemory(address, dst, byte_size, error); |
556 | 77.2k | if (bytes_read != byte_size) |
557 | 41 | error.SetErrorStringWithFormat( |
558 | 41 | "read memory from 0x%" PRIx64 " failed (%u of %u bytes read)", |
559 | 41 | (uint64_t)address, (uint32_t)bytes_read, (uint32_t)byte_size); |
560 | 77.2k | } else { |
561 | 0 | error.SetErrorStringWithFormat("read memory from 0x%" PRIx64 |
562 | 0 | " failed (invalid process)", |
563 | 0 | (uint64_t)address); |
564 | 0 | } |
565 | 77.2k | } |
566 | 78.3k | } else { |
567 | 0 | error.SetErrorStringWithFormat("unsupported AddressType value (%i)", |
568 | 0 | address_type); |
569 | 0 | } |
570 | 116k | } else { |
571 | 0 | error.SetErrorString("out of memory"); |
572 | 0 | } |
573 | | |
574 | 116k | return error; |
575 | 116k | } |
576 | | |
577 | 55.6k | Scalar &Value::ResolveValue(ExecutionContext *exe_ctx, Module *module) { |
578 | 55.6k | const CompilerType &compiler_type = GetCompilerType(); |
579 | 55.6k | if (compiler_type.IsValid()) { |
580 | 51.9k | switch (m_value_type) { |
581 | 0 | case ValueType::Invalid: |
582 | 12.8k | case ValueType::Scalar: // raw scalar value |
583 | 12.8k | break; |
584 | | |
585 | 8 | case ValueType::FileAddress: |
586 | 23.9k | case ValueType::LoadAddress: // load address value |
587 | 39.0k | case ValueType::HostAddress: // host address value (for memory in the process |
588 | | // that is using liblldb) |
589 | 39.0k | { |
590 | 39.0k | DataExtractor data; |
591 | 39.0k | lldb::addr_t addr = m_value.ULongLong(LLDB_INVALID_ADDRESS); |
592 | 39.0k | Status error(GetValueAsData(exe_ctx, data, module)); |
593 | 39.0k | if (error.Success()) { |
594 | 39.0k | Scalar scalar; |
595 | 39.0k | if (compiler_type.GetValueAsScalar( |
596 | 39.0k | data, 0, data.GetByteSize(), scalar, |
597 | 39.0k | exe_ctx ? exe_ctx->GetBestExecutionContextScope() : nullptr0 )) { |
598 | 39.0k | m_value = scalar; |
599 | 39.0k | m_value_type = ValueType::Scalar; |
600 | 39.0k | } else { |
601 | 0 | if ((uintptr_t)addr != (uintptr_t)m_data_buffer.GetBytes()) { |
602 | 0 | m_value.Clear(); |
603 | 0 | m_value_type = ValueType::Scalar; |
604 | 0 | } |
605 | 0 | } |
606 | 39.0k | } else { |
607 | 0 | if ((uintptr_t)addr != (uintptr_t)m_data_buffer.GetBytes()) { |
608 | 0 | m_value.Clear(); |
609 | 0 | m_value_type = ValueType::Scalar; |
610 | 0 | } |
611 | 0 | } |
612 | 39.0k | } break; |
613 | 51.9k | } |
614 | 51.9k | } |
615 | 55.6k | return m_value; |
616 | 55.6k | } |
617 | | |
618 | 40 | Variable *Value::GetVariable() { |
619 | 40 | if (m_context_type == ContextType::Variable) |
620 | 40 | return static_cast<Variable *>(m_context); |
621 | 0 | return nullptr; |
622 | 40 | } |
623 | | |
624 | 182 | void Value::Clear() { |
625 | 182 | m_value.Clear(); |
626 | 182 | m_compiler_type.Clear(); |
627 | 182 | m_value_type = ValueType::Scalar; |
628 | 182 | m_context = nullptr; |
629 | 182 | m_context_type = ContextType::Invalid; |
630 | 182 | m_data_buffer.Clear(); |
631 | 182 | } |
632 | | |
633 | 0 | const char *Value::GetValueTypeAsCString(ValueType value_type) { |
634 | 0 | switch (value_type) { |
635 | 0 | case ValueType::Invalid: |
636 | 0 | return "invalid"; |
637 | 0 | case ValueType::Scalar: |
638 | 0 | return "scalar"; |
639 | 0 | case ValueType::FileAddress: |
640 | 0 | return "file address"; |
641 | 0 | case ValueType::LoadAddress: |
642 | 0 | return "load address"; |
643 | 0 | case ValueType::HostAddress: |
644 | 0 | return "host address"; |
645 | 0 | }; |
646 | 0 | llvm_unreachable("enum cases exhausted."); |
647 | 0 | } |
648 | | |
649 | 0 | const char *Value::GetContextTypeAsCString(ContextType context_type) { |
650 | 0 | switch (context_type) { |
651 | 0 | case ContextType::Invalid: |
652 | 0 | return "invalid"; |
653 | 0 | case ContextType::RegisterInfo: |
654 | 0 | return "RegisterInfo *"; |
655 | 0 | case ContextType::LLDBType: |
656 | 0 | return "Type *"; |
657 | 0 | case ContextType::Variable: |
658 | 0 | return "Variable *"; |
659 | 0 | }; |
660 | 0 | llvm_unreachable("enum cases exhausted."); |
661 | 0 | } |
662 | | |
663 | 814 | void Value::ConvertToLoadAddress(Module *module, Target *target) { |
664 | 814 | if (!module || !target || (GetValueType() != ValueType::FileAddress)) |
665 | 0 | return; |
666 | | |
667 | 814 | lldb::addr_t file_addr = GetScalar().ULongLong(LLDB_INVALID_ADDRESS); |
668 | 814 | if (file_addr == LLDB_INVALID_ADDRESS) |
669 | 0 | return; |
670 | | |
671 | 814 | Address so_addr; |
672 | 814 | if (!module->ResolveFileAddress(file_addr, so_addr)) |
673 | 0 | return; |
674 | 814 | lldb::addr_t load_addr = so_addr.GetLoadAddress(target); |
675 | 814 | if (load_addr == LLDB_INVALID_ADDRESS) |
676 | 0 | return; |
677 | | |
678 | 814 | SetValueType(Value::ValueType::LoadAddress); |
679 | 814 | GetScalar() = load_addr; |
680 | 814 | } |
681 | | |
682 | 16.7k | void ValueList::PushValue(const Value &value) { m_values.push_back(value); } |
683 | | |
684 | 51.7k | size_t ValueList::GetSize() { return m_values.size(); } |
685 | | |
686 | 43.1k | Value *ValueList::GetValueAtIndex(size_t idx) { |
687 | 43.1k | if (idx < GetSize()) { |
688 | 43.1k | return &(m_values[idx]); |
689 | 43.1k | } else |
690 | 0 | return nullptr; |
691 | 43.1k | } |
692 | | |
693 | 0 | void ValueList::Clear() { m_values.clear(); } |