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_3);
327         m_option_group.Append (&m_format_options,
328                                OptionGroupFormat::OPTION_GROUP_GDB_FMT,
329                                LLDB_OPT_SET_1 | LLDB_OPT_SET_2 | 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                 }
710                 else
711                 {
712                     result.AppendErrorWithFormat ("failed to create a value object for: (%s) %s\n",
713                                                   view_as_type_cstr,
714                                                   name_strm.GetString().c_str());
715                     result.SetStatus(eReturnStatusFailed);
716                     return false;
717                 }
718             }
719             return true;
720         }
721 
722         result.SetStatus(eReturnStatusSuccessFinishResult);
723         DataExtractor data (data_sp,
724                             target->GetArchitecture().GetByteOrder(),
725                             target->GetArchitecture().GetAddressByteSize());
726 
727 
728         assert (output_stream);
729         uint32_t bytes_dumped = data.Dump (output_stream,
730                                            0,
731                                            m_format_options.GetFormat(),
732                                            item_byte_size,
733                                            item_count,
734                                            num_per_line,
735                                            addr,
736                                            0,
737                                            0,
738                                            exe_scope);
739         m_next_addr = addr + bytes_dumped;
740         output_stream->EOL();
741         return true;
742     }
743 
744 protected:
745     OptionGroupOptions m_option_group;
746     OptionGroupFormat m_format_options;
747     OptionGroupReadMemory m_memory_options;
748     OptionGroupOutputFile m_outfile_options;
749     OptionGroupValueObjectDisplay m_varobj_options;
750     lldb::addr_t m_next_addr;
751     lldb::addr_t m_prev_byte_size;
752     OptionGroupFormat m_prev_format_options;
753     OptionGroupReadMemory m_prev_memory_options;
754     OptionGroupOutputFile m_prev_outfile_options;
755     OptionGroupValueObjectDisplay m_prev_varobj_options;
756 };
757 
758 
759 OptionDefinition
760 g_memory_write_option_table[] =
761 {
762 { LLDB_OPT_SET_1, true,  "infile", 'i', required_argument, NULL, 0, eArgTypeFilename, "Write memory using the contents of a file."},
763 { LLDB_OPT_SET_1, false, "offset", 'o', required_argument, NULL, 0, eArgTypeOffset,   "Start writng bytes from an offset within the input file."},
764 };
765 
766 
767 //----------------------------------------------------------------------
768 // Write memory to the inferior process
769 //----------------------------------------------------------------------
770 class CommandObjectMemoryWrite : public CommandObject
771 {
772 public:
773 
774     class OptionGroupWriteMemory : public OptionGroup
775     {
776     public:
777         OptionGroupWriteMemory () :
778             OptionGroup()
779         {
780         }
781 
782         virtual
783         ~OptionGroupWriteMemory ()
784         {
785         }
786 
787         virtual uint32_t
788         GetNumDefinitions ()
789         {
790             return sizeof (g_memory_write_option_table) / sizeof (OptionDefinition);
791         }
792 
793         virtual const OptionDefinition*
794         GetDefinitions ()
795         {
796             return g_memory_write_option_table;
797         }
798 
799         virtual Error
800         SetOptionValue (CommandInterpreter &interpreter,
801                         uint32_t option_idx,
802                         const char *option_arg)
803         {
804             Error error;
805             char short_option = (char) g_memory_write_option_table[option_idx].short_option;
806 
807             switch (short_option)
808             {
809                 case 'i':
810                     m_infile.SetFile (option_arg, true);
811                     if (!m_infile.Exists())
812                     {
813                         m_infile.Clear();
814                         error.SetErrorStringWithFormat("input file does not exist: '%s'", option_arg);
815                     }
816                     break;
817 
818                 case 'o':
819                     {
820                         bool success;
821                         m_infile_offset = Args::StringToUInt64(option_arg, 0, 0, &success);
822                         if (!success)
823                         {
824                             error.SetErrorStringWithFormat("invalid offset string '%s'", option_arg);
825                         }
826                     }
827                     break;
828 
829                 default:
830                     error.SetErrorStringWithFormat("unrecognized short option '%c'", short_option);
831                     break;
832             }
833             return error;
834         }
835 
836         virtual void
837         OptionParsingStarting (CommandInterpreter &interpreter)
838         {
839             m_infile.Clear();
840             m_infile_offset = 0;
841         }
842 
843         FileSpec m_infile;
844         off_t m_infile_offset;
845     };
846 
847     CommandObjectMemoryWrite (CommandInterpreter &interpreter) :
848         CommandObject (interpreter,
849                        "memory write",
850                        "Write to the memory of the process being debugged.",
851                        //"memory write [<cmd-options>] <addr> [value1 value2 ...]",
852                        NULL,
853                        eFlagProcessMustBeLaunched),
854         m_option_group (interpreter),
855         m_format_options (eFormatBytes, 1, UINT64_MAX),
856         m_memory_options ()
857     {
858         CommandArgumentEntry arg1;
859         CommandArgumentEntry arg2;
860         CommandArgumentData addr_arg;
861         CommandArgumentData value_arg;
862 
863         // Define the first (and only) variant of this arg.
864         addr_arg.arg_type = eArgTypeAddress;
865         addr_arg.arg_repetition = eArgRepeatPlain;
866 
867         // There is only one variant this argument could be; put it into the argument entry.
868         arg1.push_back (addr_arg);
869 
870         // Define the first (and only) variant of this arg.
871         value_arg.arg_type = eArgTypeValue;
872         value_arg.arg_repetition = eArgRepeatPlus;
873 
874         // There is only one variant this argument could be; put it into the argument entry.
875         arg2.push_back (value_arg);
876 
877         // Push the data for the first argument into the m_arguments vector.
878         m_arguments.push_back (arg1);
879         m_arguments.push_back (arg2);
880 
881         m_option_group.Append (&m_format_options, OptionGroupFormat::OPTION_GROUP_FORMAT, LLDB_OPT_SET_1);
882         m_option_group.Append (&m_format_options, OptionGroupFormat::OPTION_GROUP_SIZE  , LLDB_OPT_SET_1|LLDB_OPT_SET_2);
883         m_option_group.Append (&m_memory_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_2);
884         m_option_group.Finalize();
885 
886     }
887 
888     virtual
889     ~CommandObjectMemoryWrite ()
890     {
891     }
892 
893     Options *
894     GetOptions ()
895     {
896         return &m_option_group;
897     }
898 
899     bool
900     UIntValueIsValidForSize (uint64_t uval64, size_t total_byte_size)
901     {
902         if (total_byte_size > 8)
903             return false;
904 
905         if (total_byte_size == 8)
906             return true;
907 
908         const uint64_t max = ((uint64_t)1 << (uint64_t)(total_byte_size * 8)) - 1;
909         return uval64 <= max;
910     }
911 
912     bool
913     SIntValueIsValidForSize (int64_t sval64, size_t total_byte_size)
914     {
915         if (total_byte_size > 8)
916             return false;
917 
918         if (total_byte_size == 8)
919             return true;
920 
921         const int64_t max = ((int64_t)1 << (uint64_t)(total_byte_size * 8 - 1)) - 1;
922         const int64_t min = ~(max);
923         return min <= sval64 && sval64 <= max;
924     }
925 
926     virtual bool
927     Execute (Args& command,
928              CommandReturnObject &result)
929     {
930         Process *process = m_interpreter.GetExecutionContext().GetProcessPtr();
931         if (process == NULL)
932         {
933             result.AppendError("need a process to read memory");
934             result.SetStatus(eReturnStatusFailed);
935             return false;
936         }
937 
938         const size_t argc = command.GetArgumentCount();
939 
940         if (m_memory_options.m_infile)
941         {
942             if (argc < 1)
943             {
944                 result.AppendErrorWithFormat ("%s takes a destination address when writing file contents.\n", m_cmd_name.c_str());
945                 result.SetStatus(eReturnStatusFailed);
946                 return false;
947             }
948         }
949         else if (argc < 2)
950         {
951             result.AppendErrorWithFormat ("%s takes a destination address and at least one value.\n", m_cmd_name.c_str());
952             result.SetStatus(eReturnStatusFailed);
953             return false;
954         }
955 
956         StreamString buffer (Stream::eBinary,
957                              process->GetTarget().GetArchitecture().GetAddressByteSize(),
958                              process->GetTarget().GetArchitecture().GetByteOrder());
959 
960         OptionValueUInt64 &byte_size_value = m_format_options.GetByteSizeValue();
961         size_t item_byte_size = byte_size_value.GetCurrentValue();
962 
963         lldb::addr_t addr = Args::StringToUInt64(command.GetArgumentAtIndex(0), LLDB_INVALID_ADDRESS, 0);
964 
965         if (addr == LLDB_INVALID_ADDRESS)
966         {
967             result.AppendErrorWithFormat("Invalid address string '%s'.\n", command.GetArgumentAtIndex(0));
968             result.SetStatus(eReturnStatusFailed);
969             return false;
970         }
971 
972         if (m_memory_options.m_infile)
973         {
974             size_t length = SIZE_MAX;
975             if (item_byte_size > 0)
976                 length = item_byte_size;
977             lldb::DataBufferSP data_sp (m_memory_options.m_infile.ReadFileContents (m_memory_options.m_infile_offset, length));
978             if (data_sp)
979             {
980                 length = data_sp->GetByteSize();
981                 if (length > 0)
982                 {
983                     Error error;
984                     size_t bytes_written = process->WriteMemory (addr, data_sp->GetBytes(), length, error);
985 
986                     if (bytes_written == length)
987                     {
988                         // All bytes written
989                         result.GetOutputStream().Printf("%zu bytes were written to 0x%llx\n", bytes_written, addr);
990                         result.SetStatus(eReturnStatusSuccessFinishResult);
991                     }
992                     else if (bytes_written > 0)
993                     {
994                         // Some byte written
995                         result.GetOutputStream().Printf("%zu bytes of %zu requested were written to 0x%llx\n", bytes_written, length, addr);
996                         result.SetStatus(eReturnStatusSuccessFinishResult);
997                     }
998                     else
999                     {
1000                         result.AppendErrorWithFormat ("Memory write to 0x%llx failed: %s.\n", addr, error.AsCString());
1001                         result.SetStatus(eReturnStatusFailed);
1002                     }
1003                 }
1004             }
1005             else
1006             {
1007                 result.AppendErrorWithFormat ("Unable to read contents of file.\n");
1008                 result.SetStatus(eReturnStatusFailed);
1009             }
1010             return result.Succeeded();
1011         }
1012         else if (item_byte_size == 0)
1013         {
1014             if (m_format_options.GetFormat() == eFormatPointer)
1015                 item_byte_size = buffer.GetAddressByteSize();
1016             else
1017                 item_byte_size = 1;
1018         }
1019 
1020         command.Shift(); // shift off the address argument
1021         uint64_t uval64;
1022         int64_t sval64;
1023         bool success = false;
1024         const uint32_t num_value_args = command.GetArgumentCount();
1025         uint32_t i;
1026         for (i=0; i<num_value_args; ++i)
1027         {
1028             const char *value_str = command.GetArgumentAtIndex(i);
1029 
1030             switch (m_format_options.GetFormat())
1031             {
1032             case kNumFormats:
1033             case eFormatFloat:  // TODO: add support for floats soon
1034             case eFormatCharPrintable:
1035             case eFormatBytesWithASCII:
1036             case eFormatComplex:
1037             case eFormatEnum:
1038             case eFormatUnicode16:
1039             case eFormatUnicode32:
1040             case eFormatVectorOfChar:
1041             case eFormatVectorOfSInt8:
1042             case eFormatVectorOfUInt8:
1043             case eFormatVectorOfSInt16:
1044             case eFormatVectorOfUInt16:
1045             case eFormatVectorOfSInt32:
1046             case eFormatVectorOfUInt32:
1047             case eFormatVectorOfSInt64:
1048             case eFormatVectorOfUInt64:
1049             case eFormatVectorOfFloat32:
1050             case eFormatVectorOfFloat64:
1051             case eFormatVectorOfUInt128:
1052             case eFormatOSType:
1053             case eFormatComplexInteger:
1054             case eFormatAddressInfo:
1055             case eFormatHexFloat:
1056             case eFormatInstruction:
1057                 result.AppendError("unsupported format for writing memory");
1058                 result.SetStatus(eReturnStatusFailed);
1059                 return false;
1060 
1061             case eFormatDefault:
1062             case eFormatBytes:
1063             case eFormatHex:
1064             case eFormatPointer:
1065 
1066                 // Decode hex bytes
1067                 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 16, &success);
1068                 if (!success)
1069                 {
1070                     result.AppendErrorWithFormat ("'%s' is not a valid hex string value.\n", value_str);
1071                     result.SetStatus(eReturnStatusFailed);
1072                     return false;
1073                 }
1074                 else if (!UIntValueIsValidForSize (uval64, item_byte_size))
1075                 {
1076                     result.AppendErrorWithFormat ("Value 0x%llx is too large to fit in a %lu byte unsigned integer value.\n", uval64, item_byte_size);
1077                     result.SetStatus(eReturnStatusFailed);
1078                     return false;
1079                 }
1080                 buffer.PutMaxHex64 (uval64, item_byte_size);
1081                 break;
1082 
1083             case eFormatBoolean:
1084                 uval64 = Args::StringToBoolean(value_str, false, &success);
1085                 if (!success)
1086                 {
1087                     result.AppendErrorWithFormat ("'%s' is not a valid boolean string value.\n", value_str);
1088                     result.SetStatus(eReturnStatusFailed);
1089                     return false;
1090                 }
1091                 buffer.PutMaxHex64 (uval64, item_byte_size);
1092                 break;
1093 
1094             case eFormatBinary:
1095                 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 2, &success);
1096                 if (!success)
1097                 {
1098                     result.AppendErrorWithFormat ("'%s' is not a valid binary string value.\n", value_str);
1099                     result.SetStatus(eReturnStatusFailed);
1100                     return false;
1101                 }
1102                 else if (!UIntValueIsValidForSize (uval64, item_byte_size))
1103                 {
1104                     result.AppendErrorWithFormat ("Value 0x%llx is too large to fit in a %lu byte unsigned integer value.\n", uval64, item_byte_size);
1105                     result.SetStatus(eReturnStatusFailed);
1106                     return false;
1107                 }
1108                 buffer.PutMaxHex64 (uval64, item_byte_size);
1109                 break;
1110 
1111             case eFormatCharArray:
1112             case eFormatChar:
1113             case eFormatCString:
1114                 if (value_str[0])
1115                 {
1116                     size_t len = strlen (value_str);
1117                     // Include the NULL for C strings...
1118                     if (m_format_options.GetFormat() == eFormatCString)
1119                         ++len;
1120                     Error error;
1121                     if (process->WriteMemory (addr, value_str, len, error) == len)
1122                     {
1123                         addr += len;
1124                     }
1125                     else
1126                     {
1127                         result.AppendErrorWithFormat ("Memory write to 0x%llx failed: %s.\n", addr, error.AsCString());
1128                         result.SetStatus(eReturnStatusFailed);
1129                         return false;
1130                     }
1131                 }
1132                 break;
1133 
1134             case eFormatDecimal:
1135                 sval64 = Args::StringToSInt64(value_str, INT64_MAX, 0, &success);
1136                 if (!success)
1137                 {
1138                     result.AppendErrorWithFormat ("'%s' is not a valid signed decimal value.\n", value_str);
1139                     result.SetStatus(eReturnStatusFailed);
1140                     return false;
1141                 }
1142                 else if (!SIntValueIsValidForSize (sval64, item_byte_size))
1143                 {
1144                     result.AppendErrorWithFormat ("Value %lli is too large or small to fit in a %lu byte signed integer value.\n", sval64, item_byte_size);
1145                     result.SetStatus(eReturnStatusFailed);
1146                     return false;
1147                 }
1148                 buffer.PutMaxHex64 (sval64, item_byte_size);
1149                 break;
1150 
1151             case eFormatUnsigned:
1152                 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 0, &success);
1153                 if (!success)
1154                 {
1155                     result.AppendErrorWithFormat ("'%s' is not a valid unsigned decimal string value.\n", value_str);
1156                     result.SetStatus(eReturnStatusFailed);
1157                     return false;
1158                 }
1159                 else if (!UIntValueIsValidForSize (uval64, item_byte_size))
1160                 {
1161                     result.AppendErrorWithFormat ("Value %llu is too large to fit in a %lu byte unsigned integer value.\n", uval64, item_byte_size);
1162                     result.SetStatus(eReturnStatusFailed);
1163                     return false;
1164                 }
1165                 buffer.PutMaxHex64 (uval64, item_byte_size);
1166                 break;
1167 
1168             case eFormatOctal:
1169                 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 8, &success);
1170                 if (!success)
1171                 {
1172                     result.AppendErrorWithFormat ("'%s' is not a valid octal string value.\n", value_str);
1173                     result.SetStatus(eReturnStatusFailed);
1174                     return false;
1175                 }
1176                 else if (!UIntValueIsValidForSize (uval64, item_byte_size))
1177                 {
1178                     result.AppendErrorWithFormat ("Value %llo is too large to fit in a %lu byte unsigned integer value.\n", uval64, item_byte_size);
1179                     result.SetStatus(eReturnStatusFailed);
1180                     return false;
1181                 }
1182                 buffer.PutMaxHex64 (uval64, item_byte_size);
1183                 break;
1184             }
1185         }
1186 
1187         if (!buffer.GetString().empty())
1188         {
1189             Error error;
1190             if (process->WriteMemory (addr, buffer.GetString().c_str(), buffer.GetString().size(), error) == buffer.GetString().size())
1191                 return true;
1192             else
1193             {
1194                 result.AppendErrorWithFormat ("Memory write to 0x%llx failed: %s.\n", addr, error.AsCString());
1195                 result.SetStatus(eReturnStatusFailed);
1196                 return false;
1197             }
1198         }
1199         return true;
1200     }
1201 
1202 protected:
1203 
1204     OptionGroupOptions m_option_group;
1205     OptionGroupFormat m_format_options;
1206     OptionGroupWriteMemory m_memory_options;
1207 };
1208 
1209 
1210 //-------------------------------------------------------------------------
1211 // CommandObjectMemory
1212 //-------------------------------------------------------------------------
1213 
1214 CommandObjectMemory::CommandObjectMemory (CommandInterpreter &interpreter) :
1215     CommandObjectMultiword (interpreter,
1216                             "memory",
1217                             "A set of commands for operating on memory.",
1218                             "memory <subcommand> [<subcommand-options>]")
1219 {
1220     LoadSubCommand ("read",  CommandObjectSP (new CommandObjectMemoryRead (interpreter)));
1221     LoadSubCommand ("write", CommandObjectSP (new CommandObjectMemoryWrite (interpreter)));
1222 }
1223 
1224 CommandObjectMemory::~CommandObjectMemory ()
1225 {
1226 }
1227