1 //===-- 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
16 #include "lldb/Core/DataBufferHeap.h"
17 #include "lldb/Core/DataExtractor.h"
18 #include "lldb/Core/Debugger.h"
19 #include "lldb/Core/StreamString.h"
20 #include "lldb/Interpreter/Args.h"
21 #include "lldb/Interpreter/CommandReturnObject.h"
22 #include "lldb/Interpreter/CommandInterpreter.h"
23 #include "lldb/Interpreter/Options.h"
24 #include "lldb/Target/Process.h"
25 
26 using namespace lldb;
27 using namespace lldb_private;
28 
29 //----------------------------------------------------------------------
30 // Read memory from the inferior process
31 //----------------------------------------------------------------------
32 class CommandObjectMemoryRead : public CommandObject
33 {
34 public:
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 
145             case 'o':
146                 m_outfile_filespec.SetFile (option_arg, true);
147                 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 
157             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;
172             m_outfile_filespec.Clear();
173             m_append_to_outfile = false;
174             m_output_as_binary = false;
175         }
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;
192         FileSpec m_outfile_filespec;
193         bool m_append_to_outfile;
194         bool m_output_as_binary;
195     };
196 
197     CommandObjectMemoryRead (CommandInterpreter &interpreter) :
198         CommandObject (interpreter,
199                        "memory read",
200                        "Read from the memory of the process being debugged.",
201                        NULL,
202                        eFlagProcessMustBeLaunched)
203     {
204         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);
226     }
227 
228     virtual
229     ~CommandObjectMemoryRead ()
230     {
231     }
232 
233     Options *
234     GetOptions ()
235     {
236         return &m_options;
237     }
238 
239     virtual bool
240     Execute (Args& command,
241              CommandReturnObject &result)
242     {
243         Process *process = m_interpreter.GetDebugger().GetExecutionContext().process;
244         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 
339         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();
400         return true;
401     }
402 
403 protected:
404     CommandOptions m_options;
405 };
406 
407 #define SET1 LLDB_OPT_SET_1
408 #define SET2 LLDB_OPT_SET_2
409 
410 lldb::OptionDefinition
411 CommandObjectMemoryRead::CommandOptions::g_option_table[] =
412 {
413 { 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 }
421 };
422 
423 #undef SET1
424 #undef SET2
425 
426 //----------------------------------------------------------------------
427 // Write memory to the inferior process
428 //----------------------------------------------------------------------
429 class CommandObjectMemoryWrite : public CommandObject
430 {
431 public:
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 
464             case 'i':
465                 m_infile.SetFile (option_arg, true);
466                 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;
483 
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;
497             m_infile.Clear();
498             m_infile_offset = 0;
499         }
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;
514         FileSpec m_infile;
515         off_t m_infile_offset;
516     };
517 
518     CommandObjectMemoryWrite (CommandInterpreter &interpreter) :
519         CommandObject (interpreter,
520                        "memory write",
521                        "Write to the memory of the process being debugged.",
522                        //"memory write [<cmd-options>] <addr> [value1 value2 ...]",
523                        NULL,
524                        eFlagProcessMustBeLaunched)
525     {
526         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);
548     }
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
589     Execute (Args& command,
590              CommandReturnObject &result)
591     {
592         Process *process = m_interpreter.GetDebugger().GetExecutionContext().process;
593         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 
602         if (m_options.m_infile)
603         {
604             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());
614             result.SetStatus(eReturnStatusFailed);
615             return false;
616         }
617 
618         StreamString buffer (Stream::eBinary,
619                              process->GetAddressByteSize(),
620                              process->GetByteOrder());
621 
622         size_t item_byte_size = m_options.m_byte_size;
623 
624         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         }
632 
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 
681         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:
719             case eFormatPointer:
720 
721                 // 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;
844             if (process->WriteMemory (addr, buffer.GetString().c_str(), buffer.GetString().size(), error) == buffer.GetString().size())
845                 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 
856 protected:
857     CommandOptions m_options;
858 };
859 
860 #define SET1 LLDB_OPT_SET_1
861 #define SET2 LLDB_OPT_SET_2
862 
863 lldb::OptionDefinition
864 CommandObjectMemoryWrite::CommandOptions::g_option_table[] =
865 {
866 { 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 }
871 };
872 
873 #undef SET1
874 #undef SET2
875 
876 //-------------------------------------------------------------------------
877 // CommandObjectMemory
878 //-------------------------------------------------------------------------
879 
880 CommandObjectMemory::CommandObjectMemory (CommandInterpreter &interpreter) :
881     CommandObjectMultiword (interpreter,
882                             "memory",
883                             "A set of commands for operating on memory.",
884                             "memory <subcommand> [<subcommand-options>]")
885 {
886     LoadSubCommand ("read",  CommandObjectSP (new CommandObjectMemoryRead (interpreter)));
887     LoadSubCommand ("write", CommandObjectSP (new CommandObjectMemoryWrite (interpreter)));
888 }
889 
890 CommandObjectMemory::~CommandObjectMemory ()
891 {
892 }
893