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