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