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/Args.h"
17 #include "lldb/Core/DataBufferHeap.h"
18 #include "lldb/Core/DataExtractor.h"
19 #include "lldb/Core/Options.h"
20 #include "lldb/Core/StreamString.h"
21 #include "lldb/Interpreter/CommandReturnObject.h"
22 #include "lldb/Interpreter/CommandContext.h"
23 #include "lldb/Target/Process.h"
24 
25 using namespace lldb;
26 using namespace lldb_private;
27 
28 //----------------------------------------------------------------------
29 // Read memory from the inferior process
30 //----------------------------------------------------------------------
31 class CommandObjectMemoryRead : public CommandObject
32 {
33 public:
34 
35     class CommandOptions : public Options
36     {
37     public:
38         CommandOptions () :
39             Options()
40         {
41             ResetOptionValues();
42         }
43 
44         virtual
45         ~CommandOptions ()
46         {
47         }
48 
49         virtual Error
50         SetOptionValue (int option_idx, const char *option_arg)
51         {
52             Error error;
53             char short_option = (char) m_getopt_table[option_idx].val;
54 
55             switch (short_option)
56             {
57             case 'f':
58                 error = Args::StringToFormat (option_arg, m_format);
59 
60                 switch (m_format)
61                 {
62                 default:
63                     break;
64 
65                 case eFormatBoolean:
66                     if (m_byte_size == 0)
67                         m_byte_size = 1;
68                     if (m_num_per_line == 0)
69                         m_num_per_line = 1;
70                     break;
71 
72                 case eFormatCString:
73                     if (m_num_per_line == 0)
74                         m_num_per_line = 1;
75                     break;
76 
77                 case eFormatPointer:
78                     break;
79 
80                 case eFormatBinary:
81                 case eFormatFloat:
82                 case eFormatOctal:
83                 case eFormatDecimal:
84                 case eFormatEnum:
85                 case eFormatUnicode16:
86                 case eFormatUnicode32:
87                 case eFormatUnsigned:
88                     if (m_byte_size == 0)
89                         m_byte_size = 4;
90                     if (m_num_per_line == 0)
91                         m_num_per_line = 1;
92                     break;
93 
94                 case eFormatBytes:
95                 case eFormatBytesWithASCII:
96                 case eFormatChar:
97                 case eFormatCharPrintable:
98                     if (m_byte_size == 0)
99                         m_byte_size = 1;
100                     break;
101                 case eFormatComplex:
102                     if (m_byte_size == 0)
103                         m_byte_size = 8;
104                     break;
105                 case eFormatHex:
106                     if (m_byte_size == 0)
107                         m_byte_size = 4;
108                     break;
109 
110                 case eFormatVectorOfChar:
111                 case eFormatVectorOfSInt8:
112                 case eFormatVectorOfUInt8:
113                 case eFormatVectorOfSInt16:
114                 case eFormatVectorOfUInt16:
115                 case eFormatVectorOfSInt32:
116                 case eFormatVectorOfUInt32:
117                 case eFormatVectorOfSInt64:
118                 case eFormatVectorOfUInt64:
119                 case eFormatVectorOfFloat32:
120                 case eFormatVectorOfFloat64:
121                 case eFormatVectorOfUInt128:
122                     break;
123                 }
124                 break;
125 
126             case 'l':
127                 m_num_per_line = Args::StringToUInt32 (option_arg, 0);
128                 if (m_num_per_line == 0)
129                     error.SetErrorStringWithFormat("Invalid value for --num-per-line option '%s'. Must be positive integer value.\n", option_arg);
130                 break;
131 
132             case 'c':
133                 m_count = Args::StringToUInt32 (option_arg, 0);
134                 if (m_count == 0)
135                     error.SetErrorStringWithFormat("Invalid value for --count option '%s'. Must be positive integer value.\n", option_arg);
136                 break;
137 
138             case 's':
139                 m_byte_size = Args::StringToUInt32 (option_arg, 0);
140                 if (m_byte_size == 0)
141                     error.SetErrorStringWithFormat("Invalid value for --size option '%s'. Must be positive integer value.\n", option_arg);
142                 break;
143 
144             default:
145                 error.SetErrorStringWithFormat("Unrecognized short option '%c'.\n", short_option);
146                 break;
147             }
148             return error;
149         }
150 
151         void
152         ResetOptionValues ()
153         {
154             Options::ResetOptionValues();
155             m_format = eFormatBytesWithASCII;
156             m_byte_size = 0;
157             m_count = 0;
158             m_num_per_line = 0;
159         }
160 
161         const lldb::OptionDefinition*
162         GetDefinitions ()
163         {
164             return g_option_table;
165         }
166 
167         // Options table: Required for subclasses of Options.
168 
169         static lldb::OptionDefinition g_option_table[];
170 
171         // Instance variables to hold the values for command options.
172         lldb::Format m_format;
173         uint32_t m_byte_size;
174         uint32_t m_count;
175         uint32_t m_num_per_line;
176     };
177 
178     CommandObjectMemoryRead () :
179         CommandObject ("memory read",
180                        "Read memory from the process being debugged.",
181                        "memory read [<cmd-options>] <start-addr> [<end-addr>]",
182                        eFlagProcessMustBeLaunched)
183     {
184     }
185 
186     virtual
187     ~CommandObjectMemoryRead ()
188     {
189     }
190 
191     Options *
192     GetOptions ()
193     {
194         return &m_options;
195     }
196 
197     virtual bool
198     Execute (Args& command,
199              CommandContext *context,
200              CommandInterpreter *interpreter,
201              CommandReturnObject &result)
202     {
203         Process *process = context->GetExecutionContext().process;
204         if (process == NULL)
205         {
206             result.AppendError("need a process to read memory");
207             result.SetStatus(eReturnStatusFailed);
208             return false;
209         }
210         const size_t argc = command.GetArgumentCount();
211 
212         if (argc == 0 || argc > 2)
213         {
214             result.AppendErrorWithFormat ("%s takes 1 or two args.\n", m_cmd_name.c_str());
215             result.SetStatus(eReturnStatusFailed);
216             return false;
217         }
218 
219         size_t item_byte_size = m_options.m_byte_size;
220         if (item_byte_size == 0)
221         {
222             if (m_options.m_format == eFormatPointer)
223                 item_byte_size = process->GetAddressByteSize();
224             else
225                 item_byte_size = 1;
226         }
227 
228         size_t item_count = m_options.m_count;
229 
230         size_t num_per_line = m_options.m_num_per_line;
231         if (num_per_line == 0)
232         {
233             num_per_line = (16/item_byte_size);
234             if (num_per_line == 0)
235                 num_per_line = 1;
236         }
237 
238         size_t total_byte_size = m_options.m_count * item_byte_size;
239         if (total_byte_size == 0)
240             total_byte_size = 32;
241 
242         lldb::addr_t addr = Args::StringToUInt64(command.GetArgumentAtIndex(0), LLDB_INVALID_ADDRESS, 0);
243 
244         if (addr == LLDB_INVALID_ADDRESS)
245         {
246             result.AppendErrorWithFormat("invalid start address string '%s'.\n", command.GetArgumentAtIndex(0));
247             result.SetStatus(eReturnStatusFailed);
248             return false;
249         }
250 
251         if (argc == 2)
252         {
253             lldb::addr_t end_addr = Args::StringToUInt64(command.GetArgumentAtIndex(1), LLDB_INVALID_ADDRESS, 0);
254             if (end_addr == LLDB_INVALID_ADDRESS)
255             {
256                 result.AppendErrorWithFormat("Invalid end address string '%s'.\n", command.GetArgumentAtIndex(1));
257                 result.SetStatus(eReturnStatusFailed);
258                 return false;
259             }
260             else if (end_addr <= addr)
261             {
262                 result.AppendErrorWithFormat("End address (0x%llx) must be greater that the start address (0x%llx).\n", end_addr, addr);
263                 result.SetStatus(eReturnStatusFailed);
264                 return false;
265             }
266             else if (item_count != 0)
267             {
268                 result.AppendErrorWithFormat("Specify either the end address (0x%llx) or the count (--count %u), not both.\n", end_addr, item_count);
269                 result.SetStatus(eReturnStatusFailed);
270                 return false;
271             }
272 
273             total_byte_size = end_addr - addr;
274             item_count = total_byte_size / item_byte_size;
275         }
276         else
277         {
278             if (item_count == 0)
279                 item_count = 32;
280         }
281 
282         DataBufferSP data_sp(new DataBufferHeap (total_byte_size, '\0'));
283         Error error;
284         size_t bytes_read = process->ReadMemory(addr, data_sp->GetBytes (), data_sp->GetByteSize(), error);
285         if (bytes_read == 0)
286         {
287             result.AppendWarningWithFormat("Read from 0x%llx failed.\n", addr);
288             result.AppendError(error.AsCString());
289             result.SetStatus(eReturnStatusFailed);
290             return false;
291         }
292 
293         if (bytes_read < total_byte_size)
294             result.AppendWarningWithFormat("Not all bytes (%u/%u) were able to be read from 0x%llx.\n", bytes_read, total_byte_size, addr);
295 
296         result.SetStatus(eReturnStatusSuccessFinishResult);
297         DataExtractor data(data_sp, process->GetByteOrder(), process->GetAddressByteSize());
298 
299         Stream &output_stream = result.GetOutputStream();
300         data.Dump(&output_stream,
301                   0,
302                   m_options.m_format,
303                   item_byte_size,
304                   item_count,
305                   num_per_line,
306                   addr,
307                   0,
308                   0);
309         output_stream.EOL();
310         return true;
311     }
312 
313 protected:
314     CommandOptions m_options;
315 };
316 
317 lldb::OptionDefinition
318 CommandObjectMemoryRead::CommandOptions::g_option_table[] =
319 {
320     { 0, false, "format",       'f', required_argument, NULL, 0, "<format>",   "The format that will be used to display the memory. Defaults to bytes with ASCII (--format=Y)."},
321     { 0, false, "size",         's', required_argument, NULL, 0, "<byte-size>","The size in bytes to use when displaying with the selected format."},
322     { 0, false, "num-per-line", 'l', required_argument, NULL, 0, "<N>",        "The number of items per line to display."},
323     { 0, false, "count",        'c', required_argument, NULL, 0, "<N>",        "The number of total items to display."},
324     { 0, false, NULL, 0, 0, NULL, 0, NULL, NULL }
325 };
326 
327 
328 //----------------------------------------------------------------------
329 // Write memory to the inferior process
330 //----------------------------------------------------------------------
331 class CommandObjectMemoryWrite : public CommandObject
332 {
333 public:
334 
335     class CommandOptions : public Options
336     {
337     public:
338         CommandOptions () :
339             Options()
340         {
341             ResetOptionValues();
342         }
343 
344         virtual
345         ~CommandOptions ()
346         {
347         }
348 
349         virtual Error
350         SetOptionValue (int option_idx, const char *option_arg)
351         {
352             Error error;
353             char short_option = (char) m_getopt_table[option_idx].val;
354             switch (short_option)
355             {
356             case 'f':
357                 error = Args::StringToFormat (option_arg, m_format);
358                 break;
359 
360             case 's':
361                 m_byte_size = Args::StringToUInt32 (option_arg, 0);
362                 if (m_byte_size == 0)
363                     error.SetErrorStringWithFormat("Invalid value for --size option '%s'.  Must be positive integer value.\n", option_arg);
364                 break;
365 
366 
367             default:
368                 error.SetErrorStringWithFormat("Unrecognized short option '%c'\n", short_option);
369                 break;
370             }
371             return error;
372         }
373 
374         void
375         ResetOptionValues ()
376         {
377             Options::ResetOptionValues();
378             m_format = eFormatBytes;
379             m_byte_size = 1;
380         }
381 
382         const lldb::OptionDefinition*
383         GetDefinitions ()
384         {
385             return g_option_table;
386         }
387 
388         // Options table: Required for subclasses of Options.
389 
390         static lldb::OptionDefinition g_option_table[];
391 
392         // Instance variables to hold the values for command options.
393         lldb::Format m_format;
394         uint32_t m_byte_size;
395     };
396 
397     CommandObjectMemoryWrite () :
398         CommandObject ("memory write",
399                        "Write memory to the process being debugged.",
400                        "memory write [<cmd-options>] <addr> [value1 value2 ...]",
401                        eFlagProcessMustBeLaunched)
402     {
403     }
404 
405     virtual
406     ~CommandObjectMemoryWrite ()
407     {
408     }
409 
410     Options *
411     GetOptions ()
412     {
413         return &m_options;
414     }
415 
416     bool
417     UIntValueIsValidForSize (uint64_t uval64, size_t total_byte_size)
418     {
419         if (total_byte_size > 8)
420             return false;
421 
422         if (total_byte_size == 8)
423             return true;
424 
425         const uint64_t max = ((uint64_t)1 << (uint64_t)(total_byte_size * 8)) - 1;
426         return uval64 <= max;
427     }
428 
429     bool
430     SIntValueIsValidForSize (int64_t sval64, size_t total_byte_size)
431     {
432         if (total_byte_size > 8)
433             return false;
434 
435         if (total_byte_size == 8)
436             return true;
437 
438         const int64_t max = ((int64_t)1 << (uint64_t)(total_byte_size * 8 - 1)) - 1;
439         const int64_t min = ~(max);
440         return min <= sval64 && sval64 <= max;
441     }
442 
443     virtual bool
444     Execute (Args& command,
445              CommandContext *context,
446              CommandInterpreter *interpreter,
447              CommandReturnObject &result)
448     {
449         Process *process = context->GetExecutionContext().process;
450         if (process == NULL)
451         {
452             result.AppendError("need a process to read memory");
453             result.SetStatus(eReturnStatusFailed);
454             return false;
455         }
456 
457         const size_t argc = command.GetArgumentCount();
458 
459         if (argc < 2)
460         {
461             result.AppendErrorWithFormat ("%s takes an address and at least one value.\n", m_cmd_name.c_str());
462             result.SetStatus(eReturnStatusFailed);
463             return false;
464         }
465 
466         size_t item_byte_size = m_options.m_byte_size ? m_options.m_byte_size : 1;
467         StreamString buffer (Stream::eBinary,
468                              process->GetAddressByteSize(),
469                              process->GetByteOrder());
470 
471         lldb::addr_t addr = Args::StringToUInt64(command.GetArgumentAtIndex(0), LLDB_INVALID_ADDRESS, 0);
472 
473         if (addr == LLDB_INVALID_ADDRESS)
474         {
475             result.AppendErrorWithFormat("Invalid address string '%s'.\n", command.GetArgumentAtIndex(0));
476             result.SetStatus(eReturnStatusFailed);
477             return false;
478         }
479         command.Shift(); // shift off the address argument
480         uint64_t uval64;
481         int64_t sval64;
482         bool success = false;
483         const uint32_t num_value_args = command.GetArgumentCount();
484         uint32_t i;
485         for (i=0; i<num_value_args; ++i)
486         {
487             const char *value_str = command.GetArgumentAtIndex(i);
488 
489             switch (m_options.m_format)
490             {
491             case eFormatFloat:  // TODO: add support for floats soon
492             case eFormatCharPrintable:
493             case eFormatBytesWithASCII:
494             case eFormatComplex:
495             case eFormatEnum:
496             case eFormatUnicode16:
497             case eFormatUnicode32:
498             case eFormatVectorOfChar:
499             case eFormatVectorOfSInt8:
500             case eFormatVectorOfUInt8:
501             case eFormatVectorOfSInt16:
502             case eFormatVectorOfUInt16:
503             case eFormatVectorOfSInt32:
504             case eFormatVectorOfUInt32:
505             case eFormatVectorOfSInt64:
506             case eFormatVectorOfUInt64:
507             case eFormatVectorOfFloat32:
508             case eFormatVectorOfFloat64:
509             case eFormatVectorOfUInt128:
510                 result.AppendError("unsupported format for writing memory");
511                 result.SetStatus(eReturnStatusFailed);
512                 return false;
513 
514             case eFormatDefault:
515             case eFormatBytes:
516             case eFormatHex:
517                 // Decode hex bytes
518                 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 16, &success);
519                 if (!success)
520                 {
521                     result.AppendErrorWithFormat ("'%s' is not a valid hex string value.\n", value_str);
522                     result.SetStatus(eReturnStatusFailed);
523                     return false;
524                 }
525                 else if (!UIntValueIsValidForSize (uval64, item_byte_size))
526                 {
527                     result.AppendErrorWithFormat ("Value 0x%llx is too large to fit in a %u byte unsigned integer value.\n", uval64, item_byte_size);
528                     result.SetStatus(eReturnStatusFailed);
529                     return false;
530                 }
531                 buffer.PutMaxHex64 (uval64, item_byte_size);
532                 break;
533 
534             case eFormatBoolean:
535                 uval64 = Args::StringToBoolean(value_str, false, &success);
536                 if (!success)
537                 {
538                     result.AppendErrorWithFormat ("'%s' is not a valid boolean string value.\n", value_str);
539                     result.SetStatus(eReturnStatusFailed);
540                     return false;
541                 }
542                 buffer.PutMaxHex64 (uval64, item_byte_size);
543                 break;
544 
545             case eFormatBinary:
546                 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 2, &success);
547                 if (!success)
548                 {
549                     result.AppendErrorWithFormat ("'%s' is not a valid binary string value.\n", value_str);
550                     result.SetStatus(eReturnStatusFailed);
551                     return false;
552                 }
553                 else if (!UIntValueIsValidForSize (uval64, item_byte_size))
554                 {
555                     result.AppendErrorWithFormat ("Value 0x%llx is too large to fit in a %u byte unsigned integer value.\n", uval64, item_byte_size);
556                     result.SetStatus(eReturnStatusFailed);
557                     return false;
558                 }
559                 buffer.PutMaxHex64 (uval64, item_byte_size);
560                 break;
561 
562             case eFormatChar:
563             case eFormatCString:
564                 if (value_str[0])
565                 {
566                     size_t len = strlen (value_str);
567                     // Include the NULL for C strings...
568                     if (m_options.m_format == eFormatCString)
569                         ++len;
570                     Error error;
571                     if (process->WriteMemory (addr, value_str, len, error) == len)
572                     {
573                         addr += len;
574                     }
575                     else
576                     {
577                         result.AppendErrorWithFormat ("Memory write to 0x%llx failed: %s.\n", addr, error.AsCString());
578                         result.SetStatus(eReturnStatusFailed);
579                         return false;
580                     }
581                 }
582                 break;
583 
584             case eFormatDecimal:
585                 sval64 = Args::StringToSInt64(value_str, INT64_MAX, 0, &success);
586                 if (!success)
587                 {
588                     result.AppendErrorWithFormat ("'%s' is not a valid signed decimal value.\n", value_str);
589                     result.SetStatus(eReturnStatusFailed);
590                     return false;
591                 }
592                 else if (!SIntValueIsValidForSize (sval64, item_byte_size))
593                 {
594                     result.AppendErrorWithFormat ("Value %lli is too large or small to fit in a %u byte signed integer value.\n", sval64, item_byte_size);
595                     result.SetStatus(eReturnStatusFailed);
596                     return false;
597                 }
598                 buffer.PutMaxHex64 (sval64, item_byte_size);
599                 break;
600 
601             case eFormatUnsigned:
602                 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 0, &success);
603                 if (!success)
604                 {
605                     result.AppendErrorWithFormat ("'%s' is not a valid unsigned decimal string value.\n", value_str);
606                     result.SetStatus(eReturnStatusFailed);
607                     return false;
608                 }
609                 else if (!UIntValueIsValidForSize (uval64, item_byte_size))
610                 {
611                     result.AppendErrorWithFormat ("Value %llu is too large to fit in a %u byte unsigned integer value.\n", uval64, item_byte_size);
612                     result.SetStatus(eReturnStatusFailed);
613                     return false;
614                 }
615                 buffer.PutMaxHex64 (uval64, item_byte_size);
616                 break;
617 
618             case eFormatOctal:
619                 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 8, &success);
620                 if (!success)
621                 {
622                     result.AppendErrorWithFormat ("'%s' is not a valid octal string value.\n", value_str);
623                     result.SetStatus(eReturnStatusFailed);
624                     return false;
625                 }
626                 else if (!UIntValueIsValidForSize (uval64, item_byte_size))
627                 {
628                     result.AppendErrorWithFormat ("Value %llo is too large to fit in a %u byte unsigned integer value.\n", uval64, item_byte_size);
629                     result.SetStatus(eReturnStatusFailed);
630                     return false;
631                 }
632                 buffer.PutMaxHex64 (uval64, item_byte_size);
633                 break;
634             }
635         }
636 
637         if (!buffer.GetString().empty())
638         {
639             Error error;
640             if (process->WriteMemory (addr, buffer.GetString().data(), buffer.GetString().size(), error) == buffer.GetString().size())
641                 return true;
642             else
643             {
644                 result.AppendErrorWithFormat ("Memory write to 0x%llx failed: %s.\n", addr, error.AsCString());
645                 result.SetStatus(eReturnStatusFailed);
646                 return false;
647             }
648         }
649         return true;
650     }
651 
652 protected:
653     CommandOptions m_options;
654 };
655 
656 lldb::OptionDefinition
657 CommandObjectMemoryWrite::CommandOptions::g_option_table[] =
658 {
659     { 0, false, "format", 'f', required_argument, NULL, 0, "<format>",   "The format value types that will be decoded and written to memory."},
660     { 0, false, "size",   's', required_argument, NULL, 0, "<byte-size>","The size in bytes of the values to write to memory."},
661     { 0, false, NULL, 0, 0, NULL, 0, NULL, NULL }
662 };
663 
664 
665 //-------------------------------------------------------------------------
666 // CommandObjectMemory
667 //-------------------------------------------------------------------------
668 
669 CommandObjectMemory::CommandObjectMemory (CommandInterpreter *interpreter) :
670     CommandObjectMultiword ("memory",
671                             "A set of commands for operating on a memory.",
672                             "memory <subcommand> [<subcommand-options>]")
673 {
674     LoadSubCommand (CommandObjectSP (new CommandObjectMemoryRead ()), "read", interpreter);
675     LoadSubCommand (CommandObjectSP (new CommandObjectMemoryWrite ()), "write", interpreter);
676 }
677 
678 CommandObjectMemory::~CommandObjectMemory ()
679 {
680 }
681