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