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