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