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