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