xref: /llvm-project/lldb/source/Commands/CommandObjectMemory.cpp (revision 644247c1dc56106a06afbf8ac25fa4e07f46dd88)
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                        eFlagProcessMustBeLaunched),
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.process == NULL)
355         {
356             result.AppendError("need a process 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             bytes_read = exe_ctx.process->ReadMemory(addr, data_sp->GetBytes (), data_sp->GetByteSize(), error);
565             if (bytes_read == 0)
566             {
567                 result.AppendWarningWithFormat("Read from 0x%llx failed.\n", addr);
568                 result.AppendError(error.AsCString());
569                 result.SetStatus(eReturnStatusFailed);
570                 return false;
571             }
572 
573             if (bytes_read < total_byte_size)
574                 result.AppendWarningWithFormat("Not all bytes (%u/%u) were able to be read from 0x%llx.\n", bytes_read, total_byte_size, addr);
575         }
576 
577         StreamFile outfile_stream;
578         Stream *output_stream = NULL;
579         const FileSpec &outfile_spec = m_outfile_options.GetFile().GetCurrentValue();
580         if (outfile_spec)
581         {
582             char path[PATH_MAX];
583             outfile_spec.GetPath (path, sizeof(path));
584 
585             uint32_t open_options = File::eOpenOptionWrite | File::eOpenOptionCanCreate;
586             const bool append = m_outfile_options.GetAppend().GetCurrentValue();
587             if (append)
588                 open_options |= File::eOpenOptionAppend;
589 
590             if (outfile_stream.GetFile ().Open (path, open_options).Success())
591             {
592                 if (m_memory_options.m_output_as_binary)
593                 {
594                     int bytes_written = outfile_stream.Write (data_sp->GetBytes(), bytes_read);
595                     if (bytes_written > 0)
596                     {
597                         result.GetOutputStream().Printf ("%i bytes %s to '%s'\n",
598                                                          bytes_written,
599                                                          append ? "appended" : "written",
600                                                          path);
601                         return true;
602                     }
603                     else
604                     {
605                         result.AppendErrorWithFormat("Failed to write %zu bytes to '%s'.\n", bytes_read, path);
606                         result.SetStatus(eReturnStatusFailed);
607                         return false;
608                     }
609                 }
610                 else
611                 {
612                     // We are going to write ASCII to the file just point the
613                     // output_stream to our outfile_stream...
614                     output_stream = &outfile_stream;
615                 }
616             }
617             else
618             {
619                 result.AppendErrorWithFormat("Failed to open file '%s' for %s.\n", path, append ? "append" : "write");
620                 result.SetStatus(eReturnStatusFailed);
621                 return false;
622             }
623         }
624         else
625         {
626             output_stream = &result.GetOutputStream();
627         }
628 
629 
630         if (clang_ast_type.GetOpaqueQualType())
631         {
632             for (uint32_t i = 0; i<item_count; ++i)
633             {
634                 addr_t item_addr = addr + (i * item_byte_size);
635                 Address address (NULL, item_addr);
636                 StreamString name_strm;
637                 name_strm.Printf ("0x%llx", item_addr);
638                 ValueObjectSP valobj_sp (ValueObjectMemory::Create (exe_ctx.GetBestExecutionContextScope(),
639                                                                     name_strm.GetString().c_str(),
640                                                                     address,
641                                                                     clang_ast_type));
642                 if (valobj_sp)
643                 {
644                     if (format != eFormatDefault)
645                         valobj_sp->SetFormat (format);
646 
647                     bool scope_already_checked = true;
648 
649                     ValueObject::DumpValueObject (*output_stream,
650                                                   valobj_sp.get(),
651                                                   NULL,
652                                                   m_varobj_options.ptr_depth,
653                                                   0,
654                                                   m_varobj_options.max_depth,
655                                                   m_varobj_options.show_types,
656                                                   m_varobj_options.show_location,
657                                                   m_varobj_options.use_objc,
658                                                   m_varobj_options.use_dynamic,
659                                                   scope_already_checked,
660                                                   m_varobj_options.flat_output);
661                 }
662                 else
663                 {
664                     result.AppendErrorWithFormat ("failed to create a value object for: (%s) %s\n",
665                                                   view_as_type_cstr,
666                                                   name_strm.GetString().c_str());
667                     result.SetStatus(eReturnStatusFailed);
668                     return false;
669                 }
670             }
671             return true;
672         }
673 
674         result.SetStatus(eReturnStatusSuccessFinishResult);
675         DataExtractor data (data_sp,
676                             exe_ctx.target->GetArchitecture().GetByteOrder(),
677                             exe_ctx.target->GetArchitecture().GetAddressByteSize());
678 
679 
680         assert (output_stream);
681         data.Dump (output_stream,
682                    0,
683                    m_format_options.GetFormat(),
684                    item_byte_size,
685                    item_count,
686                    num_per_line,
687                    addr,
688                    0,
689                    0);
690         output_stream->EOL();
691         return true;
692     }
693 
694 protected:
695     OptionGroupOptions m_option_group;
696     OptionGroupFormat m_format_options;
697     OptionGroupReadMemory m_memory_options;
698     OptionGroupOutputFile m_outfile_options;
699     OptionGroupValueObjectDisplay m_varobj_options;
700 
701 };
702 
703 //----------------------------------------------------------------------
704 // Write memory to the inferior process
705 //----------------------------------------------------------------------
706 class CommandObjectMemoryWrite : public CommandObject
707 {
708 public:
709 
710     class CommandOptions : public Options
711     {
712     public:
713         CommandOptions (CommandInterpreter &interpreter) :
714             Options(interpreter)
715         {
716             OptionParsingStarting();
717         }
718 
719         virtual
720         ~CommandOptions ()
721         {
722         }
723 
724         virtual Error
725         SetOptionValue (uint32_t option_idx, const char *option_arg)
726         {
727             Error error;
728             char short_option = (char) m_getopt_table[option_idx].val;
729             switch (short_option)
730             {
731             case 'f':
732                 error = Args::StringToFormat (option_arg, m_format, &m_byte_size);
733                 break;
734 
735             case 's':
736                 m_byte_size = Args::StringToUInt32 (option_arg, 0);
737                 if (m_byte_size == 0)
738                     error.SetErrorStringWithFormat("Invalid value for --size option '%s'.  Must be positive integer value.\n", option_arg);
739                 break;
740 
741             case 'i':
742                 m_infile.SetFile (option_arg, true);
743                 if (!m_infile.Exists())
744                 {
745                     m_infile.Clear();
746                     error.SetErrorStringWithFormat("Input file does not exist: '%s'\n", option_arg);
747                 }
748                 break;
749 
750             case 'o':
751                 {
752                     bool success;
753                     m_infile_offset = Args::StringToUInt64(option_arg, 0, 0, &success);
754                     if (!success)
755                     {
756                         error.SetErrorStringWithFormat("Invalid offset string '%s'\n", option_arg);
757                     }
758                 }
759                 break;
760 
761             default:
762                 error.SetErrorStringWithFormat("Unrecognized short option '%c'\n", short_option);
763                 break;
764             }
765             return error;
766         }
767 
768         void
769         OptionParsingStarting ()
770         {
771             m_format = eFormatBytes;
772             m_byte_size = 1;
773             m_infile.Clear();
774             m_infile_offset = 0;
775         }
776 
777         const OptionDefinition*
778         GetDefinitions ()
779         {
780             return g_option_table;
781         }
782 
783         // Options table: Required for subclasses of Options.
784 
785         static OptionDefinition g_option_table[];
786 
787         // Instance variables to hold the values for command options.
788         lldb::Format m_format;
789         uint32_t m_byte_size;
790         FileSpec m_infile;
791         off_t m_infile_offset;
792     };
793 
794     CommandObjectMemoryWrite (CommandInterpreter &interpreter) :
795         CommandObject (interpreter,
796                        "memory write",
797                        "Write to the memory of the process being debugged.",
798                        //"memory write [<cmd-options>] <addr> [value1 value2 ...]",
799                        NULL,
800                        eFlagProcessMustBeLaunched),
801         m_options (interpreter)
802     {
803         CommandArgumentEntry arg1;
804         CommandArgumentEntry arg2;
805         CommandArgumentData addr_arg;
806         CommandArgumentData value_arg;
807 
808         // Define the first (and only) variant of this arg.
809         addr_arg.arg_type = eArgTypeAddress;
810         addr_arg.arg_repetition = eArgRepeatPlain;
811 
812         // There is only one variant this argument could be; put it into the argument entry.
813         arg1.push_back (addr_arg);
814 
815         // Define the first (and only) variant of this arg.
816         value_arg.arg_type = eArgTypeValue;
817         value_arg.arg_repetition = eArgRepeatPlus;
818 
819         // There is only one variant this argument could be; put it into the argument entry.
820         arg2.push_back (value_arg);
821 
822         // Push the data for the first argument into the m_arguments vector.
823         m_arguments.push_back (arg1);
824         m_arguments.push_back (arg2);
825     }
826 
827     virtual
828     ~CommandObjectMemoryWrite ()
829     {
830     }
831 
832     Options *
833     GetOptions ()
834     {
835         return &m_options;
836     }
837 
838     bool
839     UIntValueIsValidForSize (uint64_t uval64, size_t total_byte_size)
840     {
841         if (total_byte_size > 8)
842             return false;
843 
844         if (total_byte_size == 8)
845             return true;
846 
847         const uint64_t max = ((uint64_t)1 << (uint64_t)(total_byte_size * 8)) - 1;
848         return uval64 <= max;
849     }
850 
851     bool
852     SIntValueIsValidForSize (int64_t sval64, size_t total_byte_size)
853     {
854         if (total_byte_size > 8)
855             return false;
856 
857         if (total_byte_size == 8)
858             return true;
859 
860         const int64_t max = ((int64_t)1 << (uint64_t)(total_byte_size * 8 - 1)) - 1;
861         const int64_t min = ~(max);
862         return min <= sval64 && sval64 <= max;
863     }
864 
865     virtual bool
866     Execute (Args& command,
867              CommandReturnObject &result)
868     {
869         Process *process = m_interpreter.GetExecutionContext().process;
870         if (process == NULL)
871         {
872             result.AppendError("need a process to read memory");
873             result.SetStatus(eReturnStatusFailed);
874             return false;
875         }
876 
877         const size_t argc = command.GetArgumentCount();
878 
879         if (m_options.m_infile)
880         {
881             if (argc < 1)
882             {
883                 result.AppendErrorWithFormat ("%s takes a destination address when writing file contents.\n", m_cmd_name.c_str());
884                 result.SetStatus(eReturnStatusFailed);
885                 return false;
886             }
887         }
888         else if (argc < 2)
889         {
890             result.AppendErrorWithFormat ("%s takes a destination address and at least one value.\n", m_cmd_name.c_str());
891             result.SetStatus(eReturnStatusFailed);
892             return false;
893         }
894 
895         StreamString buffer (Stream::eBinary,
896                              process->GetTarget().GetArchitecture().GetAddressByteSize(),
897                              process->GetTarget().GetArchitecture().GetByteOrder());
898 
899         size_t item_byte_size = m_options.m_byte_size;
900 
901         lldb::addr_t addr = Args::StringToUInt64(command.GetArgumentAtIndex(0), LLDB_INVALID_ADDRESS, 0);
902 
903         if (addr == LLDB_INVALID_ADDRESS)
904         {
905             result.AppendErrorWithFormat("Invalid address string '%s'.\n", command.GetArgumentAtIndex(0));
906             result.SetStatus(eReturnStatusFailed);
907             return false;
908         }
909 
910         if (m_options.m_infile)
911         {
912             size_t length = SIZE_MAX;
913             if (m_options.m_byte_size > 0)
914                 length = m_options.m_byte_size;
915             lldb::DataBufferSP data_sp (m_options.m_infile.ReadFileContents (m_options.m_infile_offset, length));
916             if (data_sp)
917             {
918                 length = data_sp->GetByteSize();
919                 if (length > 0)
920                 {
921                     Error error;
922                     size_t bytes_written = process->WriteMemory (addr, data_sp->GetBytes(), length, error);
923 
924                     if (bytes_written == length)
925                     {
926                         // All bytes written
927                         result.GetOutputStream().Printf("%zu bytes were written to 0x%llx\n", bytes_written, addr);
928                         result.SetStatus(eReturnStatusSuccessFinishResult);
929                     }
930                     else if (bytes_written > 0)
931                     {
932                         // Some byte written
933                         result.GetOutputStream().Printf("%zu bytes of %zu requested were written to 0x%llx\n", bytes_written, length, addr);
934                         result.SetStatus(eReturnStatusSuccessFinishResult);
935                     }
936                     else
937                     {
938                         result.AppendErrorWithFormat ("Memory write to 0x%llx failed: %s.\n", addr, error.AsCString());
939                         result.SetStatus(eReturnStatusFailed);
940                     }
941                 }
942             }
943             else
944             {
945                 result.AppendErrorWithFormat ("Unable to read contents of file.\n");
946                 result.SetStatus(eReturnStatusFailed);
947             }
948             return result.Succeeded();
949         }
950         else if (m_options.m_byte_size == 0)
951         {
952             if (m_options.m_format == eFormatPointer)
953                 item_byte_size = buffer.GetAddressByteSize();
954             else
955                 item_byte_size = 1;
956         }
957 
958         command.Shift(); // shift off the address argument
959         uint64_t uval64;
960         int64_t sval64;
961         bool success = false;
962         const uint32_t num_value_args = command.GetArgumentCount();
963         uint32_t i;
964         for (i=0; i<num_value_args; ++i)
965         {
966             const char *value_str = command.GetArgumentAtIndex(i);
967 
968             switch (m_options.m_format)
969             {
970             case kNumFormats:
971             case eFormatFloat:  // TODO: add support for floats soon
972             case eFormatCharPrintable:
973             case eFormatBytesWithASCII:
974             case eFormatComplex:
975             case eFormatEnum:
976             case eFormatUnicode16:
977             case eFormatUnicode32:
978             case eFormatVectorOfChar:
979             case eFormatVectorOfSInt8:
980             case eFormatVectorOfUInt8:
981             case eFormatVectorOfSInt16:
982             case eFormatVectorOfUInt16:
983             case eFormatVectorOfSInt32:
984             case eFormatVectorOfUInt32:
985             case eFormatVectorOfSInt64:
986             case eFormatVectorOfUInt64:
987             case eFormatVectorOfFloat32:
988             case eFormatVectorOfFloat64:
989             case eFormatVectorOfUInt128:
990             case eFormatOSType:
991             case eFormatComplexInteger:
992                 result.AppendError("unsupported format for writing memory");
993                 result.SetStatus(eReturnStatusFailed);
994                 return false;
995 
996             case eFormatDefault:
997             case eFormatBytes:
998             case eFormatHex:
999             case eFormatPointer:
1000 
1001                 // Decode hex bytes
1002                 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 16, &success);
1003                 if (!success)
1004                 {
1005                     result.AppendErrorWithFormat ("'%s' is not a valid hex string value.\n", value_str);
1006                     result.SetStatus(eReturnStatusFailed);
1007                     return false;
1008                 }
1009                 else if (!UIntValueIsValidForSize (uval64, item_byte_size))
1010                 {
1011                     result.AppendErrorWithFormat ("Value 0x%llx is too large to fit in a %u byte unsigned integer value.\n", uval64, item_byte_size);
1012                     result.SetStatus(eReturnStatusFailed);
1013                     return false;
1014                 }
1015                 buffer.PutMaxHex64 (uval64, item_byte_size);
1016                 break;
1017 
1018             case eFormatBoolean:
1019                 uval64 = Args::StringToBoolean(value_str, false, &success);
1020                 if (!success)
1021                 {
1022                     result.AppendErrorWithFormat ("'%s' is not a valid boolean string value.\n", value_str);
1023                     result.SetStatus(eReturnStatusFailed);
1024                     return false;
1025                 }
1026                 buffer.PutMaxHex64 (uval64, item_byte_size);
1027                 break;
1028 
1029             case eFormatBinary:
1030                 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 2, &success);
1031                 if (!success)
1032                 {
1033                     result.AppendErrorWithFormat ("'%s' is not a valid binary string value.\n", value_str);
1034                     result.SetStatus(eReturnStatusFailed);
1035                     return false;
1036                 }
1037                 else if (!UIntValueIsValidForSize (uval64, item_byte_size))
1038                 {
1039                     result.AppendErrorWithFormat ("Value 0x%llx is too large to fit in a %u byte unsigned integer value.\n", uval64, item_byte_size);
1040                     result.SetStatus(eReturnStatusFailed);
1041                     return false;
1042                 }
1043                 buffer.PutMaxHex64 (uval64, item_byte_size);
1044                 break;
1045 
1046             case eFormatCharArray:
1047             case eFormatChar:
1048             case eFormatCString:
1049                 if (value_str[0])
1050                 {
1051                     size_t len = strlen (value_str);
1052                     // Include the NULL for C strings...
1053                     if (m_options.m_format == eFormatCString)
1054                         ++len;
1055                     Error error;
1056                     if (process->WriteMemory (addr, value_str, len, error) == len)
1057                     {
1058                         addr += len;
1059                     }
1060                     else
1061                     {
1062                         result.AppendErrorWithFormat ("Memory write to 0x%llx failed: %s.\n", addr, error.AsCString());
1063                         result.SetStatus(eReturnStatusFailed);
1064                         return false;
1065                     }
1066                 }
1067                 break;
1068 
1069             case eFormatDecimal:
1070                 sval64 = Args::StringToSInt64(value_str, INT64_MAX, 0, &success);
1071                 if (!success)
1072                 {
1073                     result.AppendErrorWithFormat ("'%s' is not a valid signed decimal value.\n", value_str);
1074                     result.SetStatus(eReturnStatusFailed);
1075                     return false;
1076                 }
1077                 else if (!SIntValueIsValidForSize (sval64, item_byte_size))
1078                 {
1079                     result.AppendErrorWithFormat ("Value %lli is too large or small to fit in a %u byte signed integer value.\n", sval64, item_byte_size);
1080                     result.SetStatus(eReturnStatusFailed);
1081                     return false;
1082                 }
1083                 buffer.PutMaxHex64 (sval64, item_byte_size);
1084                 break;
1085 
1086             case eFormatUnsigned:
1087                 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 0, &success);
1088                 if (!success)
1089                 {
1090                     result.AppendErrorWithFormat ("'%s' is not a valid unsigned decimal string value.\n", value_str);
1091                     result.SetStatus(eReturnStatusFailed);
1092                     return false;
1093                 }
1094                 else if (!UIntValueIsValidForSize (uval64, item_byte_size))
1095                 {
1096                     result.AppendErrorWithFormat ("Value %llu is too large to fit in a %u byte unsigned integer value.\n", uval64, item_byte_size);
1097                     result.SetStatus(eReturnStatusFailed);
1098                     return false;
1099                 }
1100                 buffer.PutMaxHex64 (uval64, item_byte_size);
1101                 break;
1102 
1103             case eFormatOctal:
1104                 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 8, &success);
1105                 if (!success)
1106                 {
1107                     result.AppendErrorWithFormat ("'%s' is not a valid octal string value.\n", value_str);
1108                     result.SetStatus(eReturnStatusFailed);
1109                     return false;
1110                 }
1111                 else if (!UIntValueIsValidForSize (uval64, item_byte_size))
1112                 {
1113                     result.AppendErrorWithFormat ("Value %llo is too large to fit in a %u byte unsigned integer value.\n", uval64, item_byte_size);
1114                     result.SetStatus(eReturnStatusFailed);
1115                     return false;
1116                 }
1117                 buffer.PutMaxHex64 (uval64, item_byte_size);
1118                 break;
1119             }
1120         }
1121 
1122         if (!buffer.GetString().empty())
1123         {
1124             Error error;
1125             if (process->WriteMemory (addr, buffer.GetString().c_str(), buffer.GetString().size(), error) == buffer.GetString().size())
1126                 return true;
1127             else
1128             {
1129                 result.AppendErrorWithFormat ("Memory write to 0x%llx failed: %s.\n", addr, error.AsCString());
1130                 result.SetStatus(eReturnStatusFailed);
1131                 return false;
1132             }
1133         }
1134         return true;
1135     }
1136 
1137 protected:
1138     CommandOptions m_options;
1139 };
1140 
1141 #define SET1 LLDB_OPT_SET_1
1142 #define SET2 LLDB_OPT_SET_2
1143 
1144 OptionDefinition
1145 CommandObjectMemoryWrite::CommandOptions::g_option_table[] =
1146 {
1147 { SET1       , false, "format", 'f', required_argument, NULL, 0, eArgTypeFormat,   "The format value types that will be decoded and written to memory."},
1148 { SET1 | SET2, false, "size",   's', required_argument, NULL, 0, eArgTypeByteSize, "The size in bytes of the values to write to memory."},
1149 {        SET2, true,  "infile", 'i', required_argument, NULL, 0, eArgTypeFilename, "Write memory using the contents of a file."},
1150 {        SET2, false, "offset", 'o', required_argument, NULL, 0, eArgTypeOffset,   "Start writng bytes from an offset within the input file."},
1151 { 0          , false, NULL    ,  0 , 0                , NULL, 0, eArgTypeNone,     NULL }
1152 };
1153 
1154 #undef SET1
1155 #undef SET2
1156 
1157 //-------------------------------------------------------------------------
1158 // CommandObjectMemory
1159 //-------------------------------------------------------------------------
1160 
1161 CommandObjectMemory::CommandObjectMemory (CommandInterpreter &interpreter) :
1162     CommandObjectMultiword (interpreter,
1163                             "memory",
1164                             "A set of commands for operating on memory.",
1165                             "memory <subcommand> [<subcommand-options>]")
1166 {
1167     LoadSubCommand ("read",  CommandObjectSP (new CommandObjectMemoryRead (interpreter)));
1168     LoadSubCommand ("write", CommandObjectSP (new CommandObjectMemoryWrite (interpreter)));
1169 }
1170 
1171 CommandObjectMemory::~CommandObjectMemory ()
1172 {
1173 }
1174