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