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