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