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