blob: 3020c01de81f0c949cc81a6a71f6a3f1f604f645 [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
10#include "CommandObjectMemory.h"
11
12// C Includes
13// C++ Includes
14// Other libraries and framework includes
15// Project includes
Chris Lattner24943d22010-06-08 16:52:24 +000016#include "lldb/Core/DataBufferHeap.h"
17#include "lldb/Core/DataExtractor.h"
Greg Clayton63094e02010-06-23 01:19:29 +000018#include "lldb/Core/Debugger.h"
Chris Lattner24943d22010-06-08 16:52:24 +000019#include "lldb/Core/StreamString.h"
Greg Clayton63094e02010-06-23 01:19:29 +000020#include "lldb/Interpreter/Args.h"
Chris Lattner24943d22010-06-08 16:52:24 +000021#include "lldb/Interpreter/CommandReturnObject.h"
Greg Clayton63094e02010-06-23 01:19:29 +000022#include "lldb/Interpreter/CommandInterpreter.h"
23#include "lldb/Interpreter/Options.h"
Chris Lattner24943d22010-06-08 16:52:24 +000024#include "lldb/Target/Process.h"
25
26using namespace lldb;
27using namespace lldb_private;
28
29//----------------------------------------------------------------------
30// Read memory from the inferior process
31//----------------------------------------------------------------------
32class CommandObjectMemoryRead : public CommandObject
33{
34public:
35
36 class CommandOptions : public Options
37 {
38 public:
39 CommandOptions () :
40 Options()
41 {
42 ResetOptionValues();
43 }
44
45 virtual
46 ~CommandOptions ()
47 {
48 }
49
50 virtual Error
51 SetOptionValue (int option_idx, const char *option_arg)
52 {
53 Error error;
54 char short_option = (char) m_getopt_table[option_idx].val;
55
56 switch (short_option)
57 {
58 case 'f':
59 error = Args::StringToFormat (option_arg, m_format);
60
61 switch (m_format)
62 {
63 default:
64 break;
65
66 case eFormatBoolean:
67 if (m_byte_size == 0)
68 m_byte_size = 1;
69 if (m_num_per_line == 0)
70 m_num_per_line = 1;
71 break;
72
73 case eFormatCString:
74 if (m_num_per_line == 0)
75 m_num_per_line = 1;
76 break;
77
78 case eFormatPointer:
79 break;
80
81 case eFormatBinary:
82 case eFormatFloat:
83 case eFormatOctal:
84 case eFormatDecimal:
85 case eFormatEnum:
86 case eFormatUnicode16:
87 case eFormatUnicode32:
88 case eFormatUnsigned:
89 if (m_byte_size == 0)
90 m_byte_size = 4;
91 if (m_num_per_line == 0)
92 m_num_per_line = 1;
93 break;
94
95 case eFormatBytes:
96 case eFormatBytesWithASCII:
97 case eFormatChar:
98 case eFormatCharPrintable:
99 if (m_byte_size == 0)
100 m_byte_size = 1;
101 break;
102 case eFormatComplex:
103 if (m_byte_size == 0)
104 m_byte_size = 8;
105 break;
106 case eFormatHex:
107 if (m_byte_size == 0)
108 m_byte_size = 4;
109 break;
110
111 case eFormatVectorOfChar:
112 case eFormatVectorOfSInt8:
113 case eFormatVectorOfUInt8:
114 case eFormatVectorOfSInt16:
115 case eFormatVectorOfUInt16:
116 case eFormatVectorOfSInt32:
117 case eFormatVectorOfUInt32:
118 case eFormatVectorOfSInt64:
119 case eFormatVectorOfUInt64:
120 case eFormatVectorOfFloat32:
121 case eFormatVectorOfFloat64:
122 case eFormatVectorOfUInt128:
123 break;
124 }
125 break;
126
127 case 'l':
128 m_num_per_line = Args::StringToUInt32 (option_arg, 0);
129 if (m_num_per_line == 0)
130 error.SetErrorStringWithFormat("Invalid value for --num-per-line option '%s'. Must be positive integer value.\n", option_arg);
131 break;
132
133 case 'c':
134 m_count = Args::StringToUInt32 (option_arg, 0);
135 if (m_count == 0)
136 error.SetErrorStringWithFormat("Invalid value for --count option '%s'. Must be positive integer value.\n", option_arg);
137 break;
138
139 case 's':
140 m_byte_size = Args::StringToUInt32 (option_arg, 0);
141 if (m_byte_size == 0)
142 error.SetErrorStringWithFormat("Invalid value for --size option '%s'. Must be positive integer value.\n", option_arg);
143 break;
144
Greg Claytone9f5fbd2010-10-10 20:52:20 +0000145 case 'o':
Greg Clayton537a7a82010-10-20 20:54:39 +0000146 m_outfile_filespec.SetFile (option_arg, true);
Greg Claytone9f5fbd2010-10-10 20:52:20 +0000147 break;
148
149 case 'b':
150 m_output_as_binary = true;
151 break;
152
153 case 'a':
154 m_append_to_outfile = true;
155 break;
156
Chris Lattner24943d22010-06-08 16:52:24 +0000157 default:
158 error.SetErrorStringWithFormat("Unrecognized short option '%c'.\n", short_option);
159 break;
160 }
161 return error;
162 }
163
164 void
165 ResetOptionValues ()
166 {
167 Options::ResetOptionValues();
168 m_format = eFormatBytesWithASCII;
169 m_byte_size = 0;
170 m_count = 0;
171 m_num_per_line = 0;
Greg Claytone9f5fbd2010-10-10 20:52:20 +0000172 m_outfile_filespec.Clear();
173 m_append_to_outfile = false;
174 m_output_as_binary = false;
Chris Lattner24943d22010-06-08 16:52:24 +0000175 }
176
177 const lldb::OptionDefinition*
178 GetDefinitions ()
179 {
180 return g_option_table;
181 }
182
183 // Options table: Required for subclasses of Options.
184
185 static lldb::OptionDefinition g_option_table[];
186
187 // Instance variables to hold the values for command options.
188 lldb::Format m_format;
189 uint32_t m_byte_size;
190 uint32_t m_count;
191 uint32_t m_num_per_line;
Greg Claytone9f5fbd2010-10-10 20:52:20 +0000192 FileSpec m_outfile_filespec;
193 bool m_append_to_outfile;
194 bool m_output_as_binary;
Chris Lattner24943d22010-06-08 16:52:24 +0000195 };
196
Greg Clayton238c0a12010-09-18 01:14:36 +0000197 CommandObjectMemoryRead (CommandInterpreter &interpreter) :
198 CommandObject (interpreter,
199 "memory read",
Caroline Ticeabb507a2010-09-08 21:06:11 +0000200 "Read from the memory of the process being debugged.",
Caroline Tice43b014a2010-10-04 22:28:36 +0000201 NULL,
Chris Lattner24943d22010-06-08 16:52:24 +0000202 eFlagProcessMustBeLaunched)
203 {
Caroline Tice43b014a2010-10-04 22:28:36 +0000204 CommandArgumentEntry arg1;
205 CommandArgumentEntry arg2;
206 CommandArgumentData start_addr_arg;
207 CommandArgumentData end_addr_arg;
208
209 // Define the first (and only) variant of this arg.
210 start_addr_arg.arg_type = eArgTypeStartAddress;
211 start_addr_arg.arg_repetition = eArgRepeatPlain;
212
213 // There is only one variant this argument could be; put it into the argument entry.
214 arg1.push_back (start_addr_arg);
215
216 // Define the first (and only) variant of this arg.
217 end_addr_arg.arg_type = eArgTypeEndAddress;
218 end_addr_arg.arg_repetition = eArgRepeatOptional;
219
220 // There is only one variant this argument could be; put it into the argument entry.
221 arg2.push_back (end_addr_arg);
222
223 // Push the data for the first argument into the m_arguments vector.
224 m_arguments.push_back (arg1);
225 m_arguments.push_back (arg2);
Chris Lattner24943d22010-06-08 16:52:24 +0000226 }
227
228 virtual
229 ~CommandObjectMemoryRead ()
230 {
231 }
232
233 Options *
234 GetOptions ()
235 {
236 return &m_options;
237 }
238
239 virtual bool
Greg Clayton238c0a12010-09-18 01:14:36 +0000240 Execute (Args& command,
Chris Lattner24943d22010-06-08 16:52:24 +0000241 CommandReturnObject &result)
242 {
Greg Clayton238c0a12010-09-18 01:14:36 +0000243 Process *process = m_interpreter.GetDebugger().GetExecutionContext().process;
Chris Lattner24943d22010-06-08 16:52:24 +0000244 if (process == NULL)
245 {
246 result.AppendError("need a process to read memory");
247 result.SetStatus(eReturnStatusFailed);
248 return false;
249 }
250 const size_t argc = command.GetArgumentCount();
251
252 if (argc == 0 || argc > 2)
253 {
254 result.AppendErrorWithFormat ("%s takes 1 or two args.\n", m_cmd_name.c_str());
255 result.SetStatus(eReturnStatusFailed);
256 return false;
257 }
258
259 size_t item_byte_size = m_options.m_byte_size;
260 if (item_byte_size == 0)
261 {
262 if (m_options.m_format == eFormatPointer)
263 item_byte_size = process->GetAddressByteSize();
264 else
265 item_byte_size = 1;
266 }
267
268 size_t item_count = m_options.m_count;
269
270 size_t num_per_line = m_options.m_num_per_line;
271 if (num_per_line == 0)
272 {
273 num_per_line = (16/item_byte_size);
274 if (num_per_line == 0)
275 num_per_line = 1;
276 }
277
278 size_t total_byte_size = m_options.m_count * item_byte_size;
279 if (total_byte_size == 0)
280 total_byte_size = 32;
281
282 lldb::addr_t addr = Args::StringToUInt64(command.GetArgumentAtIndex(0), LLDB_INVALID_ADDRESS, 0);
283
284 if (addr == LLDB_INVALID_ADDRESS)
285 {
286 result.AppendErrorWithFormat("invalid start address string '%s'.\n", command.GetArgumentAtIndex(0));
287 result.SetStatus(eReturnStatusFailed);
288 return false;
289 }
290
291 if (argc == 2)
292 {
293 lldb::addr_t end_addr = Args::StringToUInt64(command.GetArgumentAtIndex(1), LLDB_INVALID_ADDRESS, 0);
294 if (end_addr == LLDB_INVALID_ADDRESS)
295 {
296 result.AppendErrorWithFormat("Invalid end address string '%s'.\n", command.GetArgumentAtIndex(1));
297 result.SetStatus(eReturnStatusFailed);
298 return false;
299 }
300 else if (end_addr <= addr)
301 {
302 result.AppendErrorWithFormat("End address (0x%llx) must be greater that the start address (0x%llx).\n", end_addr, addr);
303 result.SetStatus(eReturnStatusFailed);
304 return false;
305 }
306 else if (item_count != 0)
307 {
308 result.AppendErrorWithFormat("Specify either the end address (0x%llx) or the count (--count %u), not both.\n", end_addr, item_count);
309 result.SetStatus(eReturnStatusFailed);
310 return false;
311 }
312
313 total_byte_size = end_addr - addr;
314 item_count = total_byte_size / item_byte_size;
315 }
316 else
317 {
318 if (item_count == 0)
319 item_count = 32;
320 }
321
322 DataBufferSP data_sp(new DataBufferHeap (total_byte_size, '\0'));
323 Error error;
324 size_t bytes_read = process->ReadMemory(addr, data_sp->GetBytes (), data_sp->GetByteSize(), error);
325 if (bytes_read == 0)
326 {
327 result.AppendWarningWithFormat("Read from 0x%llx failed.\n", addr);
328 result.AppendError(error.AsCString());
329 result.SetStatus(eReturnStatusFailed);
330 return false;
331 }
332
333 if (bytes_read < total_byte_size)
334 result.AppendWarningWithFormat("Not all bytes (%u/%u) were able to be read from 0x%llx.\n", bytes_read, total_byte_size, addr);
335
336 result.SetStatus(eReturnStatusSuccessFinishResult);
337 DataExtractor data(data_sp, process->GetByteOrder(), process->GetAddressByteSize());
338
Greg Claytone9f5fbd2010-10-10 20:52:20 +0000339 StreamFile outfile_stream;
340 Stream *output_stream = NULL;
341
342 if (m_options.m_outfile_filespec)
343 {
344 char path[PATH_MAX];
345 m_options.m_outfile_filespec.GetPath (path, sizeof(path));
346 char mode[16] = { 'w', '\0' };
347 if (m_options.m_append_to_outfile)
348 mode[0] = 'a';
349
350 if (outfile_stream.Open (path, mode))
351 {
352 if (m_options.m_output_as_binary)
353 {
354 int bytes_written = outfile_stream.Write (data_sp->GetBytes(), bytes_read);
355 if (bytes_written > 0)
356 {
357 result.GetOutputStream().Printf ("%i bytes %s to '%s'\n",
358 bytes_written,
359 m_options.m_append_to_outfile ? "appended" : "written",
360 path);
361 return true;
362 }
363 else
364 {
365 result.AppendErrorWithFormat("Failed to write %zu bytes to '%s'.\n", bytes_read, path);
366 result.SetStatus(eReturnStatusFailed);
367 return false;
368 }
369 }
370 else
371 {
372 // We are going to write ASCII to the file just point the
373 // output_stream to our outfile_stream...
374 output_stream = &outfile_stream;
375 }
376 }
377 else
378 {
379 result.AppendErrorWithFormat("Failed to open file '%s' with a mode of '%s'.\n", path, mode);
380 result.SetStatus(eReturnStatusFailed);
381 return false;
382 }
383 }
384 else
385 {
386 output_stream = &result.GetOutputStream();
387 }
388
389 assert (output_stream);
390 data.Dump (output_stream,
391 0,
392 m_options.m_format,
393 item_byte_size,
394 item_count,
395 num_per_line,
396 addr,
397 0,
398 0);
399 output_stream->EOL();
Chris Lattner24943d22010-06-08 16:52:24 +0000400 return true;
401 }
402
403protected:
404 CommandOptions m_options;
405};
406
Greg Claytone9f5fbd2010-10-10 20:52:20 +0000407#define SET1 LLDB_OPT_SET_1
408#define SET2 LLDB_OPT_SET_2
409
Chris Lattner24943d22010-06-08 16:52:24 +0000410lldb::OptionDefinition
411CommandObjectMemoryRead::CommandOptions::g_option_table[] =
412{
Greg Claytone9f5fbd2010-10-10 20:52:20 +0000413{ SET1 , false, "format", 'f', required_argument, NULL, 0, eArgTypeFormat, "The format that will be used to display the memory. Defaults to bytes with ASCII (--format=Y)."},
414{ SET1 , false, "size", 's', required_argument, NULL, 0, eArgTypeByteSize, "The size in bytes to use when displaying with the selected format."},
415{ SET1 , false, "num-per-line", 'l', required_argument, NULL, 0, eArgTypeNumberPerLine,"The number of items per line to display."},
416{ SET1 , false, "count", 'c', required_argument, NULL, 0, eArgTypeCount, "The number of total items to display."},
417{ SET1 | SET2, false, "outfile", 'o', required_argument, NULL, 0, eArgTypeFilename, "Dump memory read results into a file."},
418{ SET1 | SET2, false, "append", 'a', no_argument, NULL, 0, eArgTypeNone, "Append memory read results to 'outfile'."},
419{ SET2, 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."},
420{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
Chris Lattner24943d22010-06-08 16:52:24 +0000421};
422
Greg Claytone9f5fbd2010-10-10 20:52:20 +0000423#undef SET1
424#undef SET2
Chris Lattner24943d22010-06-08 16:52:24 +0000425
426//----------------------------------------------------------------------
427// Write memory to the inferior process
428//----------------------------------------------------------------------
429class CommandObjectMemoryWrite : public CommandObject
430{
431public:
432
433 class CommandOptions : public Options
434 {
435 public:
436 CommandOptions () :
437 Options()
438 {
439 ResetOptionValues();
440 }
441
442 virtual
443 ~CommandOptions ()
444 {
445 }
446
447 virtual Error
448 SetOptionValue (int option_idx, const char *option_arg)
449 {
450 Error error;
451 char short_option = (char) m_getopt_table[option_idx].val;
452 switch (short_option)
453 {
454 case 'f':
455 error = Args::StringToFormat (option_arg, m_format);
456 break;
457
458 case 's':
459 m_byte_size = Args::StringToUInt32 (option_arg, 0);
460 if (m_byte_size == 0)
461 error.SetErrorStringWithFormat("Invalid value for --size option '%s'. Must be positive integer value.\n", option_arg);
462 break;
463
Greg Claytone9f5fbd2010-10-10 20:52:20 +0000464 case 'i':
Greg Clayton537a7a82010-10-20 20:54:39 +0000465 m_infile.SetFile (option_arg, true);
Greg Claytone9f5fbd2010-10-10 20:52:20 +0000466 if (!m_infile.Exists())
467 {
468 m_infile.Clear();
469 error.SetErrorStringWithFormat("Input file does not exist: '%s'\n", option_arg);
470 }
471 break;
472
473 case 'o':
474 {
475 bool success;
476 m_infile_offset = Args::StringToUInt64(option_arg, 0, 0, &success);
477 if (!success)
478 {
479 error.SetErrorStringWithFormat("Invalid offset string '%s'\n", option_arg);
480 }
481 }
482 break;
Chris Lattner24943d22010-06-08 16:52:24 +0000483
484 default:
485 error.SetErrorStringWithFormat("Unrecognized short option '%c'\n", short_option);
486 break;
487 }
488 return error;
489 }
490
491 void
492 ResetOptionValues ()
493 {
494 Options::ResetOptionValues();
495 m_format = eFormatBytes;
496 m_byte_size = 1;
Greg Claytone9f5fbd2010-10-10 20:52:20 +0000497 m_infile.Clear();
498 m_infile_offset = 0;
Chris Lattner24943d22010-06-08 16:52:24 +0000499 }
500
501 const lldb::OptionDefinition*
502 GetDefinitions ()
503 {
504 return g_option_table;
505 }
506
507 // Options table: Required for subclasses of Options.
508
509 static lldb::OptionDefinition g_option_table[];
510
511 // Instance variables to hold the values for command options.
512 lldb::Format m_format;
513 uint32_t m_byte_size;
Greg Claytone9f5fbd2010-10-10 20:52:20 +0000514 FileSpec m_infile;
515 off_t m_infile_offset;
Chris Lattner24943d22010-06-08 16:52:24 +0000516 };
517
Greg Clayton238c0a12010-09-18 01:14:36 +0000518 CommandObjectMemoryWrite (CommandInterpreter &interpreter) :
519 CommandObject (interpreter,
520 "memory write",
Caroline Ticeabb507a2010-09-08 21:06:11 +0000521 "Write to the memory of the process being debugged.",
Caroline Tice43b014a2010-10-04 22:28:36 +0000522 //"memory write [<cmd-options>] <addr> [value1 value2 ...]",
523 NULL,
Chris Lattner24943d22010-06-08 16:52:24 +0000524 eFlagProcessMustBeLaunched)
525 {
Caroline Tice43b014a2010-10-04 22:28:36 +0000526 CommandArgumentEntry arg1;
527 CommandArgumentEntry arg2;
528 CommandArgumentData addr_arg;
529 CommandArgumentData value_arg;
530
531 // Define the first (and only) variant of this arg.
532 addr_arg.arg_type = eArgTypeAddress;
533 addr_arg.arg_repetition = eArgRepeatPlain;
534
535 // There is only one variant this argument could be; put it into the argument entry.
536 arg1.push_back (addr_arg);
537
538 // Define the first (and only) variant of this arg.
539 value_arg.arg_type = eArgTypeValue;
540 value_arg.arg_repetition = eArgRepeatPlus;
541
542 // There is only one variant this argument could be; put it into the argument entry.
543 arg2.push_back (value_arg);
544
545 // Push the data for the first argument into the m_arguments vector.
546 m_arguments.push_back (arg1);
547 m_arguments.push_back (arg2);
Chris Lattner24943d22010-06-08 16:52:24 +0000548 }
549
550 virtual
551 ~CommandObjectMemoryWrite ()
552 {
553 }
554
555 Options *
556 GetOptions ()
557 {
558 return &m_options;
559 }
560
561 bool
562 UIntValueIsValidForSize (uint64_t uval64, size_t total_byte_size)
563 {
564 if (total_byte_size > 8)
565 return false;
566
567 if (total_byte_size == 8)
568 return true;
569
570 const uint64_t max = ((uint64_t)1 << (uint64_t)(total_byte_size * 8)) - 1;
571 return uval64 <= max;
572 }
573
574 bool
575 SIntValueIsValidForSize (int64_t sval64, size_t total_byte_size)
576 {
577 if (total_byte_size > 8)
578 return false;
579
580 if (total_byte_size == 8)
581 return true;
582
583 const int64_t max = ((int64_t)1 << (uint64_t)(total_byte_size * 8 - 1)) - 1;
584 const int64_t min = ~(max);
585 return min <= sval64 && sval64 <= max;
586 }
587
588 virtual bool
Greg Clayton238c0a12010-09-18 01:14:36 +0000589 Execute (Args& command,
Chris Lattner24943d22010-06-08 16:52:24 +0000590 CommandReturnObject &result)
591 {
Greg Clayton238c0a12010-09-18 01:14:36 +0000592 Process *process = m_interpreter.GetDebugger().GetExecutionContext().process;
Chris Lattner24943d22010-06-08 16:52:24 +0000593 if (process == NULL)
594 {
595 result.AppendError("need a process to read memory");
596 result.SetStatus(eReturnStatusFailed);
597 return false;
598 }
599
600 const size_t argc = command.GetArgumentCount();
601
Greg Claytone9f5fbd2010-10-10 20:52:20 +0000602 if (m_options.m_infile)
Chris Lattner24943d22010-06-08 16:52:24 +0000603 {
Greg Claytone9f5fbd2010-10-10 20:52:20 +0000604 if (argc < 1)
605 {
606 result.AppendErrorWithFormat ("%s takes a destination address when writing file contents.\n", m_cmd_name.c_str());
607 result.SetStatus(eReturnStatusFailed);
608 return false;
609 }
610 }
611 else if (argc < 2)
612 {
613 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 +0000614 result.SetStatus(eReturnStatusFailed);
615 return false;
616 }
617
Chris Lattner24943d22010-06-08 16:52:24 +0000618 StreamString buffer (Stream::eBinary,
619 process->GetAddressByteSize(),
620 process->GetByteOrder());
621
Greg Clayton54e7afa2010-07-09 20:39:50 +0000622 size_t item_byte_size = m_options.m_byte_size;
Greg Clayton54e7afa2010-07-09 20:39:50 +0000623
Chris Lattner24943d22010-06-08 16:52:24 +0000624 lldb::addr_t addr = Args::StringToUInt64(command.GetArgumentAtIndex(0), LLDB_INVALID_ADDRESS, 0);
625
626 if (addr == LLDB_INVALID_ADDRESS)
627 {
628 result.AppendErrorWithFormat("Invalid address string '%s'.\n", command.GetArgumentAtIndex(0));
629 result.SetStatus(eReturnStatusFailed);
630 return false;
631 }
Greg Claytone9f5fbd2010-10-10 20:52:20 +0000632
633 if (m_options.m_infile)
634 {
635 size_t length = SIZE_MAX;
636 if (m_options.m_byte_size > 0)
637 length = m_options.m_byte_size;
638 lldb::DataBufferSP data_sp (m_options.m_infile.ReadFileContents (m_options.m_infile_offset, length));
639 if (data_sp)
640 {
641 length = data_sp->GetByteSize();
642 if (length > 0)
643 {
644 Error error;
645 size_t bytes_written = process->WriteMemory (addr, data_sp->GetBytes(), length, error);
646
647 if (bytes_written == length)
648 {
649 // All bytes written
650 result.GetOutputStream().Printf("%zu bytes were written to 0x%llx\n", bytes_written, addr);
651 result.SetStatus(eReturnStatusSuccessFinishResult);
652 }
653 else if (bytes_written > 0)
654 {
655 // Some byte written
656 result.GetOutputStream().Printf("%zu bytes of %zu requested were written to 0x%llx\n", bytes_written, length, addr);
657 result.SetStatus(eReturnStatusSuccessFinishResult);
658 }
659 else
660 {
661 result.AppendErrorWithFormat ("Memory write to 0x%llx failed: %s.\n", addr, error.AsCString());
662 result.SetStatus(eReturnStatusFailed);
663 }
664 }
665 }
666 else
667 {
668 result.AppendErrorWithFormat ("Unable to read contents of file.\n");
669 result.SetStatus(eReturnStatusFailed);
670 }
671 return result.Succeeded();
672 }
673 else if (m_options.m_byte_size == 0)
674 {
675 if (m_options.m_format == eFormatPointer)
676 item_byte_size = buffer.GetAddressByteSize();
677 else
678 item_byte_size = 1;
679 }
680
Chris Lattner24943d22010-06-08 16:52:24 +0000681 command.Shift(); // shift off the address argument
682 uint64_t uval64;
683 int64_t sval64;
684 bool success = false;
685 const uint32_t num_value_args = command.GetArgumentCount();
686 uint32_t i;
687 for (i=0; i<num_value_args; ++i)
688 {
689 const char *value_str = command.GetArgumentAtIndex(i);
690
691 switch (m_options.m_format)
692 {
693 case eFormatFloat: // TODO: add support for floats soon
694 case eFormatCharPrintable:
695 case eFormatBytesWithASCII:
696 case eFormatComplex:
697 case eFormatEnum:
698 case eFormatUnicode16:
699 case eFormatUnicode32:
700 case eFormatVectorOfChar:
701 case eFormatVectorOfSInt8:
702 case eFormatVectorOfUInt8:
703 case eFormatVectorOfSInt16:
704 case eFormatVectorOfUInt16:
705 case eFormatVectorOfSInt32:
706 case eFormatVectorOfUInt32:
707 case eFormatVectorOfSInt64:
708 case eFormatVectorOfUInt64:
709 case eFormatVectorOfFloat32:
710 case eFormatVectorOfFloat64:
711 case eFormatVectorOfUInt128:
712 result.AppendError("unsupported format for writing memory");
713 result.SetStatus(eReturnStatusFailed);
714 return false;
715
716 case eFormatDefault:
717 case eFormatBytes:
718 case eFormatHex:
Greg Clayton54e7afa2010-07-09 20:39:50 +0000719 case eFormatPointer:
720
Chris Lattner24943d22010-06-08 16:52:24 +0000721 // Decode hex bytes
722 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 16, &success);
723 if (!success)
724 {
725 result.AppendErrorWithFormat ("'%s' is not a valid hex string value.\n", value_str);
726 result.SetStatus(eReturnStatusFailed);
727 return false;
728 }
729 else if (!UIntValueIsValidForSize (uval64, item_byte_size))
730 {
731 result.AppendErrorWithFormat ("Value 0x%llx is too large to fit in a %u byte unsigned integer value.\n", uval64, item_byte_size);
732 result.SetStatus(eReturnStatusFailed);
733 return false;
734 }
735 buffer.PutMaxHex64 (uval64, item_byte_size);
736 break;
737
738 case eFormatBoolean:
739 uval64 = Args::StringToBoolean(value_str, false, &success);
740 if (!success)
741 {
742 result.AppendErrorWithFormat ("'%s' is not a valid boolean string value.\n", value_str);
743 result.SetStatus(eReturnStatusFailed);
744 return false;
745 }
746 buffer.PutMaxHex64 (uval64, item_byte_size);
747 break;
748
749 case eFormatBinary:
750 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 2, &success);
751 if (!success)
752 {
753 result.AppendErrorWithFormat ("'%s' is not a valid binary string value.\n", value_str);
754 result.SetStatus(eReturnStatusFailed);
755 return false;
756 }
757 else if (!UIntValueIsValidForSize (uval64, item_byte_size))
758 {
759 result.AppendErrorWithFormat ("Value 0x%llx is too large to fit in a %u byte unsigned integer value.\n", uval64, item_byte_size);
760 result.SetStatus(eReturnStatusFailed);
761 return false;
762 }
763 buffer.PutMaxHex64 (uval64, item_byte_size);
764 break;
765
766 case eFormatChar:
767 case eFormatCString:
768 if (value_str[0])
769 {
770 size_t len = strlen (value_str);
771 // Include the NULL for C strings...
772 if (m_options.m_format == eFormatCString)
773 ++len;
774 Error error;
775 if (process->WriteMemory (addr, value_str, len, error) == len)
776 {
777 addr += len;
778 }
779 else
780 {
781 result.AppendErrorWithFormat ("Memory write to 0x%llx failed: %s.\n", addr, error.AsCString());
782 result.SetStatus(eReturnStatusFailed);
783 return false;
784 }
785 }
786 break;
787
788 case eFormatDecimal:
789 sval64 = Args::StringToSInt64(value_str, INT64_MAX, 0, &success);
790 if (!success)
791 {
792 result.AppendErrorWithFormat ("'%s' is not a valid signed decimal value.\n", value_str);
793 result.SetStatus(eReturnStatusFailed);
794 return false;
795 }
796 else if (!SIntValueIsValidForSize (sval64, item_byte_size))
797 {
798 result.AppendErrorWithFormat ("Value %lli is too large or small to fit in a %u byte signed integer value.\n", sval64, item_byte_size);
799 result.SetStatus(eReturnStatusFailed);
800 return false;
801 }
802 buffer.PutMaxHex64 (sval64, item_byte_size);
803 break;
804
805 case eFormatUnsigned:
806 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 0, &success);
807 if (!success)
808 {
809 result.AppendErrorWithFormat ("'%s' is not a valid unsigned decimal string value.\n", value_str);
810 result.SetStatus(eReturnStatusFailed);
811 return false;
812 }
813 else if (!UIntValueIsValidForSize (uval64, item_byte_size))
814 {
815 result.AppendErrorWithFormat ("Value %llu is too large to fit in a %u byte unsigned integer value.\n", uval64, item_byte_size);
816 result.SetStatus(eReturnStatusFailed);
817 return false;
818 }
819 buffer.PutMaxHex64 (uval64, item_byte_size);
820 break;
821
822 case eFormatOctal:
823 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 8, &success);
824 if (!success)
825 {
826 result.AppendErrorWithFormat ("'%s' is not a valid octal string value.\n", value_str);
827 result.SetStatus(eReturnStatusFailed);
828 return false;
829 }
830 else if (!UIntValueIsValidForSize (uval64, item_byte_size))
831 {
832 result.AppendErrorWithFormat ("Value %llo is too large to fit in a %u byte unsigned integer value.\n", uval64, item_byte_size);
833 result.SetStatus(eReturnStatusFailed);
834 return false;
835 }
836 buffer.PutMaxHex64 (uval64, item_byte_size);
837 break;
838 }
839 }
840
841 if (!buffer.GetString().empty())
842 {
843 Error error;
Greg Clayton53d68e72010-07-20 22:52:08 +0000844 if (process->WriteMemory (addr, buffer.GetString().c_str(), buffer.GetString().size(), error) == buffer.GetString().size())
Chris Lattner24943d22010-06-08 16:52:24 +0000845 return true;
846 else
847 {
848 result.AppendErrorWithFormat ("Memory write to 0x%llx failed: %s.\n", addr, error.AsCString());
849 result.SetStatus(eReturnStatusFailed);
850 return false;
851 }
852 }
853 return true;
854 }
855
856protected:
857 CommandOptions m_options;
858};
859
Greg Claytone9f5fbd2010-10-10 20:52:20 +0000860#define SET1 LLDB_OPT_SET_1
861#define SET2 LLDB_OPT_SET_2
862
Chris Lattner24943d22010-06-08 16:52:24 +0000863lldb::OptionDefinition
864CommandObjectMemoryWrite::CommandOptions::g_option_table[] =
865{
Greg Claytone9f5fbd2010-10-10 20:52:20 +0000866{ SET1 , false, "format", 'f', required_argument, NULL, 0, eArgTypeFormat, "The format value types that will be decoded and written to memory."},
867{ SET1 | SET2, false, "size", 's', required_argument, NULL, 0, eArgTypeByteSize, "The size in bytes of the values to write to memory."},
868{ SET2, true, "infile", 'i', required_argument, NULL, 0, eArgTypeFilename, "Write memory using the contents of a file."},
869{ SET2, false, "offset", 'o', required_argument, NULL, 0, eArgTypeOffset, "Start writng bytes from an offset within the input file."},
870{ 0 , false, NULL , 0 , 0 , NULL, 0, eArgTypeNone, NULL }
Chris Lattner24943d22010-06-08 16:52:24 +0000871};
872
Greg Claytone9f5fbd2010-10-10 20:52:20 +0000873#undef SET1
874#undef SET2
Chris Lattner24943d22010-06-08 16:52:24 +0000875
876//-------------------------------------------------------------------------
877// CommandObjectMemory
878//-------------------------------------------------------------------------
879
Greg Clayton63094e02010-06-23 01:19:29 +0000880CommandObjectMemory::CommandObjectMemory (CommandInterpreter &interpreter) :
Greg Clayton238c0a12010-09-18 01:14:36 +0000881 CommandObjectMultiword (interpreter,
882 "memory",
Caroline Ticec1ad82e2010-09-07 22:38:08 +0000883 "A set of commands for operating on memory.",
Chris Lattner24943d22010-06-08 16:52:24 +0000884 "memory <subcommand> [<subcommand-options>]")
885{
Greg Clayton238c0a12010-09-18 01:14:36 +0000886 LoadSubCommand ("read", CommandObjectSP (new CommandObjectMemoryRead (interpreter)));
887 LoadSubCommand ("write", CommandObjectSP (new CommandObjectMemoryWrite (interpreter)));
Chris Lattner24943d22010-06-08 16:52:24 +0000888}
889
890CommandObjectMemory::~CommandObjectMemory ()
891{
892}