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