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