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