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