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/Core/ValueObjectMemory.h"
21 #include "lldb/Interpreter/Args.h"
22 #include "lldb/Interpreter/CommandReturnObject.h"
23 #include "lldb/Interpreter/CommandInterpreter.h"
24 #include "lldb/Interpreter/Options.h"
25 #include "lldb/Interpreter/OptionGroupFormat.h"
26 #include "lldb/Interpreter/OptionGroupOutputFile.h"
27 #include "lldb/Interpreter/OptionGroupValueObjectDisplay.h"
28 #include "lldb/Target/Process.h"
29 #include "lldb/Target/StackFrame.h"
30 
31 using namespace lldb;
32 using namespace lldb_private;
33 
34 static OptionDefinition
35 g_option_table[] =
36 {
37     { LLDB_OPT_SET_1|
38       LLDB_OPT_SET_2, false, "size"         ,'s', required_argument, NULL, 0, eArgTypeByteSize      ,"The size in bytes to use when displaying with the selected format."},
39     { LLDB_OPT_SET_1|
40       LLDB_OPT_SET_3, false, "count"        ,'c', required_argument, NULL, 0, eArgTypeCount         ,"The number of total items to display."},
41     { LLDB_OPT_SET_1, false, "num-per-line" ,'l', required_argument, NULL, 0, eArgTypeNumberPerLine ,"The number of items per line to display."},
42     { 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."},
43     { LLDB_OPT_SET_3, true , "view-as"      ,'t', required_argument, NULL, 0, eArgTypeNone          ,"The name of a type to view memory as."},
44 };
45 
46 
47 
48 class OptionGroupReadMemory : public OptionGroup
49 {
50 public:
51 
52     OptionGroupReadMemory () :
53         m_byte_size (1,1),
54         m_count (8,8),
55         m_num_per_line (1,1),
56         m_output_as_binary (false),
57         m_view_as_type()
58     {
59     }
60 
61     virtual
62     ~OptionGroupReadMemory ()
63     {
64     }
65 
66 
67     virtual uint32_t
68     GetNumDefinitions ()
69     {
70         return sizeof (g_option_table) / sizeof (OptionDefinition);
71     }
72 
73     virtual const OptionDefinition*
74     GetDefinitions ()
75     {
76         return g_option_table;
77     }
78 
79     virtual Error
80     SetOptionValue (CommandInterpreter &interpreter,
81                     uint32_t option_idx,
82                     const char *option_arg)
83     {
84         Error error;
85         char short_option = (char) g_option_table[option_idx].short_option;
86 
87         switch (short_option)
88         {
89             case 'l':
90                 error = m_num_per_line.SetValueFromCString (option_arg);
91                 if (m_num_per_line.GetCurrentValue() == 0)
92                     error.SetErrorStringWithFormat("Invalid value for --num-per-line option '%s'. Must be positive integer value.\n", option_arg);
93                 break;
94 
95             case 'c':
96                 error = m_count.SetValueFromCString (option_arg);
97                 if (m_count.GetCurrentValue() == 0)
98                     error.SetErrorStringWithFormat("Invalid value for --count option '%s'. Must be positive integer value.\n", option_arg);
99                 break;
100 
101             case 's':
102                 error = m_byte_size.SetValueFromCString (option_arg);
103                 if (m_byte_size.GetCurrentValue() == 0)
104                     error.SetErrorStringWithFormat("Invalid value for --size option '%s'. Must be positive integer value.\n", option_arg);
105                 break;
106 
107             case 'b':
108                 m_output_as_binary = true;
109                 break;
110 
111             case 't':
112                 error = m_view_as_type.SetValueFromCString (option_arg);
113                 break;
114 
115             default:
116                 error.SetErrorStringWithFormat("Unrecognized short option '%c'.\n", short_option);
117                 break;
118         }
119         return error;
120     }
121 
122     virtual void
123     OptionParsingStarting (CommandInterpreter &interpreter)
124     {
125         m_byte_size.Clear();
126         m_count.Clear();
127         m_num_per_line.Clear();
128         m_output_as_binary = false;
129         m_view_as_type.Clear();
130     }
131 
132     Error
133     FinalizeSettings (Target *target, const OptionGroupFormat& format_options)
134     {
135         Error error;
136         bool byte_size_option_set = m_byte_size.OptionWasSet();
137         const bool num_per_line_option_set = m_num_per_line.OptionWasSet();
138         const bool count_option_set = m_count.OptionWasSet();
139 
140         uint32_t format_byte_size = format_options.GetByteSize();
141         if (byte_size_option_set)
142         {
143             if (format_byte_size > 0)
144             {
145                 error.SetErrorString("can't specify the byte size in both the '--size <num>' option and the '--format [<byte-size>]<format-char>' options.");
146                 return error;
147             }
148         }
149         else
150         {
151             if (format_byte_size != 0)
152             {
153                 byte_size_option_set = true;
154                 m_byte_size = format_byte_size;
155             }
156         }
157 
158         switch (format_options.GetFormat())
159         {
160             default:
161                 break;
162 
163             case eFormatBoolean:
164                 if (!byte_size_option_set)
165                     m_byte_size = 1;
166                 if (!num_per_line_option_set)
167                     m_num_per_line = 1;
168                 if (!count_option_set)
169                     m_count = 8;
170                 break;
171 
172             case eFormatCString:
173                 break;
174 
175             case eFormatPointer:
176                 m_byte_size = target->GetArchitecture().GetAddressByteSize();
177                 if (!num_per_line_option_set)
178                     m_num_per_line = 4;
179                 if (!count_option_set)
180                     m_count = 8;
181                 break;
182 
183             case eFormatBinary:
184             case eFormatFloat:
185             case eFormatOctal:
186             case eFormatDecimal:
187             case eFormatEnum:
188             case eFormatUnicode16:
189             case eFormatUnicode32:
190             case eFormatUnsigned:
191                 if (!byte_size_option_set)
192                     m_byte_size = 4;
193                 if (!num_per_line_option_set)
194                     m_num_per_line = 1;
195                 if (!count_option_set)
196                     m_count = 8;
197                 break;
198 
199             case eFormatBytes:
200             case eFormatBytesWithASCII:
201                 if (m_byte_size.OptionWasSet())
202                 {
203                     if (m_byte_size > 1)
204                         error.SetErrorString ("use --count option to specify an end address to display a number of bytes");
205                 }
206                 else
207                     m_byte_size = 1;
208                 if (!num_per_line_option_set)
209                     m_num_per_line = 16;
210                 if (!count_option_set)
211                     m_count = 32;
212                 break;
213             case eFormatCharArray:
214             case eFormatChar:
215             case eFormatCharPrintable:
216                 if (!byte_size_option_set)
217                     m_byte_size = 1;
218                 if (!num_per_line_option_set)
219                     m_num_per_line = 32;
220                 if (!count_option_set)
221                     m_count = 64;
222                 break;
223             case eFormatComplex:
224                 if (!byte_size_option_set)
225                     m_byte_size = 8;
226                 if (!num_per_line_option_set)
227                     m_num_per_line = 1;
228                 if (!count_option_set)
229                     m_count = 8;
230                 break;
231             case eFormatHex:
232                 if (!byte_size_option_set)
233                     m_byte_size = 4;
234                 if (!num_per_line_option_set)
235                 {
236                     switch (m_byte_size)
237                     {
238                         case 1:
239                         case 2:
240                             m_num_per_line = 8;
241                             break;
242                         case 4:
243                             m_num_per_line = 4;
244                             break;
245                         case 8:
246                             m_num_per_line = 2;
247                             break;
248                         default:
249                             m_num_per_line = 1;
250                             break;
251                     }
252                 }
253                 if (!count_option_set)
254                     m_count = 8;
255                 break;
256 
257             case eFormatVectorOfChar:
258             case eFormatVectorOfSInt8:
259             case eFormatVectorOfUInt8:
260             case eFormatVectorOfSInt16:
261             case eFormatVectorOfUInt16:
262             case eFormatVectorOfSInt32:
263             case eFormatVectorOfUInt32:
264             case eFormatVectorOfSInt64:
265             case eFormatVectorOfUInt64:
266             case eFormatVectorOfFloat32:
267             case eFormatVectorOfFloat64:
268             case eFormatVectorOfUInt128:
269                 if (!byte_size_option_set)
270                     m_byte_size = 128;
271                 if (!num_per_line_option_set)
272                     m_num_per_line = 1;
273                 if (!count_option_set)
274                     m_count = 4;
275                 break;
276         }
277         return error;
278     }
279 
280     OptionValueUInt64 m_byte_size;
281     OptionValueUInt64 m_count;
282     OptionValueUInt64 m_num_per_line;
283     bool m_output_as_binary;
284     OptionValueString m_view_as_type;
285 };
286 
287 
288 
289 //----------------------------------------------------------------------
290 // Read memory from the inferior process
291 //----------------------------------------------------------------------
292 class CommandObjectMemoryRead : public CommandObject
293 {
294 public:
295 
296     CommandObjectMemoryRead (CommandInterpreter &interpreter) :
297         CommandObject (interpreter,
298                        "memory read",
299                        "Read from the memory of the process being debugged.",
300                        NULL,
301                        eFlagProcessMustBePaused),
302         m_option_group (interpreter),
303         m_format_options (eFormatBytesWithASCII, 0, true),
304         m_memory_options (),
305         m_outfile_options (),
306         m_varobj_options()
307     {
308         CommandArgumentEntry arg1;
309         CommandArgumentEntry arg2;
310         CommandArgumentData start_addr_arg;
311         CommandArgumentData end_addr_arg;
312 
313         // Define the first (and only) variant of this arg.
314         start_addr_arg.arg_type = eArgTypeStartAddress;
315         start_addr_arg.arg_repetition = eArgRepeatPlain;
316 
317         // There is only one variant this argument could be; put it into the argument entry.
318         arg1.push_back (start_addr_arg);
319 
320         // Define the first (and only) variant of this arg.
321         end_addr_arg.arg_type = eArgTypeEndAddress;
322         end_addr_arg.arg_repetition = eArgRepeatOptional;
323 
324         // There is only one variant this argument could be; put it into the argument entry.
325         arg2.push_back (end_addr_arg);
326 
327         // Push the data for the first argument into the m_arguments vector.
328         m_arguments.push_back (arg1);
329         m_arguments.push_back (arg2);
330 
331         m_option_group.Append (&m_format_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1 | LLDB_OPT_SET_3);
332         m_option_group.Append (&m_memory_options);
333         m_option_group.Append (&m_outfile_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1 | LLDB_OPT_SET_2 | LLDB_OPT_SET_3);
334         m_option_group.Append (&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_3);
335         m_option_group.Finalize();
336     }
337 
338     virtual
339     ~CommandObjectMemoryRead ()
340     {
341     }
342 
343     Options *
344     GetOptions ()
345     {
346         return &m_option_group;
347     }
348 
349     virtual bool
350     Execute (Args& command,
351              CommandReturnObject &result)
352     {
353         ExecutionContext exe_ctx (m_interpreter.GetExecutionContext());
354         if (exe_ctx.target == NULL)
355         {
356             result.AppendError("need at least a target to read memory");
357             result.SetStatus(eReturnStatusFailed);
358             return false;
359         }
360         const size_t argc = command.GetArgumentCount();
361 
362 
363         if (argc == 0 || argc > 2)
364         {
365             result.AppendErrorWithFormat ("%s takes 1 or two args.\n", m_cmd_name.c_str());
366             result.SetStatus(eReturnStatusFailed);
367             return false;
368         }
369 
370         ClangASTType clang_ast_type;
371         Error error;
372 
373         Format format = m_format_options.GetFormat();
374         const char *view_as_type_cstr = m_memory_options.m_view_as_type.GetCurrentValue();
375         if (view_as_type_cstr && view_as_type_cstr[0])
376         {
377             // We are viewing memory as a type
378             SymbolContext sc;
379             const bool append = true;
380             TypeList type_list;
381             uint32_t reference_count = 0;
382             uint32_t pointer_count = 0;
383             size_t idx;
384             static const char *g_keywords[] = { "const", "volatile", "restrict", "struct", "class", "union"};
385             static size_t g_num_keywords = sizeof(g_keywords)/sizeof(const char *);
386             std::string type_str(view_as_type_cstr);
387 
388             // Remove all instances of g_keywords that are followed by spaces
389             for (size_t i = 0; i < g_num_keywords; ++i)
390             {
391                 const char *keyword = g_keywords[i];
392                 int keyword_len = ::strlen (keyword);
393                 while ((idx = type_str.find (keyword)) != std::string::npos)
394                 {
395                     if (type_str[idx + keyword_len] == ' ' || type_str[idx + keyword_len] == '\t')
396                         type_str.erase(idx, keyword_len+1);
397                 }
398             }
399             bool done = type_str.empty();
400             //
401             idx = type_str.find_first_not_of (" \t");
402             if (idx > 0 && idx != std::string::npos)
403                 type_str.erase (0, idx);
404             while (!done)
405             {
406                 // Strip trailing spaces
407                 if (type_str.empty())
408                     done = true;
409                 else
410                 {
411                     switch (type_str[type_str.size()-1])
412                     {
413                     case '*':
414                         ++pointer_count;
415                         // fall through...
416                     case ' ':
417                     case '\t':
418                         type_str.erase(type_str.size()-1);
419                         break;
420 
421                     case '&':
422                         if (reference_count == 0)
423                         {
424                             reference_count = 1;
425                             type_str.erase(type_str.size()-1);
426                         }
427                         else
428                         {
429                             result.AppendErrorWithFormat ("invalid type string: '%s'\n", view_as_type_cstr);
430                             result.SetStatus(eReturnStatusFailed);
431                             return false;
432                         }
433                         break;
434 
435                     default:
436                         done = true;
437                         break;
438                     }
439                 }
440             }
441 
442             ConstString lookup_type_name(type_str.c_str());
443             if (exe_ctx.frame)
444             {
445                 sc = exe_ctx.frame->GetSymbolContext (eSymbolContextModule);
446                 if (sc.module_sp)
447                 {
448                     sc.module_sp->FindTypes (sc,
449                                              lookup_type_name,
450                                              append,
451                                              1,
452                                              type_list);
453                 }
454             }
455             if (type_list.GetSize() == 0)
456             {
457                 exe_ctx.target->GetImages().FindTypes (sc,
458                                                        lookup_type_name,
459                                                        append,
460                                                        1,
461                                                        type_list);
462             }
463 
464             if (type_list.GetSize() == 0)
465             {
466                 result.AppendErrorWithFormat ("unable to find any types that match the raw type '%s' for full type '%s'\n",
467                                               lookup_type_name.GetCString(),
468                                               view_as_type_cstr);
469                 result.SetStatus(eReturnStatusFailed);
470                 return false;
471             }
472 
473             TypeSP type_sp (type_list.GetTypeAtIndex(0));
474             clang_ast_type.SetClangType (type_sp->GetClangAST(), type_sp->GetClangFullType());
475 
476             while (pointer_count > 0)
477             {
478                 clang_type_t pointer_type = ClangASTContext::CreatePointerType (clang_ast_type.GetASTContext(), clang_ast_type.GetOpaqueQualType());
479                 if (pointer_type)
480                     clang_ast_type.SetClangType (clang_ast_type.GetASTContext(), pointer_type);
481                 else
482                 {
483                     result.AppendError ("unable make a pointer type\n");
484                     result.SetStatus(eReturnStatusFailed);
485                     return false;
486                 }
487                 --pointer_count;
488             }
489 
490             m_memory_options.m_byte_size = (clang_ast_type.GetClangTypeBitWidth () + 7) / 8;
491 
492             if (m_memory_options.m_byte_size == 0)
493             {
494                 result.AppendErrorWithFormat ("unable to get the byte size of the type '%s'\n",
495                                               view_as_type_cstr);
496                 result.SetStatus(eReturnStatusFailed);
497                 return false;
498             }
499 
500             if (!m_memory_options.m_count.OptionWasSet())
501                 m_memory_options.m_count = 1;
502         }
503         else
504         {
505             error = m_memory_options.FinalizeSettings (exe_ctx.target, m_format_options);
506         }
507 
508         // Look for invalid combinations of settings
509         if (error.Fail())
510         {
511             result.AppendErrorWithFormat("%s", error.AsCString());
512             result.SetStatus(eReturnStatusFailed);
513             return false;
514         }
515 
516         size_t item_count = m_memory_options.m_count.GetCurrentValue();
517         const size_t item_byte_size = m_memory_options.m_byte_size;
518         const size_t num_per_line = m_memory_options.m_num_per_line.GetCurrentValue();
519 
520         size_t total_byte_size = item_count * item_byte_size;
521         if (total_byte_size == 0)
522             total_byte_size = 32;
523 
524         lldb::addr_t addr = Args::StringToUInt64(command.GetArgumentAtIndex(0), LLDB_INVALID_ADDRESS, 0);
525 
526         if (addr == LLDB_INVALID_ADDRESS)
527         {
528             result.AppendErrorWithFormat("invalid start address string '%s'.\n", command.GetArgumentAtIndex(0));
529             result.SetStatus(eReturnStatusFailed);
530             return false;
531         }
532 
533         if (argc == 2)
534         {
535             lldb::addr_t end_addr = Args::StringToUInt64(command.GetArgumentAtIndex(1), LLDB_INVALID_ADDRESS, 0);
536             if (end_addr == LLDB_INVALID_ADDRESS)
537             {
538                 result.AppendErrorWithFormat("invalid end address string '%s'.\n", command.GetArgumentAtIndex(1));
539                 result.SetStatus(eReturnStatusFailed);
540                 return false;
541             }
542             else if (end_addr <= addr)
543             {
544                 result.AppendErrorWithFormat("end address (0x%llx) must be greater that the start address (0x%llx).\n", end_addr, addr);
545                 result.SetStatus(eReturnStatusFailed);
546                 return false;
547             }
548             else if (m_memory_options.m_count.OptionWasSet())
549             {
550                 result.AppendErrorWithFormat("specify either the end address (0x%llx) or the count (--count %u), not both.\n", end_addr, item_count);
551                 result.SetStatus(eReturnStatusFailed);
552                 return false;
553             }
554 
555             total_byte_size = end_addr - addr;
556             item_count = total_byte_size / item_byte_size;
557         }
558 
559         DataBufferSP data_sp;
560         size_t bytes_read = 0;
561         if (!clang_ast_type.GetOpaqueQualType())
562         {
563             data_sp.reset (new DataBufferHeap (total_byte_size, '\0'));
564             Address address(NULL, addr);
565             bytes_read = exe_ctx.target->ReadMemory(address, false, data_sp->GetBytes (), data_sp->GetByteSize(), error);
566             if (bytes_read == 0)
567             {
568                 result.AppendWarningWithFormat("Read from 0x%llx failed.\n", addr);
569                 result.AppendError(error.AsCString());
570                 result.SetStatus(eReturnStatusFailed);
571                 return false;
572             }
573 
574             if (bytes_read < total_byte_size)
575                 result.AppendWarningWithFormat("Not all bytes (%u/%u) were able to be read from 0x%llx.\n", bytes_read, total_byte_size, addr);
576         }
577 
578         StreamFile outfile_stream;
579         Stream *output_stream = NULL;
580         const FileSpec &outfile_spec = m_outfile_options.GetFile().GetCurrentValue();
581         if (outfile_spec)
582         {
583             char path[PATH_MAX];
584             outfile_spec.GetPath (path, sizeof(path));
585 
586             uint32_t open_options = File::eOpenOptionWrite | File::eOpenOptionCanCreate;
587             const bool append = m_outfile_options.GetAppend().GetCurrentValue();
588             if (append)
589                 open_options |= File::eOpenOptionAppend;
590 
591             if (outfile_stream.GetFile ().Open (path, open_options).Success())
592             {
593                 if (m_memory_options.m_output_as_binary)
594                 {
595                     int bytes_written = outfile_stream.Write (data_sp->GetBytes(), bytes_read);
596                     if (bytes_written > 0)
597                     {
598                         result.GetOutputStream().Printf ("%i bytes %s to '%s'\n",
599                                                          bytes_written,
600                                                          append ? "appended" : "written",
601                                                          path);
602                         return true;
603                     }
604                     else
605                     {
606                         result.AppendErrorWithFormat("Failed to write %zu bytes to '%s'.\n", bytes_read, path);
607                         result.SetStatus(eReturnStatusFailed);
608                         return false;
609                     }
610                 }
611                 else
612                 {
613                     // We are going to write ASCII to the file just point the
614                     // output_stream to our outfile_stream...
615                     output_stream = &outfile_stream;
616                 }
617             }
618             else
619             {
620                 result.AppendErrorWithFormat("Failed to open file '%s' for %s.\n", path, append ? "append" : "write");
621                 result.SetStatus(eReturnStatusFailed);
622                 return false;
623             }
624         }
625         else
626         {
627             output_stream = &result.GetOutputStream();
628         }
629 
630 
631         if (clang_ast_type.GetOpaqueQualType())
632         {
633             for (uint32_t i = 0; i<item_count; ++i)
634             {
635                 addr_t item_addr = addr + (i * item_byte_size);
636                 Address address (NULL, item_addr);
637                 StreamString name_strm;
638                 name_strm.Printf ("0x%llx", item_addr);
639                 ValueObjectSP valobj_sp (ValueObjectMemory::Create (exe_ctx.GetBestExecutionContextScope(),
640                                                                     name_strm.GetString().c_str(),
641                                                                     address,
642                                                                     clang_ast_type));
643                 if (valobj_sp)
644                 {
645                     if (format != eFormatDefault)
646                         valobj_sp->SetFormat (format);
647 
648                     bool scope_already_checked = true;
649 
650                     ValueObject::DumpValueObject (*output_stream,
651                                                   valobj_sp.get(),
652                                                   NULL,
653                                                   m_varobj_options.ptr_depth,
654                                                   0,
655                                                   m_varobj_options.max_depth,
656                                                   m_varobj_options.show_types,
657                                                   m_varobj_options.show_location,
658                                                   m_varobj_options.use_objc,
659                                                   m_varobj_options.use_dynamic,
660                                                   scope_already_checked,
661                                                   m_varobj_options.flat_output);
662                 }
663                 else
664                 {
665                     result.AppendErrorWithFormat ("failed to create a value object for: (%s) %s\n",
666                                                   view_as_type_cstr,
667                                                   name_strm.GetString().c_str());
668                     result.SetStatus(eReturnStatusFailed);
669                     return false;
670                 }
671             }
672             return true;
673         }
674 
675         result.SetStatus(eReturnStatusSuccessFinishResult);
676         DataExtractor data (data_sp,
677                             exe_ctx.target->GetArchitecture().GetByteOrder(),
678                             exe_ctx.target->GetArchitecture().GetAddressByteSize());
679 
680 
681         assert (output_stream);
682         data.Dump (output_stream,
683                    0,
684                    m_format_options.GetFormat(),
685                    item_byte_size,
686                    item_count,
687                    num_per_line,
688                    addr,
689                    0,
690                    0);
691         output_stream->EOL();
692         return true;
693     }
694 
695 protected:
696     OptionGroupOptions m_option_group;
697     OptionGroupFormat m_format_options;
698     OptionGroupReadMemory m_memory_options;
699     OptionGroupOutputFile m_outfile_options;
700     OptionGroupValueObjectDisplay m_varobj_options;
701 
702 };
703 
704 //----------------------------------------------------------------------
705 // Write memory to the inferior process
706 //----------------------------------------------------------------------
707 class CommandObjectMemoryWrite : public CommandObject
708 {
709 public:
710 
711     class CommandOptions : public Options
712     {
713     public:
714         CommandOptions (CommandInterpreter &interpreter) :
715             Options(interpreter)
716         {
717             OptionParsingStarting();
718         }
719 
720         virtual
721         ~CommandOptions ()
722         {
723         }
724 
725         virtual Error
726         SetOptionValue (uint32_t option_idx, const char *option_arg)
727         {
728             Error error;
729             char short_option = (char) m_getopt_table[option_idx].val;
730             switch (short_option)
731             {
732             case 'f':
733                 error = Args::StringToFormat (option_arg, m_format, &m_byte_size);
734                 break;
735 
736             case 's':
737                 m_byte_size = Args::StringToUInt32 (option_arg, 0);
738                 if (m_byte_size == 0)
739                     error.SetErrorStringWithFormat("Invalid value for --size option '%s'.  Must be positive integer value.\n", option_arg);
740                 break;
741 
742             case 'i':
743                 m_infile.SetFile (option_arg, true);
744                 if (!m_infile.Exists())
745                 {
746                     m_infile.Clear();
747                     error.SetErrorStringWithFormat("Input file does not exist: '%s'\n", option_arg);
748                 }
749                 break;
750 
751             case 'o':
752                 {
753                     bool success;
754                     m_infile_offset = Args::StringToUInt64(option_arg, 0, 0, &success);
755                     if (!success)
756                     {
757                         error.SetErrorStringWithFormat("Invalid offset string '%s'\n", option_arg);
758                     }
759                 }
760                 break;
761 
762             default:
763                 error.SetErrorStringWithFormat("Unrecognized short option '%c'\n", short_option);
764                 break;
765             }
766             return error;
767         }
768 
769         void
770         OptionParsingStarting ()
771         {
772             m_format = eFormatBytes;
773             m_byte_size = 1;
774             m_infile.Clear();
775             m_infile_offset = 0;
776         }
777 
778         const OptionDefinition*
779         GetDefinitions ()
780         {
781             return g_option_table;
782         }
783 
784         // Options table: Required for subclasses of Options.
785 
786         static OptionDefinition g_option_table[];
787 
788         // Instance variables to hold the values for command options.
789         lldb::Format m_format;
790         uint32_t m_byte_size;
791         FileSpec m_infile;
792         off_t m_infile_offset;
793     };
794 
795     CommandObjectMemoryWrite (CommandInterpreter &interpreter) :
796         CommandObject (interpreter,
797                        "memory write",
798                        "Write to the memory of the process being debugged.",
799                        //"memory write [<cmd-options>] <addr> [value1 value2 ...]",
800                        NULL,
801                        eFlagProcessMustBeLaunched),
802         m_options (interpreter)
803     {
804         CommandArgumentEntry arg1;
805         CommandArgumentEntry arg2;
806         CommandArgumentData addr_arg;
807         CommandArgumentData value_arg;
808 
809         // Define the first (and only) variant of this arg.
810         addr_arg.arg_type = eArgTypeAddress;
811         addr_arg.arg_repetition = eArgRepeatPlain;
812 
813         // There is only one variant this argument could be; put it into the argument entry.
814         arg1.push_back (addr_arg);
815 
816         // Define the first (and only) variant of this arg.
817         value_arg.arg_type = eArgTypeValue;
818         value_arg.arg_repetition = eArgRepeatPlus;
819 
820         // There is only one variant this argument could be; put it into the argument entry.
821         arg2.push_back (value_arg);
822 
823         // Push the data for the first argument into the m_arguments vector.
824         m_arguments.push_back (arg1);
825         m_arguments.push_back (arg2);
826     }
827 
828     virtual
829     ~CommandObjectMemoryWrite ()
830     {
831     }
832 
833     Options *
834     GetOptions ()
835     {
836         return &m_options;
837     }
838 
839     bool
840     UIntValueIsValidForSize (uint64_t uval64, size_t total_byte_size)
841     {
842         if (total_byte_size > 8)
843             return false;
844 
845         if (total_byte_size == 8)
846             return true;
847 
848         const uint64_t max = ((uint64_t)1 << (uint64_t)(total_byte_size * 8)) - 1;
849         return uval64 <= max;
850     }
851 
852     bool
853     SIntValueIsValidForSize (int64_t sval64, size_t total_byte_size)
854     {
855         if (total_byte_size > 8)
856             return false;
857 
858         if (total_byte_size == 8)
859             return true;
860 
861         const int64_t max = ((int64_t)1 << (uint64_t)(total_byte_size * 8 - 1)) - 1;
862         const int64_t min = ~(max);
863         return min <= sval64 && sval64 <= max;
864     }
865 
866     virtual bool
867     Execute (Args& command,
868              CommandReturnObject &result)
869     {
870         Process *process = m_interpreter.GetExecutionContext().process;
871         if (process == NULL)
872         {
873             result.AppendError("need a process to read memory");
874             result.SetStatus(eReturnStatusFailed);
875             return false;
876         }
877 
878         const size_t argc = command.GetArgumentCount();
879 
880         if (m_options.m_infile)
881         {
882             if (argc < 1)
883             {
884                 result.AppendErrorWithFormat ("%s takes a destination address when writing file contents.\n", m_cmd_name.c_str());
885                 result.SetStatus(eReturnStatusFailed);
886                 return false;
887             }
888         }
889         else if (argc < 2)
890         {
891             result.AppendErrorWithFormat ("%s takes a destination address and at least one value.\n", m_cmd_name.c_str());
892             result.SetStatus(eReturnStatusFailed);
893             return false;
894         }
895 
896         StreamString buffer (Stream::eBinary,
897                              process->GetTarget().GetArchitecture().GetAddressByteSize(),
898                              process->GetTarget().GetArchitecture().GetByteOrder());
899 
900         size_t item_byte_size = m_options.m_byte_size;
901 
902         lldb::addr_t addr = Args::StringToUInt64(command.GetArgumentAtIndex(0), LLDB_INVALID_ADDRESS, 0);
903 
904         if (addr == LLDB_INVALID_ADDRESS)
905         {
906             result.AppendErrorWithFormat("Invalid address string '%s'.\n", command.GetArgumentAtIndex(0));
907             result.SetStatus(eReturnStatusFailed);
908             return false;
909         }
910 
911         if (m_options.m_infile)
912         {
913             size_t length = SIZE_MAX;
914             if (m_options.m_byte_size > 0)
915                 length = m_options.m_byte_size;
916             lldb::DataBufferSP data_sp (m_options.m_infile.ReadFileContents (m_options.m_infile_offset, length));
917             if (data_sp)
918             {
919                 length = data_sp->GetByteSize();
920                 if (length > 0)
921                 {
922                     Error error;
923                     size_t bytes_written = process->WriteMemory (addr, data_sp->GetBytes(), length, error);
924 
925                     if (bytes_written == length)
926                     {
927                         // All bytes written
928                         result.GetOutputStream().Printf("%zu bytes were written to 0x%llx\n", bytes_written, addr);
929                         result.SetStatus(eReturnStatusSuccessFinishResult);
930                     }
931                     else if (bytes_written > 0)
932                     {
933                         // Some byte written
934                         result.GetOutputStream().Printf("%zu bytes of %zu requested were written to 0x%llx\n", bytes_written, length, addr);
935                         result.SetStatus(eReturnStatusSuccessFinishResult);
936                     }
937                     else
938                     {
939                         result.AppendErrorWithFormat ("Memory write to 0x%llx failed: %s.\n", addr, error.AsCString());
940                         result.SetStatus(eReturnStatusFailed);
941                     }
942                 }
943             }
944             else
945             {
946                 result.AppendErrorWithFormat ("Unable to read contents of file.\n");
947                 result.SetStatus(eReturnStatusFailed);
948             }
949             return result.Succeeded();
950         }
951         else if (m_options.m_byte_size == 0)
952         {
953             if (m_options.m_format == eFormatPointer)
954                 item_byte_size = buffer.GetAddressByteSize();
955             else
956                 item_byte_size = 1;
957         }
958 
959         command.Shift(); // shift off the address argument
960         uint64_t uval64;
961         int64_t sval64;
962         bool success = false;
963         const uint32_t num_value_args = command.GetArgumentCount();
964         uint32_t i;
965         for (i=0; i<num_value_args; ++i)
966         {
967             const char *value_str = command.GetArgumentAtIndex(i);
968 
969             switch (m_options.m_format)
970             {
971             case kNumFormats:
972             case eFormatFloat:  // TODO: add support for floats soon
973             case eFormatCharPrintable:
974             case eFormatBytesWithASCII:
975             case eFormatComplex:
976             case eFormatEnum:
977             case eFormatUnicode16:
978             case eFormatUnicode32:
979             case eFormatVectorOfChar:
980             case eFormatVectorOfSInt8:
981             case eFormatVectorOfUInt8:
982             case eFormatVectorOfSInt16:
983             case eFormatVectorOfUInt16:
984             case eFormatVectorOfSInt32:
985             case eFormatVectorOfUInt32:
986             case eFormatVectorOfSInt64:
987             case eFormatVectorOfUInt64:
988             case eFormatVectorOfFloat32:
989             case eFormatVectorOfFloat64:
990             case eFormatVectorOfUInt128:
991             case eFormatOSType:
992             case eFormatComplexInteger:
993                 result.AppendError("unsupported format for writing memory");
994                 result.SetStatus(eReturnStatusFailed);
995                 return false;
996 
997             case eFormatDefault:
998             case eFormatBytes:
999             case eFormatHex:
1000             case eFormatPointer:
1001 
1002                 // Decode hex bytes
1003                 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 16, &success);
1004                 if (!success)
1005                 {
1006                     result.AppendErrorWithFormat ("'%s' is not a valid hex string value.\n", value_str);
1007                     result.SetStatus(eReturnStatusFailed);
1008                     return false;
1009                 }
1010                 else if (!UIntValueIsValidForSize (uval64, item_byte_size))
1011                 {
1012                     result.AppendErrorWithFormat ("Value 0x%llx is too large to fit in a %u byte unsigned integer value.\n", uval64, item_byte_size);
1013                     result.SetStatus(eReturnStatusFailed);
1014                     return false;
1015                 }
1016                 buffer.PutMaxHex64 (uval64, item_byte_size);
1017                 break;
1018 
1019             case eFormatBoolean:
1020                 uval64 = Args::StringToBoolean(value_str, false, &success);
1021                 if (!success)
1022                 {
1023                     result.AppendErrorWithFormat ("'%s' is not a valid boolean string value.\n", value_str);
1024                     result.SetStatus(eReturnStatusFailed);
1025                     return false;
1026                 }
1027                 buffer.PutMaxHex64 (uval64, item_byte_size);
1028                 break;
1029 
1030             case eFormatBinary:
1031                 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 2, &success);
1032                 if (!success)
1033                 {
1034                     result.AppendErrorWithFormat ("'%s' is not a valid binary string value.\n", value_str);
1035                     result.SetStatus(eReturnStatusFailed);
1036                     return false;
1037                 }
1038                 else if (!UIntValueIsValidForSize (uval64, item_byte_size))
1039                 {
1040                     result.AppendErrorWithFormat ("Value 0x%llx is too large to fit in a %u byte unsigned integer value.\n", uval64, item_byte_size);
1041                     result.SetStatus(eReturnStatusFailed);
1042                     return false;
1043                 }
1044                 buffer.PutMaxHex64 (uval64, item_byte_size);
1045                 break;
1046 
1047             case eFormatCharArray:
1048             case eFormatChar:
1049             case eFormatCString:
1050                 if (value_str[0])
1051                 {
1052                     size_t len = strlen (value_str);
1053                     // Include the NULL for C strings...
1054                     if (m_options.m_format == eFormatCString)
1055                         ++len;
1056                     Error error;
1057                     if (process->WriteMemory (addr, value_str, len, error) == len)
1058                     {
1059                         addr += len;
1060                     }
1061                     else
1062                     {
1063                         result.AppendErrorWithFormat ("Memory write to 0x%llx failed: %s.\n", addr, error.AsCString());
1064                         result.SetStatus(eReturnStatusFailed);
1065                         return false;
1066                     }
1067                 }
1068                 break;
1069 
1070             case eFormatDecimal:
1071                 sval64 = Args::StringToSInt64(value_str, INT64_MAX, 0, &success);
1072                 if (!success)
1073                 {
1074                     result.AppendErrorWithFormat ("'%s' is not a valid signed decimal value.\n", value_str);
1075                     result.SetStatus(eReturnStatusFailed);
1076                     return false;
1077                 }
1078                 else if (!SIntValueIsValidForSize (sval64, item_byte_size))
1079                 {
1080                     result.AppendErrorWithFormat ("Value %lli is too large or small to fit in a %u byte signed integer value.\n", sval64, item_byte_size);
1081                     result.SetStatus(eReturnStatusFailed);
1082                     return false;
1083                 }
1084                 buffer.PutMaxHex64 (sval64, item_byte_size);
1085                 break;
1086 
1087             case eFormatUnsigned:
1088                 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 0, &success);
1089                 if (!success)
1090                 {
1091                     result.AppendErrorWithFormat ("'%s' is not a valid unsigned decimal string value.\n", value_str);
1092                     result.SetStatus(eReturnStatusFailed);
1093                     return false;
1094                 }
1095                 else if (!UIntValueIsValidForSize (uval64, item_byte_size))
1096                 {
1097                     result.AppendErrorWithFormat ("Value %llu is too large to fit in a %u byte unsigned integer value.\n", uval64, item_byte_size);
1098                     result.SetStatus(eReturnStatusFailed);
1099                     return false;
1100                 }
1101                 buffer.PutMaxHex64 (uval64, item_byte_size);
1102                 break;
1103 
1104             case eFormatOctal:
1105                 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 8, &success);
1106                 if (!success)
1107                 {
1108                     result.AppendErrorWithFormat ("'%s' is not a valid octal string value.\n", value_str);
1109                     result.SetStatus(eReturnStatusFailed);
1110                     return false;
1111                 }
1112                 else if (!UIntValueIsValidForSize (uval64, item_byte_size))
1113                 {
1114                     result.AppendErrorWithFormat ("Value %llo is too large to fit in a %u byte unsigned integer value.\n", uval64, item_byte_size);
1115                     result.SetStatus(eReturnStatusFailed);
1116                     return false;
1117                 }
1118                 buffer.PutMaxHex64 (uval64, item_byte_size);
1119                 break;
1120             }
1121         }
1122 
1123         if (!buffer.GetString().empty())
1124         {
1125             Error error;
1126             if (process->WriteMemory (addr, buffer.GetString().c_str(), buffer.GetString().size(), error) == buffer.GetString().size())
1127                 return true;
1128             else
1129             {
1130                 result.AppendErrorWithFormat ("Memory write to 0x%llx failed: %s.\n", addr, error.AsCString());
1131                 result.SetStatus(eReturnStatusFailed);
1132                 return false;
1133             }
1134         }
1135         return true;
1136     }
1137 
1138 protected:
1139     CommandOptions m_options;
1140 };
1141 
1142 #define SET1 LLDB_OPT_SET_1
1143 #define SET2 LLDB_OPT_SET_2
1144 
1145 OptionDefinition
1146 CommandObjectMemoryWrite::CommandOptions::g_option_table[] =
1147 {
1148 { SET1       , false, "format", 'f', required_argument, NULL, 0, eArgTypeFormat,   "The format value types that will be decoded and written to memory."},
1149 { SET1 | SET2, false, "size",   's', required_argument, NULL, 0, eArgTypeByteSize, "The size in bytes of the values to write to memory."},
1150 {        SET2, true,  "infile", 'i', required_argument, NULL, 0, eArgTypeFilename, "Write memory using the contents of a file."},
1151 {        SET2, false, "offset", 'o', required_argument, NULL, 0, eArgTypeOffset,   "Start writng bytes from an offset within the input file."},
1152 { 0          , false, NULL    ,  0 , 0                , NULL, 0, eArgTypeNone,     NULL }
1153 };
1154 
1155 #undef SET1
1156 #undef SET2
1157 
1158 //-------------------------------------------------------------------------
1159 // CommandObjectMemory
1160 //-------------------------------------------------------------------------
1161 
1162 CommandObjectMemory::CommandObjectMemory (CommandInterpreter &interpreter) :
1163     CommandObjectMultiword (interpreter,
1164                             "memory",
1165                             "A set of commands for operating on memory.",
1166                             "memory <subcommand> [<subcommand-options>]")
1167 {
1168     LoadSubCommand ("read",  CommandObjectSP (new CommandObjectMemoryRead (interpreter)));
1169     LoadSubCommand ("write", CommandObjectSP (new CommandObjectMemoryWrite (interpreter)));
1170 }
1171 
1172 CommandObjectMemory::~CommandObjectMemory ()
1173 {
1174 }
1175