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