blob: 43944cea2c778d972110ca2bc61e0a5ca1791b76 [file] [log] [blame]
Chris Lattner24943d22010-06-08 16:52:24 +00001//===-- CommandObjectMemory.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
Daniel Malead891f9b2012-12-05 00:20:57 +000010#include "lldb/lldb-python.h"
11
Chris Lattner24943d22010-06-08 16:52:24 +000012#include "CommandObjectMemory.h"
13
14// C Includes
15// C++ Includes
16// Other libraries and framework includes
17// Project includes
Chris Lattner24943d22010-06-08 16:52:24 +000018#include "lldb/Core/DataBufferHeap.h"
19#include "lldb/Core/DataExtractor.h"
Greg Clayton63094e02010-06-23 01:19:29 +000020#include "lldb/Core/Debugger.h"
Greg Clayton49ce8962012-08-29 21:13:06 +000021#include "lldb/Core/Module.h"
Chris Lattner24943d22010-06-08 16:52:24 +000022#include "lldb/Core/StreamString.h"
Greg Clayton57b3c6b2011-04-27 22:04:39 +000023#include "lldb/Core/ValueObjectMemory.h"
Greg Clayton63094e02010-06-23 01:19:29 +000024#include "lldb/Interpreter/Args.h"
Chris Lattner24943d22010-06-08 16:52:24 +000025#include "lldb/Interpreter/CommandReturnObject.h"
Greg Clayton63094e02010-06-23 01:19:29 +000026#include "lldb/Interpreter/CommandInterpreter.h"
27#include "lldb/Interpreter/Options.h"
Greg Clayton57b3c6b2011-04-27 22:04:39 +000028#include "lldb/Interpreter/OptionGroupFormat.h"
29#include "lldb/Interpreter/OptionGroupOutputFile.h"
Greg Clayton56bbdaf2011-04-28 20:55:26 +000030#include "lldb/Interpreter/OptionGroupValueObjectDisplay.h"
Greg Clayton73844aa2012-08-22 17:17:09 +000031#include "lldb/Interpreter/OptionValueString.h"
Greg Clayton49ce8962012-08-29 21:13:06 +000032#include "lldb/Symbol/TypeList.h"
Chris Lattner24943d22010-06-08 16:52:24 +000033#include "lldb/Target/Process.h"
Greg Clayton57b3c6b2011-04-27 22:04:39 +000034#include "lldb/Target/StackFrame.h"
Chris Lattner24943d22010-06-08 16:52:24 +000035
36using namespace lldb;
37using namespace lldb_private;
38
Greg Clayton56bbdaf2011-04-28 20:55:26 +000039static OptionDefinition
Greg Clayton57b3c6b2011-04-27 22:04:39 +000040g_option_table[] =
41{
Greg Clayton57b3c6b2011-04-27 22:04:39 +000042 { LLDB_OPT_SET_1, false, "num-per-line" ,'l', required_argument, NULL, 0, eArgTypeNumberPerLine ,"The number of items per line to display."},
43 { LLDB_OPT_SET_2, false, "binary" ,'b', no_argument , NULL, 0, eArgTypeNone ,"If true, memory will be saved as binary. If false, the memory is saved save as an ASCII dump that uses the format, size, count and number per line settings."},
Sean Callanan06dc17f2012-09-24 22:25:51 +000044 { LLDB_OPT_SET_3, true , "type" ,'t', required_argument, NULL, 0, eArgTypeNone ,"The name of a type to view memory as."},
Greg Clayton827baf62012-11-02 21:14:58 +000045 { LLDB_OPT_SET_1|
46 LLDB_OPT_SET_2|
47 LLDB_OPT_SET_3, false, "force" ,'r', no_argument, NULL, 0, eArgTypeNone ,"Necessary if reading over 1024 bytes of memory."},
Greg Clayton57b3c6b2011-04-27 22:04:39 +000048};
49
50
51
52class OptionGroupReadMemory : public OptionGroup
53{
54public:
55
56 OptionGroupReadMemory () :
Greg Clayton56bbdaf2011-04-28 20:55:26 +000057 m_num_per_line (1,1),
Greg Clayton57b3c6b2011-04-27 22:04:39 +000058 m_output_as_binary (false),
59 m_view_as_type()
60 {
61 }
62
63 virtual
64 ~OptionGroupReadMemory ()
65 {
66 }
67
68
69 virtual uint32_t
70 GetNumDefinitions ()
71 {
72 return sizeof (g_option_table) / sizeof (OptionDefinition);
73 }
74
75 virtual const OptionDefinition*
76 GetDefinitions ()
77 {
78 return g_option_table;
79 }
80
81 virtual Error
82 SetOptionValue (CommandInterpreter &interpreter,
83 uint32_t option_idx,
84 const char *option_arg)
85 {
86 Error error;
Greg Clayton6475c422012-12-04 00:32:51 +000087 const int short_option = g_option_table[option_idx].short_option;
Greg Clayton57b3c6b2011-04-27 22:04:39 +000088
89 switch (short_option)
90 {
91 case 'l':
92 error = m_num_per_line.SetValueFromCString (option_arg);
93 if (m_num_per_line.GetCurrentValue() == 0)
Greg Clayton9c236732011-10-26 00:56:27 +000094 error.SetErrorStringWithFormat("invalid value for --num-per-line option '%s'", option_arg);
Greg Clayton57b3c6b2011-04-27 22:04:39 +000095 break;
Greg Claytona42880a2011-10-25 06:44:01 +000096
Greg Clayton57b3c6b2011-04-27 22:04:39 +000097 case 'b':
98 m_output_as_binary = true;
99 break;
100
101 case 't':
102 error = m_view_as_type.SetValueFromCString (option_arg);
103 break;
Sean Callanan8a6f3e92012-04-28 01:27:38 +0000104
105 case 'r':
106 m_force = true;
107 break;
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000108
109 default:
Greg Clayton9c236732011-10-26 00:56:27 +0000110 error.SetErrorStringWithFormat("unrecognized short option '%c'", short_option);
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000111 break;
112 }
113 return error;
114 }
115
116 virtual void
117 OptionParsingStarting (CommandInterpreter &interpreter)
118 {
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000119 m_num_per_line.Clear();
120 m_output_as_binary = false;
121 m_view_as_type.Clear();
122 }
123
Greg Clayton56bbdaf2011-04-28 20:55:26 +0000124 Error
Greg Claytona42880a2011-10-25 06:44:01 +0000125 FinalizeSettings (Target *target, OptionGroupFormat& format_options)
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000126 {
Greg Clayton56bbdaf2011-04-28 20:55:26 +0000127 Error error;
Greg Claytona42880a2011-10-25 06:44:01 +0000128 OptionValueUInt64 &byte_size_value = format_options.GetByteSizeValue();
129 OptionValueUInt64 &count_value = format_options.GetCountValue();
Greg Clayton9c236732011-10-26 00:56:27 +0000130 const bool byte_size_option_set = byte_size_value.OptionWasSet();
Greg Clayton56bbdaf2011-04-28 20:55:26 +0000131 const bool num_per_line_option_set = m_num_per_line.OptionWasSet();
Greg Claytona42880a2011-10-25 06:44:01 +0000132 const bool count_option_set = format_options.GetCountValue().OptionWasSet();
Greg Clayton56bbdaf2011-04-28 20:55:26 +0000133
Greg Clayton56bbdaf2011-04-28 20:55:26 +0000134 switch (format_options.GetFormat())
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000135 {
136 default:
137 break;
138
139 case eFormatBoolean:
Greg Clayton56bbdaf2011-04-28 20:55:26 +0000140 if (!byte_size_option_set)
Greg Claytona42880a2011-10-25 06:44:01 +0000141 byte_size_value = 1;
Greg Clayton56bbdaf2011-04-28 20:55:26 +0000142 if (!num_per_line_option_set)
143 m_num_per_line = 1;
144 if (!count_option_set)
Greg Claytona42880a2011-10-25 06:44:01 +0000145 format_options.GetCountValue() = 8;
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000146 break;
147
148 case eFormatCString:
149 break;
Greg Clayton24a6bd92011-10-27 17:55:14 +0000150
151 case eFormatInstruction:
152 if (count_option_set)
Jim Inghamab885832012-11-07 01:52:04 +0000153 byte_size_value = target->GetArchitecture().GetMaximumOpcodeByteSize();
Greg Clayton24a6bd92011-10-27 17:55:14 +0000154 m_num_per_line = 1;
155 break;
156
157 case eFormatAddressInfo:
158 if (!byte_size_option_set)
159 byte_size_value = target->GetArchitecture().GetAddressByteSize();
160 m_num_per_line = 1;
161 if (!count_option_set)
162 format_options.GetCountValue() = 8;
163 break;
164
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000165 case eFormatPointer:
Greg Claytona42880a2011-10-25 06:44:01 +0000166 byte_size_value = target->GetArchitecture().GetAddressByteSize();
Greg Clayton56bbdaf2011-04-28 20:55:26 +0000167 if (!num_per_line_option_set)
168 m_num_per_line = 4;
169 if (!count_option_set)
Greg Claytona42880a2011-10-25 06:44:01 +0000170 format_options.GetCountValue() = 8;
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000171 break;
172
173 case eFormatBinary:
174 case eFormatFloat:
175 case eFormatOctal:
176 case eFormatDecimal:
177 case eFormatEnum:
178 case eFormatUnicode16:
179 case eFormatUnicode32:
180 case eFormatUnsigned:
Greg Clayton24a6bd92011-10-27 17:55:14 +0000181 case eFormatHexFloat:
Greg Clayton56bbdaf2011-04-28 20:55:26 +0000182 if (!byte_size_option_set)
Greg Claytona42880a2011-10-25 06:44:01 +0000183 byte_size_value = 4;
Greg Clayton56bbdaf2011-04-28 20:55:26 +0000184 if (!num_per_line_option_set)
185 m_num_per_line = 1;
186 if (!count_option_set)
Greg Claytona42880a2011-10-25 06:44:01 +0000187 format_options.GetCountValue() = 8;
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000188 break;
Greg Clayton24a6bd92011-10-27 17:55:14 +0000189
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000190 case eFormatBytes:
191 case eFormatBytesWithASCII:
Greg Clayton9c236732011-10-26 00:56:27 +0000192 if (byte_size_option_set)
Greg Clayton56bbdaf2011-04-28 20:55:26 +0000193 {
Greg Claytona42880a2011-10-25 06:44:01 +0000194 if (byte_size_value > 1)
Daniel Malea5f35a4b2012-11-29 21:49:15 +0000195 error.SetErrorStringWithFormat ("display format (bytes/bytes with ascii) conflicts with the specified byte size %" PRIu64 "\n"
Johnny Chenbf9ba592012-03-06 01:17:59 +0000196 "\tconsider using a different display format or don't specify the byte size",
197 byte_size_value.GetCurrentValue());
Greg Clayton56bbdaf2011-04-28 20:55:26 +0000198 }
199 else
Greg Claytona42880a2011-10-25 06:44:01 +0000200 byte_size_value = 1;
Greg Clayton56bbdaf2011-04-28 20:55:26 +0000201 if (!num_per_line_option_set)
202 m_num_per_line = 16;
203 if (!count_option_set)
Greg Claytona42880a2011-10-25 06:44:01 +0000204 format_options.GetCountValue() = 32;
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000205 break;
Greg Clayton307fa072011-06-17 23:50:44 +0000206 case eFormatCharArray:
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000207 case eFormatChar:
208 case eFormatCharPrintable:
Greg Clayton56bbdaf2011-04-28 20:55:26 +0000209 if (!byte_size_option_set)
Greg Claytona42880a2011-10-25 06:44:01 +0000210 byte_size_value = 1;
Greg Clayton56bbdaf2011-04-28 20:55:26 +0000211 if (!num_per_line_option_set)
212 m_num_per_line = 32;
213 if (!count_option_set)
Greg Claytona42880a2011-10-25 06:44:01 +0000214 format_options.GetCountValue() = 64;
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000215 break;
216 case eFormatComplex:
Greg Clayton56bbdaf2011-04-28 20:55:26 +0000217 if (!byte_size_option_set)
Greg Claytona42880a2011-10-25 06:44:01 +0000218 byte_size_value = 8;
Greg Clayton56bbdaf2011-04-28 20:55:26 +0000219 if (!num_per_line_option_set)
220 m_num_per_line = 1;
221 if (!count_option_set)
Greg Claytona42880a2011-10-25 06:44:01 +0000222 format_options.GetCountValue() = 8;
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000223 break;
Jason Molenda42077d92013-03-23 05:16:54 +0000224 case eFormatComplexInteger:
225 if (!byte_size_option_set)
226 byte_size_value = 8;
227 if (!num_per_line_option_set)
228 m_num_per_line = 1;
229 if (!count_option_set)
230 format_options.GetCountValue() = 8;
231 break;
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000232 case eFormatHex:
Greg Clayton56bbdaf2011-04-28 20:55:26 +0000233 if (!byte_size_option_set)
Greg Claytona42880a2011-10-25 06:44:01 +0000234 byte_size_value = 4;
Greg Clayton56bbdaf2011-04-28 20:55:26 +0000235 if (!num_per_line_option_set)
236 {
Greg Claytona42880a2011-10-25 06:44:01 +0000237 switch (byte_size_value)
Greg Clayton56bbdaf2011-04-28 20:55:26 +0000238 {
239 case 1:
240 case 2:
241 m_num_per_line = 8;
242 break;
243 case 4:
244 m_num_per_line = 4;
245 break;
246 case 8:
247 m_num_per_line = 2;
248 break;
249 default:
250 m_num_per_line = 1;
251 break;
252 }
253 }
254 if (!count_option_set)
Greg Claytona42880a2011-10-25 06:44:01 +0000255 count_value = 8;
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000256 break;
257
258 case eFormatVectorOfChar:
259 case eFormatVectorOfSInt8:
260 case eFormatVectorOfUInt8:
261 case eFormatVectorOfSInt16:
262 case eFormatVectorOfUInt16:
263 case eFormatVectorOfSInt32:
264 case eFormatVectorOfUInt32:
265 case eFormatVectorOfSInt64:
266 case eFormatVectorOfUInt64:
267 case eFormatVectorOfFloat32:
268 case eFormatVectorOfFloat64:
269 case eFormatVectorOfUInt128:
Greg Clayton56bbdaf2011-04-28 20:55:26 +0000270 if (!byte_size_option_set)
Greg Claytona42880a2011-10-25 06:44:01 +0000271 byte_size_value = 128;
Greg Clayton56bbdaf2011-04-28 20:55:26 +0000272 if (!num_per_line_option_set)
273 m_num_per_line = 1;
274 if (!count_option_set)
Greg Claytona42880a2011-10-25 06:44:01 +0000275 count_value = 4;
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000276 break;
277 }
Greg Clayton56bbdaf2011-04-28 20:55:26 +0000278 return error;
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000279 }
280
Greg Clayton902b5be2011-10-26 04:32:38 +0000281 bool
282 AnyOptionWasSet () const
283 {
284 return m_num_per_line.OptionWasSet() ||
285 m_output_as_binary ||
286 m_view_as_type.OptionWasSet();
287 }
288
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000289 OptionValueUInt64 m_num_per_line;
290 bool m_output_as_binary;
291 OptionValueString m_view_as_type;
Sean Callanan8a6f3e92012-04-28 01:27:38 +0000292 bool m_force;
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000293};
294
295
296
Chris Lattner24943d22010-06-08 16:52:24 +0000297//----------------------------------------------------------------------
298// Read memory from the inferior process
299//----------------------------------------------------------------------
Jim Inghamda26bd22012-06-08 21:56:10 +0000300class CommandObjectMemoryRead : public CommandObjectParsed
Chris Lattner24943d22010-06-08 16:52:24 +0000301{
302public:
303
Greg Clayton238c0a12010-09-18 01:14:36 +0000304 CommandObjectMemoryRead (CommandInterpreter &interpreter) :
Jim Inghamda26bd22012-06-08 21:56:10 +0000305 CommandObjectParsed (interpreter,
306 "memory read",
307 "Read from the memory of the process being debugged.",
308 NULL,
Greg Claytonea0bb4d2013-01-09 19:44:40 +0000309 eFlagRequiresTarget | eFlagProcessMustBePaused),
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000310 m_option_group (interpreter),
Greg Claytona42880a2011-10-25 06:44:01 +0000311 m_format_options (eFormatBytesWithASCII, 1, 8),
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000312 m_memory_options (),
Greg Clayton56bbdaf2011-04-28 20:55:26 +0000313 m_outfile_options (),
Greg Clayton902b5be2011-10-26 04:32:38 +0000314 m_varobj_options(),
315 m_next_addr(LLDB_INVALID_ADDRESS),
316 m_prev_byte_size(0),
317 m_prev_format_options (eFormatBytesWithASCII, 1, 8),
318 m_prev_memory_options (),
319 m_prev_outfile_options (),
320 m_prev_varobj_options()
Chris Lattner24943d22010-06-08 16:52:24 +0000321 {
Caroline Tice43b014a2010-10-04 22:28:36 +0000322 CommandArgumentEntry arg1;
323 CommandArgumentEntry arg2;
324 CommandArgumentData start_addr_arg;
325 CommandArgumentData end_addr_arg;
326
327 // Define the first (and only) variant of this arg.
Enrico Granata4968ad82013-01-29 01:48:30 +0000328 start_addr_arg.arg_type = eArgTypeAddressOrExpression;
Caroline Tice43b014a2010-10-04 22:28:36 +0000329 start_addr_arg.arg_repetition = eArgRepeatPlain;
330
331 // There is only one variant this argument could be; put it into the argument entry.
332 arg1.push_back (start_addr_arg);
333
334 // Define the first (and only) variant of this arg.
Enrico Granata4968ad82013-01-29 01:48:30 +0000335 end_addr_arg.arg_type = eArgTypeAddressOrExpression;
Caroline Tice43b014a2010-10-04 22:28:36 +0000336 end_addr_arg.arg_repetition = eArgRepeatOptional;
337
338 // There is only one variant this argument could be; put it into the argument entry.
339 arg2.push_back (end_addr_arg);
340
341 // Push the data for the first argument into the m_arguments vector.
342 m_arguments.push_back (arg1);
343 m_arguments.push_back (arg2);
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000344
Greg Claytona42880a2011-10-25 06:44:01 +0000345 // Add the "--format" and "--count" options to group 1 and 3
346 m_option_group.Append (&m_format_options,
347 OptionGroupFormat::OPTION_GROUP_FORMAT | OptionGroupFormat::OPTION_GROUP_COUNT,
Greg Clayton31feaa82011-11-22 18:07:35 +0000348 LLDB_OPT_SET_1 | LLDB_OPT_SET_2 | LLDB_OPT_SET_3);
Greg Clayton24a6bd92011-10-27 17:55:14 +0000349 m_option_group.Append (&m_format_options,
350 OptionGroupFormat::OPTION_GROUP_GDB_FMT,
Greg Clayton31feaa82011-11-22 18:07:35 +0000351 LLDB_OPT_SET_1 | LLDB_OPT_SET_3);
Greg Claytona42880a2011-10-25 06:44:01 +0000352 // Add the "--size" option to group 1 and 2
353 m_option_group.Append (&m_format_options,
354 OptionGroupFormat::OPTION_GROUP_SIZE,
355 LLDB_OPT_SET_1 | LLDB_OPT_SET_2);
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000356 m_option_group.Append (&m_memory_options);
357 m_option_group.Append (&m_outfile_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1 | LLDB_OPT_SET_2 | LLDB_OPT_SET_3);
Greg Clayton56bbdaf2011-04-28 20:55:26 +0000358 m_option_group.Append (&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_3);
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000359 m_option_group.Finalize();
Chris Lattner24943d22010-06-08 16:52:24 +0000360 }
361
362 virtual
363 ~CommandObjectMemoryRead ()
364 {
365 }
366
367 Options *
368 GetOptions ()
369 {
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000370 return &m_option_group;
Chris Lattner24943d22010-06-08 16:52:24 +0000371 }
372
Greg Clayton902b5be2011-10-26 04:32:38 +0000373 virtual const char *GetRepeatCommand (Args &current_command_args, uint32_t index)
374 {
375 return m_cmd_name.c_str();
376 }
377
Jim Inghamda26bd22012-06-08 21:56:10 +0000378protected:
Chris Lattner24943d22010-06-08 16:52:24 +0000379 virtual bool
Greg Clayton49d888d2012-12-06 22:49:16 +0000380 DoExecute (Args& command, CommandReturnObject &result)
Chris Lattner24943d22010-06-08 16:52:24 +0000381 {
Greg Claytonea0bb4d2013-01-09 19:44:40 +0000382 // No need to check "target" for validity as eFlagRequiresTarget ensures it is valid
383 Target *target = m_exe_ctx.GetTargetPtr();
384
Chris Lattner24943d22010-06-08 16:52:24 +0000385 const size_t argc = command.GetArgumentCount();
386
Greg Clayton902b5be2011-10-26 04:32:38 +0000387 if ((argc == 0 && m_next_addr == LLDB_INVALID_ADDRESS) || argc > 2)
Chris Lattner24943d22010-06-08 16:52:24 +0000388 {
Greg Clayton49d888d2012-12-06 22:49:16 +0000389 result.AppendErrorWithFormat ("%s takes a start address expression with an optional end address expression.\n", m_cmd_name.c_str());
Greg Claytonbad1c9e2012-12-15 02:08:17 +0000390 result.AppendRawWarning("Expressions should be quoted if they contain spaces or other special characters.\n");
Chris Lattner24943d22010-06-08 16:52:24 +0000391 result.SetStatus(eReturnStatusFailed);
392 return false;
393 }
394
Greg Clayton56bbdaf2011-04-28 20:55:26 +0000395 ClangASTType clang_ast_type;
396 Error error;
397
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000398 const char *view_as_type_cstr = m_memory_options.m_view_as_type.GetCurrentValue();
399 if (view_as_type_cstr && view_as_type_cstr[0])
Chris Lattner24943d22010-06-08 16:52:24 +0000400 {
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000401 // We are viewing memory as a type
Greg Claytonbad1c9e2012-12-15 02:08:17 +0000402
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000403 SymbolContext sc;
Greg Claytondc0a38c2012-03-26 23:03:23 +0000404 const bool exact_match = false;
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000405 TypeList type_list;
406 uint32_t reference_count = 0;
407 uint32_t pointer_count = 0;
408 size_t idx;
Sean Callananddb2ece2012-07-10 21:24:26 +0000409
410#define ALL_KEYWORDS \
411 KEYWORD("const") \
412 KEYWORD("volatile") \
413 KEYWORD("restrict") \
414 KEYWORD("struct") \
415 KEYWORD("class") \
416 KEYWORD("union")
417
418#define KEYWORD(s) s,
419 static const char *g_keywords[] =
420 {
421 ALL_KEYWORDS
422 };
423#undef KEYWORD
424
425#define KEYWORD(s) (sizeof(s) - 1),
426 static const int g_keyword_lengths[] =
427 {
428 ALL_KEYWORDS
429 };
430#undef KEYWORD
431
432#undef ALL_KEYWORDS
433
434 static size_t g_num_keywords = sizeof(g_keywords) / sizeof(const char *);
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000435 std::string type_str(view_as_type_cstr);
436
437 // Remove all instances of g_keywords that are followed by spaces
438 for (size_t i = 0; i < g_num_keywords; ++i)
439 {
440 const char *keyword = g_keywords[i];
Sean Callananddb2ece2012-07-10 21:24:26 +0000441 int keyword_len = g_keyword_lengths[i];
442
443 idx = 0;
444 while ((idx = type_str.find (keyword, idx)) != std::string::npos)
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000445 {
446 if (type_str[idx + keyword_len] == ' ' || type_str[idx + keyword_len] == '\t')
Sean Callananddb2ece2012-07-10 21:24:26 +0000447 {
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000448 type_str.erase(idx, keyword_len+1);
Sean Callananddb2ece2012-07-10 21:24:26 +0000449 idx = 0;
450 }
451 else
452 {
453 idx += keyword_len;
454 }
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000455 }
456 }
457 bool done = type_str.empty();
458 //
459 idx = type_str.find_first_not_of (" \t");
460 if (idx > 0 && idx != std::string::npos)
461 type_str.erase (0, idx);
462 while (!done)
463 {
464 // Strip trailing spaces
465 if (type_str.empty())
466 done = true;
467 else
468 {
469 switch (type_str[type_str.size()-1])
470 {
471 case '*':
472 ++pointer_count;
473 // fall through...
474 case ' ':
475 case '\t':
476 type_str.erase(type_str.size()-1);
477 break;
478
479 case '&':
480 if (reference_count == 0)
481 {
482 reference_count = 1;
483 type_str.erase(type_str.size()-1);
484 }
485 else
486 {
487 result.AppendErrorWithFormat ("invalid type string: '%s'\n", view_as_type_cstr);
488 result.SetStatus(eReturnStatusFailed);
489 return false;
490 }
491 break;
492
493 default:
494 done = true;
495 break;
496 }
497 }
498 }
499
500 ConstString lookup_type_name(type_str.c_str());
Greg Claytonea0bb4d2013-01-09 19:44:40 +0000501 StackFrame *frame = m_exe_ctx.GetFramePtr();
Greg Clayton567e7f32011-09-22 04:58:26 +0000502 if (frame)
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000503 {
Greg Clayton567e7f32011-09-22 04:58:26 +0000504 sc = frame->GetSymbolContext (eSymbolContextModule);
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000505 if (sc.module_sp)
506 {
Sean Callanan3e80cd92011-10-12 02:08:07 +0000507 sc.module_sp->FindTypes (sc,
508 lookup_type_name,
Greg Claytondc0a38c2012-03-26 23:03:23 +0000509 exact_match,
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000510 1,
511 type_list);
512 }
513 }
514 if (type_list.GetSize() == 0)
515 {
Greg Clayton9f95fb62012-04-06 17:41:13 +0000516 target->GetImages().FindTypes (sc,
Greg Clayton567e7f32011-09-22 04:58:26 +0000517 lookup_type_name,
Greg Claytondc0a38c2012-03-26 23:03:23 +0000518 exact_match,
Greg Clayton567e7f32011-09-22 04:58:26 +0000519 1,
520 type_list);
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000521 }
522
523 if (type_list.GetSize() == 0)
524 {
525 result.AppendErrorWithFormat ("unable to find any types that match the raw type '%s' for full type '%s'\n",
526 lookup_type_name.GetCString(),
527 view_as_type_cstr);
528 result.SetStatus(eReturnStatusFailed);
529 return false;
530 }
531
532 TypeSP type_sp (type_list.GetTypeAtIndex(0));
533 clang_ast_type.SetClangType (type_sp->GetClangAST(), type_sp->GetClangFullType());
534
535 while (pointer_count > 0)
536 {
537 clang_type_t pointer_type = ClangASTContext::CreatePointerType (clang_ast_type.GetASTContext(), clang_ast_type.GetOpaqueQualType());
538 if (pointer_type)
539 clang_ast_type.SetClangType (clang_ast_type.GetASTContext(), pointer_type);
540 else
541 {
542 result.AppendError ("unable make a pointer type\n");
543 result.SetStatus(eReturnStatusFailed);
544 return false;
545 }
546 --pointer_count;
547 }
548
Greg Claytonfe6dc6e2013-03-14 18:31:44 +0000549 m_format_options.GetByteSizeValue() = clang_ast_type.GetClangTypeByteSize();
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000550
Greg Claytona42880a2011-10-25 06:44:01 +0000551 if (m_format_options.GetByteSizeValue() == 0)
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000552 {
553 result.AppendErrorWithFormat ("unable to get the byte size of the type '%s'\n",
554 view_as_type_cstr);
555 result.SetStatus(eReturnStatusFailed);
556 return false;
557 }
Greg Clayton56bbdaf2011-04-28 20:55:26 +0000558
Greg Claytona42880a2011-10-25 06:44:01 +0000559 if (!m_format_options.GetCountValue().OptionWasSet())
560 m_format_options.GetCountValue() = 1;
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000561 }
562 else
563 {
Greg Clayton567e7f32011-09-22 04:58:26 +0000564 error = m_memory_options.FinalizeSettings (target, m_format_options);
Greg Clayton56bbdaf2011-04-28 20:55:26 +0000565 }
566
567 // Look for invalid combinations of settings
568 if (error.Fail())
569 {
Greg Clayton49d888d2012-12-06 22:49:16 +0000570 result.AppendError(error.AsCString());
Greg Clayton56bbdaf2011-04-28 20:55:26 +0000571 result.SetStatus(eReturnStatusFailed);
572 return false;
Chris Lattner24943d22010-06-08 16:52:24 +0000573 }
574
Greg Clayton902b5be2011-10-26 04:32:38 +0000575 lldb::addr_t addr;
576 size_t total_byte_size = 0;
577 if (argc == 0)
578 {
579 // Use the last address and byte size and all options as they were
580 // if no options have been set
581 addr = m_next_addr;
582 total_byte_size = m_prev_byte_size;
Greg Claytonbad1c9e2012-12-15 02:08:17 +0000583 clang_ast_type = m_prev_clang_ast_type;
584 if (!m_format_options.AnyOptionWasSet() &&
Greg Clayton902b5be2011-10-26 04:32:38 +0000585 !m_memory_options.AnyOptionWasSet() &&
586 !m_outfile_options.AnyOptionWasSet() &&
587 !m_varobj_options.AnyOptionWasSet())
588 {
589 m_format_options = m_prev_format_options;
590 m_memory_options = m_prev_memory_options;
591 m_outfile_options = m_prev_outfile_options;
592 m_varobj_options = m_prev_varobj_options;
593 }
594 }
595
Greg Claytona42880a2011-10-25 06:44:01 +0000596 size_t item_count = m_format_options.GetCountValue().GetCurrentValue();
Enrico Granata45358912013-01-21 19:20:50 +0000597 size_t item_byte_size = m_format_options.GetByteSizeValue().GetCurrentValue();
Greg Clayton56bbdaf2011-04-28 20:55:26 +0000598 const size_t num_per_line = m_memory_options.m_num_per_line.GetCurrentValue();
Chris Lattner24943d22010-06-08 16:52:24 +0000599
Chris Lattner24943d22010-06-08 16:52:24 +0000600 if (total_byte_size == 0)
Greg Clayton902b5be2011-10-26 04:32:38 +0000601 {
602 total_byte_size = item_count * item_byte_size;
603 if (total_byte_size == 0)
604 total_byte_size = 32;
605 }
Chris Lattner24943d22010-06-08 16:52:24 +0000606
Greg Clayton902b5be2011-10-26 04:32:38 +0000607 if (argc > 0)
Greg Claytonea0bb4d2013-01-09 19:44:40 +0000608 addr = Args::StringToAddress(&m_exe_ctx, command.GetArgumentAtIndex(0), LLDB_INVALID_ADDRESS, &error);
Chris Lattner24943d22010-06-08 16:52:24 +0000609
610 if (addr == LLDB_INVALID_ADDRESS)
611 {
Greg Clayton49d888d2012-12-06 22:49:16 +0000612 result.AppendError("invalid start address expression.");
613 result.AppendError(error.AsCString());
Chris Lattner24943d22010-06-08 16:52:24 +0000614 result.SetStatus(eReturnStatusFailed);
615 return false;
616 }
617
618 if (argc == 2)
619 {
Greg Claytonea0bb4d2013-01-09 19:44:40 +0000620 lldb::addr_t end_addr = Args::StringToAddress(&m_exe_ctx, command.GetArgumentAtIndex(1), LLDB_INVALID_ADDRESS, 0);
Chris Lattner24943d22010-06-08 16:52:24 +0000621 if (end_addr == LLDB_INVALID_ADDRESS)
622 {
Greg Clayton49d888d2012-12-06 22:49:16 +0000623 result.AppendError("invalid end address expression.");
624 result.AppendError(error.AsCString());
Chris Lattner24943d22010-06-08 16:52:24 +0000625 result.SetStatus(eReturnStatusFailed);
626 return false;
627 }
628 else if (end_addr <= addr)
629 {
Daniel Malea5f35a4b2012-11-29 21:49:15 +0000630 result.AppendErrorWithFormat("end address (0x%" PRIx64 ") must be greater that the start address (0x%" PRIx64 ").\n", end_addr, addr);
Chris Lattner24943d22010-06-08 16:52:24 +0000631 result.SetStatus(eReturnStatusFailed);
632 return false;
633 }
Greg Claytona42880a2011-10-25 06:44:01 +0000634 else if (m_format_options.GetCountValue().OptionWasSet())
Chris Lattner24943d22010-06-08 16:52:24 +0000635 {
Daniel Malea5f35a4b2012-11-29 21:49:15 +0000636 result.AppendErrorWithFormat("specify either the end address (0x%" PRIx64 ") or the count (--count %lu), not both.\n", end_addr, item_count);
Chris Lattner24943d22010-06-08 16:52:24 +0000637 result.SetStatus(eReturnStatusFailed);
638 return false;
639 }
640
641 total_byte_size = end_addr - addr;
642 item_count = total_byte_size / item_byte_size;
643 }
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000644
Sean Callanan8a6f3e92012-04-28 01:27:38 +0000645 if (total_byte_size > 1024 && !m_memory_options.m_force)
646 {
647 result.AppendErrorWithFormat("Normally, \'memory read\' will not read over 1Kbyte of data.\n");
648 result.AppendErrorWithFormat("Please use --force to override this restriction.\n");
649 return false;
650 }
651
Enrico Granata45358912013-01-21 19:20:50 +0000652
653
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000654 DataBufferSP data_sp;
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000655 size_t bytes_read = 0;
Greg Claytonbad1c9e2012-12-15 02:08:17 +0000656 if (clang_ast_type.GetOpaqueQualType())
657 {
658 // Make sure we don't display our type as ASCII bytes like the default memory read
659 if (m_format_options.GetFormatValue().OptionWasSet() == false)
660 m_format_options.GetFormatValue().SetCurrentValue(eFormatDefault);
661
662 bytes_read = clang_ast_type.GetTypeByteSize() * m_format_options.GetCountValue().GetCurrentValue();
663 }
Enrico Granata45358912013-01-21 19:20:50 +0000664 else if (m_format_options.GetFormatValue().GetCurrentValue() != eFormatCString)
Chris Lattner24943d22010-06-08 16:52:24 +0000665 {
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000666 data_sp.reset (new DataBufferHeap (total_byte_size, '\0'));
Greg Clayton3508c382012-02-24 01:59:29 +0000667 Address address(addr, NULL);
Greg Clayton567e7f32011-09-22 04:58:26 +0000668 bytes_read = target->ReadMemory(address, false, data_sp->GetBytes (), data_sp->GetByteSize(), error);
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000669 if (bytes_read == 0)
670 {
Greg Clayton04e6ada2012-05-25 17:05:55 +0000671 const char *error_cstr = error.AsCString();
672 if (error_cstr && error_cstr[0])
673 {
674 result.AppendError(error_cstr);
675 }
676 else
677 {
Daniel Malea5f35a4b2012-11-29 21:49:15 +0000678 result.AppendErrorWithFormat("failed to read memory from 0x%" PRIx64 ".\n", addr);
Greg Clayton04e6ada2012-05-25 17:05:55 +0000679 }
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000680 result.SetStatus(eReturnStatusFailed);
681 return false;
682 }
683
684 if (bytes_read < total_byte_size)
Jim Ingham40aa9032013-01-25 23:05:01 +0000685 result.AppendWarningWithFormat("Not all bytes (%lu/%lu) were able to be read from 0x%" PRIx64 ".\n", bytes_read, total_byte_size, addr);
Chris Lattner24943d22010-06-08 16:52:24 +0000686 }
Enrico Granata45358912013-01-21 19:20:50 +0000687 else
688 {
689 // we treat c-strings as a special case because they do not have a fixed size
690 if (m_format_options.GetByteSizeValue().OptionWasSet() && !m_format_options.HasGDBFormat())
691 item_byte_size = m_format_options.GetByteSizeValue().GetCurrentValue();
692 else
693 item_byte_size = target->GetMaximumSizeOfStringSummary();
694 if (!m_format_options.GetCountValue().OptionWasSet())
695 item_count = 1;
696 data_sp.reset (new DataBufferHeap ((item_byte_size+1) * item_count, '\0')); // account for NULLs as necessary
697 uint8_t *data_ptr = data_sp->GetBytes();
698 auto data_addr = addr;
699 auto count = item_count;
700 item_count = 0;
701 while (item_count < count)
702 {
703 std::string buffer;
704 buffer.resize(item_byte_size+1,0);
705 Error error;
706 size_t read = target->ReadCStringFromMemory(data_addr, &buffer[0], item_byte_size+1, error);
707 if (error.Fail())
708 {
709 result.AppendErrorWithFormat("failed to read memory from 0x%" PRIx64 ".\n", addr);
710 result.SetStatus(eReturnStatusFailed);
711 return false;
712 }
713 if (item_byte_size == read)
714 {
715 result.AppendWarningWithFormat("unable to find a NULL terminated string at 0x%" PRIx64 ".Consider increasing the maximum read length.\n", data_addr);
716 break;
717 }
718 read+=1; // account for final NULL byte
719 memcpy(data_ptr, &buffer[0], read);
720 data_ptr += read;
721 data_addr += read;
722 bytes_read += read;
723 item_count++; // if we break early we know we only read item_count strings
724 }
725 data_sp.reset(new DataBufferHeap(data_sp->GetBytes(),bytes_read+1));
726 }
Chris Lattner24943d22010-06-08 16:52:24 +0000727
Greg Claytonbad1c9e2012-12-15 02:08:17 +0000728 m_next_addr = addr + bytes_read;
729 m_prev_byte_size = bytes_read;
730 m_prev_format_options = m_format_options;
731 m_prev_memory_options = m_memory_options;
732 m_prev_outfile_options = m_outfile_options;
733 m_prev_varobj_options = m_varobj_options;
734 m_prev_clang_ast_type = clang_ast_type;
735
Greg Claytone9f5fbd2010-10-10 20:52:20 +0000736 StreamFile outfile_stream;
737 Stream *output_stream = NULL;
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000738 const FileSpec &outfile_spec = m_outfile_options.GetFile().GetCurrentValue();
739 if (outfile_spec)
Greg Claytone9f5fbd2010-10-10 20:52:20 +0000740 {
741 char path[PATH_MAX];
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000742 outfile_spec.GetPath (path, sizeof(path));
743
744 uint32_t open_options = File::eOpenOptionWrite | File::eOpenOptionCanCreate;
745 const bool append = m_outfile_options.GetAppend().GetCurrentValue();
746 if (append)
747 open_options |= File::eOpenOptionAppend;
748
749 if (outfile_stream.GetFile ().Open (path, open_options).Success())
Greg Claytone9f5fbd2010-10-10 20:52:20 +0000750 {
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000751 if (m_memory_options.m_output_as_binary)
Greg Claytone9f5fbd2010-10-10 20:52:20 +0000752 {
Greg Clayton36da2aa2013-01-25 18:06:21 +0000753 const size_t bytes_written = outfile_stream.Write (data_sp->GetBytes(), bytes_read);
Greg Claytone9f5fbd2010-10-10 20:52:20 +0000754 if (bytes_written > 0)
755 {
Greg Clayton36da2aa2013-01-25 18:06:21 +0000756 result.GetOutputStream().Printf ("%zi bytes %s to '%s'\n",
Greg Claytone9f5fbd2010-10-10 20:52:20 +0000757 bytes_written,
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000758 append ? "appended" : "written",
Greg Claytone9f5fbd2010-10-10 20:52:20 +0000759 path);
760 return true;
761 }
762 else
763 {
Daniel Malea5f35a4b2012-11-29 21:49:15 +0000764 result.AppendErrorWithFormat("Failed to write %" PRIu64 " bytes to '%s'.\n", (uint64_t)bytes_read, path);
Greg Claytone9f5fbd2010-10-10 20:52:20 +0000765 result.SetStatus(eReturnStatusFailed);
766 return false;
767 }
768 }
769 else
770 {
771 // We are going to write ASCII to the file just point the
772 // output_stream to our outfile_stream...
773 output_stream = &outfile_stream;
774 }
775 }
776 else
777 {
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000778 result.AppendErrorWithFormat("Failed to open file '%s' for %s.\n", path, append ? "append" : "write");
Greg Claytone9f5fbd2010-10-10 20:52:20 +0000779 result.SetStatus(eReturnStatusFailed);
780 return false;
781 }
782 }
783 else
784 {
785 output_stream = &result.GetOutputStream();
786 }
787
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000788
Greg Claytonea0bb4d2013-01-09 19:44:40 +0000789 ExecutionContextScope *exe_scope = m_exe_ctx.GetBestExecutionContextScope();
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000790 if (clang_ast_type.GetOpaqueQualType())
791 {
792 for (uint32_t i = 0; i<item_count; ++i)
793 {
794 addr_t item_addr = addr + (i * item_byte_size);
Greg Clayton3508c382012-02-24 01:59:29 +0000795 Address address (item_addr);
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000796 StreamString name_strm;
Daniel Malea5f35a4b2012-11-29 21:49:15 +0000797 name_strm.Printf ("0x%" PRIx64, item_addr);
Greg Clayton24a6bd92011-10-27 17:55:14 +0000798 ValueObjectSP valobj_sp (ValueObjectMemory::Create (exe_scope,
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000799 name_strm.GetString().c_str(),
800 address,
801 clang_ast_type));
802 if (valobj_sp)
803 {
Greg Claytonbad1c9e2012-12-15 02:08:17 +0000804 Format format = m_format_options.GetFormat();
Greg Clayton56bbdaf2011-04-28 20:55:26 +0000805 if (format != eFormatDefault)
806 valobj_sp->SetFormat (format);
807
Greg Clayton56bbdaf2011-04-28 20:55:26 +0000808 bool scope_already_checked = true;
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000809
Enrico Granata3069c622012-03-01 04:24:26 +0000810 ValueObject::DumpValueObjectOptions options;
811 options.SetMaximumPointerDepth(m_varobj_options.ptr_depth)
812 .SetMaximumDepth(m_varobj_options.max_depth)
813 .SetShowLocation(m_varobj_options.show_location)
814 .SetShowTypes(m_varobj_options.show_types)
815 .SetUseObjectiveC(m_varobj_options.use_objc)
816 .SetScopeChecked(scope_already_checked)
817 .SetFlatOutput(m_varobj_options.flat_output)
Enrico Granatacf09f882012-03-19 22:58:49 +0000818 .SetUseSyntheticValue(m_varobj_options.be_raw ? false : m_varobj_options.use_synth)
Enrico Granata3069c622012-03-01 04:24:26 +0000819 .SetOmitSummaryDepth(m_varobj_options.be_raw ? UINT32_MAX : m_varobj_options.no_summary_depth)
820 .SetIgnoreCap(m_varobj_options.be_raw ? true : m_varobj_options.ignore_cap)
821 .SetFormat(format)
822 .SetSummary();
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000823 ValueObject::DumpValueObject (*output_stream,
824 valobj_sp.get(),
Enrico Granata3069c622012-03-01 04:24:26 +0000825 options);
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000826 }
827 else
828 {
829 result.AppendErrorWithFormat ("failed to create a value object for: (%s) %s\n",
830 view_as_type_cstr,
831 name_strm.GetString().c_str());
832 result.SetStatus(eReturnStatusFailed);
833 return false;
834 }
835 }
836 return true;
837 }
838
839 result.SetStatus(eReturnStatusSuccessFinishResult);
840 DataExtractor data (data_sp,
Greg Clayton567e7f32011-09-22 04:58:26 +0000841 target->GetArchitecture().GetByteOrder(),
842 target->GetArchitecture().GetAddressByteSize());
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000843
844
Greg Claytone9f5fbd2010-10-10 20:52:20 +0000845 assert (output_stream);
Greg Clayton36da2aa2013-01-25 18:06:21 +0000846 size_t bytes_dumped = data.Dump (output_stream,
847 0,
848 m_format_options.GetFormat(),
849 item_byte_size,
850 item_count,
851 num_per_line,
852 addr,
853 0,
854 0,
855 exe_scope);
Greg Clayton746979d2011-10-28 23:44:55 +0000856 m_next_addr = addr + bytes_dumped;
Greg Claytone9f5fbd2010-10-10 20:52:20 +0000857 output_stream->EOL();
Chris Lattner24943d22010-06-08 16:52:24 +0000858 return true;
859 }
860
Greg Clayton57b3c6b2011-04-27 22:04:39 +0000861 OptionGroupOptions m_option_group;
862 OptionGroupFormat m_format_options;
863 OptionGroupReadMemory m_memory_options;
864 OptionGroupOutputFile m_outfile_options;
Greg Clayton56bbdaf2011-04-28 20:55:26 +0000865 OptionGroupValueObjectDisplay m_varobj_options;
Greg Clayton902b5be2011-10-26 04:32:38 +0000866 lldb::addr_t m_next_addr;
867 lldb::addr_t m_prev_byte_size;
868 OptionGroupFormat m_prev_format_options;
869 OptionGroupReadMemory m_prev_memory_options;
870 OptionGroupOutputFile m_prev_outfile_options;
871 OptionGroupValueObjectDisplay m_prev_varobj_options;
Greg Claytonbad1c9e2012-12-15 02:08:17 +0000872 ClangASTType m_prev_clang_ast_type;
Chris Lattner24943d22010-06-08 16:52:24 +0000873};
874
Greg Claytona42880a2011-10-25 06:44:01 +0000875
876OptionDefinition
877g_memory_write_option_table[] =
878{
879{ LLDB_OPT_SET_1, true, "infile", 'i', required_argument, NULL, 0, eArgTypeFilename, "Write memory using the contents of a file."},
880{ LLDB_OPT_SET_1, false, "offset", 'o', required_argument, NULL, 0, eArgTypeOffset, "Start writng bytes from an offset within the input file."},
881};
882
883
Chris Lattner24943d22010-06-08 16:52:24 +0000884//----------------------------------------------------------------------
885// Write memory to the inferior process
886//----------------------------------------------------------------------
Jim Inghamda26bd22012-06-08 21:56:10 +0000887class CommandObjectMemoryWrite : public CommandObjectParsed
Chris Lattner24943d22010-06-08 16:52:24 +0000888{
889public:
890
Greg Claytona42880a2011-10-25 06:44:01 +0000891 class OptionGroupWriteMemory : public OptionGroup
Chris Lattner24943d22010-06-08 16:52:24 +0000892 {
893 public:
Greg Claytona42880a2011-10-25 06:44:01 +0000894 OptionGroupWriteMemory () :
895 OptionGroup()
Chris Lattner24943d22010-06-08 16:52:24 +0000896 {
Chris Lattner24943d22010-06-08 16:52:24 +0000897 }
898
899 virtual
Greg Claytona42880a2011-10-25 06:44:01 +0000900 ~OptionGroupWriteMemory ()
Chris Lattner24943d22010-06-08 16:52:24 +0000901 {
902 }
903
Greg Claytona42880a2011-10-25 06:44:01 +0000904 virtual uint32_t
905 GetNumDefinitions ()
906 {
907 return sizeof (g_memory_write_option_table) / sizeof (OptionDefinition);
908 }
909
910 virtual const OptionDefinition*
911 GetDefinitions ()
912 {
913 return g_memory_write_option_table;
914 }
915
Chris Lattner24943d22010-06-08 16:52:24 +0000916 virtual Error
Greg Claytona42880a2011-10-25 06:44:01 +0000917 SetOptionValue (CommandInterpreter &interpreter,
918 uint32_t option_idx,
919 const char *option_arg)
Chris Lattner24943d22010-06-08 16:52:24 +0000920 {
921 Error error;
Greg Clayton6475c422012-12-04 00:32:51 +0000922 const int short_option = g_memory_write_option_table[option_idx].short_option;
Greg Claytona42880a2011-10-25 06:44:01 +0000923
Chris Lattner24943d22010-06-08 16:52:24 +0000924 switch (short_option)
925 {
Greg Claytona42880a2011-10-25 06:44:01 +0000926 case 'i':
927 m_infile.SetFile (option_arg, true);
928 if (!m_infile.Exists())
Greg Claytone9f5fbd2010-10-10 20:52:20 +0000929 {
Greg Claytona42880a2011-10-25 06:44:01 +0000930 m_infile.Clear();
Greg Clayton9c236732011-10-26 00:56:27 +0000931 error.SetErrorStringWithFormat("input file does not exist: '%s'", option_arg);
Greg Claytone9f5fbd2010-10-10 20:52:20 +0000932 }
Greg Claytona42880a2011-10-25 06:44:01 +0000933 break;
934
935 case 'o':
936 {
937 bool success;
938 m_infile_offset = Args::StringToUInt64(option_arg, 0, 0, &success);
939 if (!success)
940 {
Greg Clayton9c236732011-10-26 00:56:27 +0000941 error.SetErrorStringWithFormat("invalid offset string '%s'", option_arg);
Greg Claytona42880a2011-10-25 06:44:01 +0000942 }
943 }
944 break;
945
946 default:
Greg Clayton9c236732011-10-26 00:56:27 +0000947 error.SetErrorStringWithFormat("unrecognized short option '%c'", short_option);
Greg Claytona42880a2011-10-25 06:44:01 +0000948 break;
Chris Lattner24943d22010-06-08 16:52:24 +0000949 }
950 return error;
951 }
Greg Claytona42880a2011-10-25 06:44:01 +0000952
953 virtual void
954 OptionParsingStarting (CommandInterpreter &interpreter)
Chris Lattner24943d22010-06-08 16:52:24 +0000955 {
Greg Claytone9f5fbd2010-10-10 20:52:20 +0000956 m_infile.Clear();
957 m_infile_offset = 0;
Chris Lattner24943d22010-06-08 16:52:24 +0000958 }
959
Greg Claytone9f5fbd2010-10-10 20:52:20 +0000960 FileSpec m_infile;
961 off_t m_infile_offset;
Chris Lattner24943d22010-06-08 16:52:24 +0000962 };
963
Greg Clayton238c0a12010-09-18 01:14:36 +0000964 CommandObjectMemoryWrite (CommandInterpreter &interpreter) :
Jim Inghamda26bd22012-06-08 21:56:10 +0000965 CommandObjectParsed (interpreter,
966 "memory write",
967 "Write to the memory of the process being debugged.",
968 NULL,
Greg Claytonea0bb4d2013-01-09 19:44:40 +0000969 eFlagRequiresProcess | eFlagProcessMustBeLaunched),
Greg Claytona42880a2011-10-25 06:44:01 +0000970 m_option_group (interpreter),
971 m_format_options (eFormatBytes, 1, UINT64_MAX),
972 m_memory_options ()
Chris Lattner24943d22010-06-08 16:52:24 +0000973 {
Caroline Tice43b014a2010-10-04 22:28:36 +0000974 CommandArgumentEntry arg1;
975 CommandArgumentEntry arg2;
976 CommandArgumentData addr_arg;
977 CommandArgumentData value_arg;
978
979 // Define the first (and only) variant of this arg.
980 addr_arg.arg_type = eArgTypeAddress;
981 addr_arg.arg_repetition = eArgRepeatPlain;
982
983 // There is only one variant this argument could be; put it into the argument entry.
984 arg1.push_back (addr_arg);
985
986 // Define the first (and only) variant of this arg.
987 value_arg.arg_type = eArgTypeValue;
988 value_arg.arg_repetition = eArgRepeatPlus;
989
990 // There is only one variant this argument could be; put it into the argument entry.
991 arg2.push_back (value_arg);
992
993 // Push the data for the first argument into the m_arguments vector.
994 m_arguments.push_back (arg1);
995 m_arguments.push_back (arg2);
Greg Claytona42880a2011-10-25 06:44:01 +0000996
997 m_option_group.Append (&m_format_options, OptionGroupFormat::OPTION_GROUP_FORMAT, LLDB_OPT_SET_1);
998 m_option_group.Append (&m_format_options, OptionGroupFormat::OPTION_GROUP_SIZE , LLDB_OPT_SET_1|LLDB_OPT_SET_2);
999 m_option_group.Append (&m_memory_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_2);
1000 m_option_group.Finalize();
1001
Chris Lattner24943d22010-06-08 16:52:24 +00001002 }
1003
1004 virtual
1005 ~CommandObjectMemoryWrite ()
1006 {
1007 }
1008
1009 Options *
1010 GetOptions ()
1011 {
Greg Claytona42880a2011-10-25 06:44:01 +00001012 return &m_option_group;
Chris Lattner24943d22010-06-08 16:52:24 +00001013 }
1014
1015 bool
1016 UIntValueIsValidForSize (uint64_t uval64, size_t total_byte_size)
1017 {
1018 if (total_byte_size > 8)
1019 return false;
1020
1021 if (total_byte_size == 8)
1022 return true;
1023
1024 const uint64_t max = ((uint64_t)1 << (uint64_t)(total_byte_size * 8)) - 1;
1025 return uval64 <= max;
1026 }
1027
1028 bool
1029 SIntValueIsValidForSize (int64_t sval64, size_t total_byte_size)
1030 {
1031 if (total_byte_size > 8)
1032 return false;
1033
1034 if (total_byte_size == 8)
1035 return true;
1036
1037 const int64_t max = ((int64_t)1 << (uint64_t)(total_byte_size * 8 - 1)) - 1;
1038 const int64_t min = ~(max);
1039 return min <= sval64 && sval64 <= max;
1040 }
1041
Jim Inghamda26bd22012-06-08 21:56:10 +00001042protected:
Chris Lattner24943d22010-06-08 16:52:24 +00001043 virtual bool
Jim Inghamda26bd22012-06-08 21:56:10 +00001044 DoExecute (Args& command, CommandReturnObject &result)
Chris Lattner24943d22010-06-08 16:52:24 +00001045 {
Greg Claytonea0bb4d2013-01-09 19:44:40 +00001046 // No need to check "process" for validity as eFlagRequiresProcess ensures it is valid
1047 Process *process = m_exe_ctx.GetProcessPtr();
Chris Lattner24943d22010-06-08 16:52:24 +00001048
1049 const size_t argc = command.GetArgumentCount();
1050
Greg Claytona42880a2011-10-25 06:44:01 +00001051 if (m_memory_options.m_infile)
Chris Lattner24943d22010-06-08 16:52:24 +00001052 {
Greg Claytone9f5fbd2010-10-10 20:52:20 +00001053 if (argc < 1)
1054 {
1055 result.AppendErrorWithFormat ("%s takes a destination address when writing file contents.\n", m_cmd_name.c_str());
1056 result.SetStatus(eReturnStatusFailed);
1057 return false;
1058 }
1059 }
1060 else if (argc < 2)
1061 {
1062 result.AppendErrorWithFormat ("%s takes a destination address and at least one value.\n", m_cmd_name.c_str());
Chris Lattner24943d22010-06-08 16:52:24 +00001063 result.SetStatus(eReturnStatusFailed);
1064 return false;
1065 }
1066
Chris Lattner24943d22010-06-08 16:52:24 +00001067 StreamString buffer (Stream::eBinary,
Greg Clayton395fc332011-02-15 21:59:32 +00001068 process->GetTarget().GetArchitecture().GetAddressByteSize(),
1069 process->GetTarget().GetArchitecture().GetByteOrder());
Chris Lattner24943d22010-06-08 16:52:24 +00001070
Greg Claytona42880a2011-10-25 06:44:01 +00001071 OptionValueUInt64 &byte_size_value = m_format_options.GetByteSizeValue();
1072 size_t item_byte_size = byte_size_value.GetCurrentValue();
Greg Clayton54e7afa2010-07-09 20:39:50 +00001073
Greg Clayton49d888d2012-12-06 22:49:16 +00001074 Error error;
Greg Claytonea0bb4d2013-01-09 19:44:40 +00001075 lldb::addr_t addr = Args::StringToAddress (&m_exe_ctx,
Greg Clayton49d888d2012-12-06 22:49:16 +00001076 command.GetArgumentAtIndex(0),
1077 LLDB_INVALID_ADDRESS,
1078 &error);
Chris Lattner24943d22010-06-08 16:52:24 +00001079
1080 if (addr == LLDB_INVALID_ADDRESS)
1081 {
Greg Clayton49d888d2012-12-06 22:49:16 +00001082 result.AppendError("invalid address expression\n");
1083 result.AppendError(error.AsCString());
Chris Lattner24943d22010-06-08 16:52:24 +00001084 result.SetStatus(eReturnStatusFailed);
1085 return false;
1086 }
Greg Claytone9f5fbd2010-10-10 20:52:20 +00001087
Greg Claytona42880a2011-10-25 06:44:01 +00001088 if (m_memory_options.m_infile)
Greg Claytone9f5fbd2010-10-10 20:52:20 +00001089 {
1090 size_t length = SIZE_MAX;
Greg Claytona42880a2011-10-25 06:44:01 +00001091 if (item_byte_size > 0)
1092 length = item_byte_size;
1093 lldb::DataBufferSP data_sp (m_memory_options.m_infile.ReadFileContents (m_memory_options.m_infile_offset, length));
Greg Claytone9f5fbd2010-10-10 20:52:20 +00001094 if (data_sp)
1095 {
1096 length = data_sp->GetByteSize();
1097 if (length > 0)
1098 {
1099 Error error;
1100 size_t bytes_written = process->WriteMemory (addr, data_sp->GetBytes(), length, error);
1101
1102 if (bytes_written == length)
1103 {
1104 // All bytes written
Daniel Malea5f35a4b2012-11-29 21:49:15 +00001105 result.GetOutputStream().Printf("%" PRIu64 " bytes were written to 0x%" PRIx64 "\n", (uint64_t)bytes_written, addr);
Greg Claytone9f5fbd2010-10-10 20:52:20 +00001106 result.SetStatus(eReturnStatusSuccessFinishResult);
1107 }
1108 else if (bytes_written > 0)
1109 {
1110 // Some byte written
Daniel Malea5f35a4b2012-11-29 21:49:15 +00001111 result.GetOutputStream().Printf("%" PRIu64 " bytes of %" PRIu64 " requested were written to 0x%" PRIx64 "\n", (uint64_t)bytes_written, (uint64_t)length, addr);
Greg Claytone9f5fbd2010-10-10 20:52:20 +00001112 result.SetStatus(eReturnStatusSuccessFinishResult);
1113 }
1114 else
1115 {
Daniel Malea5f35a4b2012-11-29 21:49:15 +00001116 result.AppendErrorWithFormat ("Memory write to 0x%" PRIx64 " failed: %s.\n", addr, error.AsCString());
Greg Claytone9f5fbd2010-10-10 20:52:20 +00001117 result.SetStatus(eReturnStatusFailed);
1118 }
1119 }
1120 }
1121 else
1122 {
1123 result.AppendErrorWithFormat ("Unable to read contents of file.\n");
1124 result.SetStatus(eReturnStatusFailed);
1125 }
1126 return result.Succeeded();
1127 }
Greg Claytona42880a2011-10-25 06:44:01 +00001128 else if (item_byte_size == 0)
Greg Claytone9f5fbd2010-10-10 20:52:20 +00001129 {
Greg Claytona42880a2011-10-25 06:44:01 +00001130 if (m_format_options.GetFormat() == eFormatPointer)
Greg Claytone9f5fbd2010-10-10 20:52:20 +00001131 item_byte_size = buffer.GetAddressByteSize();
1132 else
1133 item_byte_size = 1;
1134 }
1135
Chris Lattner24943d22010-06-08 16:52:24 +00001136 command.Shift(); // shift off the address argument
1137 uint64_t uval64;
1138 int64_t sval64;
1139 bool success = false;
Greg Clayton36da2aa2013-01-25 18:06:21 +00001140 const size_t num_value_args = command.GetArgumentCount();
1141 for (size_t i=0; i<num_value_args; ++i)
Chris Lattner24943d22010-06-08 16:52:24 +00001142 {
1143 const char *value_str = command.GetArgumentAtIndex(i);
1144
Greg Claytona42880a2011-10-25 06:44:01 +00001145 switch (m_format_options.GetFormat())
Chris Lattner24943d22010-06-08 16:52:24 +00001146 {
Greg Clayton3182eff2011-06-23 21:22:24 +00001147 case kNumFormats:
Chris Lattner24943d22010-06-08 16:52:24 +00001148 case eFormatFloat: // TODO: add support for floats soon
1149 case eFormatCharPrintable:
1150 case eFormatBytesWithASCII:
1151 case eFormatComplex:
1152 case eFormatEnum:
1153 case eFormatUnicode16:
1154 case eFormatUnicode32:
1155 case eFormatVectorOfChar:
1156 case eFormatVectorOfSInt8:
1157 case eFormatVectorOfUInt8:
1158 case eFormatVectorOfSInt16:
1159 case eFormatVectorOfUInt16:
1160 case eFormatVectorOfSInt32:
1161 case eFormatVectorOfUInt32:
1162 case eFormatVectorOfSInt64:
1163 case eFormatVectorOfUInt64:
1164 case eFormatVectorOfFloat32:
1165 case eFormatVectorOfFloat64:
1166 case eFormatVectorOfUInt128:
Greg Clayton4fdf7602011-03-20 04:57:14 +00001167 case eFormatOSType:
1168 case eFormatComplexInteger:
Greg Clayton24a6bd92011-10-27 17:55:14 +00001169 case eFormatAddressInfo:
1170 case eFormatHexFloat:
1171 case eFormatInstruction:
Sean Callanan96abc622012-08-08 17:35:10 +00001172 case eFormatVoid:
Chris Lattner24943d22010-06-08 16:52:24 +00001173 result.AppendError("unsupported format for writing memory");
1174 result.SetStatus(eReturnStatusFailed);
1175 return false;
1176
1177 case eFormatDefault:
1178 case eFormatBytes:
1179 case eFormatHex:
Enrico Granata535543d2012-08-09 19:33:34 +00001180 case eFormatHexUppercase:
Greg Clayton54e7afa2010-07-09 20:39:50 +00001181 case eFormatPointer:
1182
Chris Lattner24943d22010-06-08 16:52:24 +00001183 // Decode hex bytes
1184 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 16, &success);
1185 if (!success)
1186 {
1187 result.AppendErrorWithFormat ("'%s' is not a valid hex string value.\n", value_str);
1188 result.SetStatus(eReturnStatusFailed);
1189 return false;
1190 }
1191 else if (!UIntValueIsValidForSize (uval64, item_byte_size))
1192 {
Daniel Malea5f35a4b2012-11-29 21:49:15 +00001193 result.AppendErrorWithFormat ("Value 0x%" PRIx64 " is too large to fit in a %lu byte unsigned integer value.\n", uval64, item_byte_size);
Chris Lattner24943d22010-06-08 16:52:24 +00001194 result.SetStatus(eReturnStatusFailed);
1195 return false;
1196 }
1197 buffer.PutMaxHex64 (uval64, item_byte_size);
1198 break;
1199
1200 case eFormatBoolean:
1201 uval64 = Args::StringToBoolean(value_str, false, &success);
1202 if (!success)
1203 {
1204 result.AppendErrorWithFormat ("'%s' is not a valid boolean string value.\n", value_str);
1205 result.SetStatus(eReturnStatusFailed);
1206 return false;
1207 }
1208 buffer.PutMaxHex64 (uval64, item_byte_size);
1209 break;
1210
1211 case eFormatBinary:
1212 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 2, &success);
1213 if (!success)
1214 {
1215 result.AppendErrorWithFormat ("'%s' is not a valid binary string value.\n", value_str);
1216 result.SetStatus(eReturnStatusFailed);
1217 return false;
1218 }
1219 else if (!UIntValueIsValidForSize (uval64, item_byte_size))
1220 {
Daniel Malea5f35a4b2012-11-29 21:49:15 +00001221 result.AppendErrorWithFormat ("Value 0x%" PRIx64 " is too large to fit in a %lu byte unsigned integer value.\n", uval64, item_byte_size);
Chris Lattner24943d22010-06-08 16:52:24 +00001222 result.SetStatus(eReturnStatusFailed);
1223 return false;
1224 }
1225 buffer.PutMaxHex64 (uval64, item_byte_size);
1226 break;
1227
Greg Clayton307fa072011-06-17 23:50:44 +00001228 case eFormatCharArray:
Chris Lattner24943d22010-06-08 16:52:24 +00001229 case eFormatChar:
1230 case eFormatCString:
1231 if (value_str[0])
1232 {
1233 size_t len = strlen (value_str);
1234 // Include the NULL for C strings...
Greg Claytona42880a2011-10-25 06:44:01 +00001235 if (m_format_options.GetFormat() == eFormatCString)
Chris Lattner24943d22010-06-08 16:52:24 +00001236 ++len;
1237 Error error;
1238 if (process->WriteMemory (addr, value_str, len, error) == len)
1239 {
1240 addr += len;
1241 }
1242 else
1243 {
Daniel Malea5f35a4b2012-11-29 21:49:15 +00001244 result.AppendErrorWithFormat ("Memory write to 0x%" PRIx64 " failed: %s.\n", addr, error.AsCString());
Chris Lattner24943d22010-06-08 16:52:24 +00001245 result.SetStatus(eReturnStatusFailed);
1246 return false;
1247 }
1248 }
1249 break;
1250
1251 case eFormatDecimal:
1252 sval64 = Args::StringToSInt64(value_str, INT64_MAX, 0, &success);
1253 if (!success)
1254 {
1255 result.AppendErrorWithFormat ("'%s' is not a valid signed decimal value.\n", value_str);
1256 result.SetStatus(eReturnStatusFailed);
1257 return false;
1258 }
1259 else if (!SIntValueIsValidForSize (sval64, item_byte_size))
1260 {
Daniel Malea5f35a4b2012-11-29 21:49:15 +00001261 result.AppendErrorWithFormat ("Value %" PRIi64 " is too large or small to fit in a %lu byte signed integer value.\n", sval64, item_byte_size);
Chris Lattner24943d22010-06-08 16:52:24 +00001262 result.SetStatus(eReturnStatusFailed);
1263 return false;
1264 }
1265 buffer.PutMaxHex64 (sval64, item_byte_size);
1266 break;
1267
1268 case eFormatUnsigned:
1269 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 0, &success);
1270 if (!success)
1271 {
1272 result.AppendErrorWithFormat ("'%s' is not a valid unsigned decimal string value.\n", value_str);
1273 result.SetStatus(eReturnStatusFailed);
1274 return false;
1275 }
1276 else if (!UIntValueIsValidForSize (uval64, item_byte_size))
1277 {
Daniel Malea5f35a4b2012-11-29 21:49:15 +00001278 result.AppendErrorWithFormat ("Value %" PRIu64 " is too large to fit in a %lu byte unsigned integer value.\n", uval64, item_byte_size);
Chris Lattner24943d22010-06-08 16:52:24 +00001279 result.SetStatus(eReturnStatusFailed);
1280 return false;
1281 }
1282 buffer.PutMaxHex64 (uval64, item_byte_size);
1283 break;
1284
1285 case eFormatOctal:
1286 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 8, &success);
1287 if (!success)
1288 {
1289 result.AppendErrorWithFormat ("'%s' is not a valid octal string value.\n", value_str);
1290 result.SetStatus(eReturnStatusFailed);
1291 return false;
1292 }
1293 else if (!UIntValueIsValidForSize (uval64, item_byte_size))
1294 {
Daniel Malea5f35a4b2012-11-29 21:49:15 +00001295 result.AppendErrorWithFormat ("Value %" PRIo64 " is too large to fit in a %lu byte unsigned integer value.\n", uval64, item_byte_size);
Chris Lattner24943d22010-06-08 16:52:24 +00001296 result.SetStatus(eReturnStatusFailed);
1297 return false;
1298 }
1299 buffer.PutMaxHex64 (uval64, item_byte_size);
1300 break;
1301 }
1302 }
1303
1304 if (!buffer.GetString().empty())
1305 {
1306 Error error;
Greg Clayton53d68e72010-07-20 22:52:08 +00001307 if (process->WriteMemory (addr, buffer.GetString().c_str(), buffer.GetString().size(), error) == buffer.GetString().size())
Chris Lattner24943d22010-06-08 16:52:24 +00001308 return true;
1309 else
1310 {
Daniel Malea5f35a4b2012-11-29 21:49:15 +00001311 result.AppendErrorWithFormat ("Memory write to 0x%" PRIx64 " failed: %s.\n", addr, error.AsCString());
Chris Lattner24943d22010-06-08 16:52:24 +00001312 result.SetStatus(eReturnStatusFailed);
1313 return false;
1314 }
1315 }
1316 return true;
1317 }
1318
Greg Claytona42880a2011-10-25 06:44:01 +00001319 OptionGroupOptions m_option_group;
1320 OptionGroupFormat m_format_options;
1321 OptionGroupWriteMemory m_memory_options;
Chris Lattner24943d22010-06-08 16:52:24 +00001322};
1323
Chris Lattner24943d22010-06-08 16:52:24 +00001324
1325//-------------------------------------------------------------------------
1326// CommandObjectMemory
1327//-------------------------------------------------------------------------
1328
Greg Clayton63094e02010-06-23 01:19:29 +00001329CommandObjectMemory::CommandObjectMemory (CommandInterpreter &interpreter) :
Greg Clayton238c0a12010-09-18 01:14:36 +00001330 CommandObjectMultiword (interpreter,
1331 "memory",
Caroline Ticec1ad82e2010-09-07 22:38:08 +00001332 "A set of commands for operating on memory.",
Chris Lattner24943d22010-06-08 16:52:24 +00001333 "memory <subcommand> [<subcommand-options>]")
1334{
Greg Clayton238c0a12010-09-18 01:14:36 +00001335 LoadSubCommand ("read", CommandObjectSP (new CommandObjectMemoryRead (interpreter)));
1336 LoadSubCommand ("write", CommandObjectSP (new CommandObjectMemoryWrite (interpreter)));
Chris Lattner24943d22010-06-08 16:52:24 +00001337}
1338
1339CommandObjectMemory::~CommandObjectMemory ()
1340{
1341}