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