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