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