xref: /llvm-project/lldb/source/Commands/CommandObjectMemory.cpp (revision bb7f31fa2976875a8460c2f5d214c702ea982146)
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                        eFlagProcessMustBeLaunched),
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.process == NULL)
355         {
356             result.AppendError("need a process 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             bytes_read = exe_ctx.process->ReadMemory(addr, data_sp->GetBytes (), data_sp->GetByteSize(), error);
565             if (bytes_read == 0)
566             {
567                 result.AppendWarningWithFormat("Read from 0x%llx failed.\n", addr);
568                 result.AppendError(error.AsCString());
569                 result.SetStatus(eReturnStatusFailed);
570                 return false;
571             }
572 
573             if (bytes_read < total_byte_size)
574                 result.AppendWarningWithFormat("Not all bytes (%u/%u) were able to be read from 0x%llx.\n", bytes_read, total_byte_size, addr);
575         }
576 
577         StreamFile outfile_stream;
578         Stream *output_stream = NULL;
579         const FileSpec &outfile_spec = m_outfile_options.GetFile().GetCurrentValue();
580         if (outfile_spec)
581         {
582             char path[PATH_MAX];
583             outfile_spec.GetPath (path, sizeof(path));
584 
585             uint32_t open_options = File::eOpenOptionWrite | File::eOpenOptionCanCreate;
586             const bool append = m_outfile_options.GetAppend().GetCurrentValue();
587             if (append)
588                 open_options |= File::eOpenOptionAppend;
589 
590             if (outfile_stream.GetFile ().Open (path, open_options).Success())
591             {
592                 if (m_memory_options.m_output_as_binary)
593                 {
594                     int bytes_written = outfile_stream.Write (data_sp->GetBytes(), bytes_read);
595                     if (bytes_written > 0)
596                     {
597                         result.GetOutputStream().Printf ("%i bytes %s to '%s'\n",
598                                                          bytes_written,
599                                                          append ? "appended" : "written",
600                                                          path);
601                         return true;
602                     }
603                     else
604                     {
605                         result.AppendErrorWithFormat("Failed to write %zu bytes to '%s'.\n", bytes_read, path);
606                         result.SetStatus(eReturnStatusFailed);
607                         return false;
608                     }
609                 }
610                 else
611                 {
612                     // We are going to write ASCII to the file just point the
613                     // output_stream to our outfile_stream...
614                     output_stream = &outfile_stream;
615                 }
616             }
617             else
618             {
619                 result.AppendErrorWithFormat("Failed to open file '%s' for %s.\n", path, append ? "append" : "write");
620                 result.SetStatus(eReturnStatusFailed);
621                 return false;
622             }
623         }
624         else
625         {
626             output_stream = &result.GetOutputStream();
627         }
628 
629 
630         if (clang_ast_type.GetOpaqueQualType())
631         {
632             for (uint32_t i = 0; i<item_count; ++i)
633             {
634                 addr_t item_addr = addr + (i * item_byte_size);
635                 Address address (NULL, item_addr);
636                 StreamString name_strm;
637                 name_strm.Printf ("0x%llx", item_addr);
638                 ValueObjectSP valobj_sp (ValueObjectMemory::Create (exe_ctx.GetBestExecutionContextScope(),
639                                                                     name_strm.GetString().c_str(),
640                                                                     address,
641                                                                     clang_ast_type));
642                 if (valobj_sp)
643                 {
644                     if (format != eFormatDefault)
645                         valobj_sp->SetFormat (format);
646 
647                     bool scope_already_checked = true;
648 
649                     ValueObject::DumpValueObject (*output_stream,
650                                                   valobj_sp.get(),
651                                                   NULL,
652                                                   m_varobj_options.ptr_depth,
653                                                   0,
654                                                   m_varobj_options.max_depth,
655                                                   m_varobj_options.show_types,
656                                                   m_varobj_options.show_location,
657                                                   m_varobj_options.use_objc,
658                                                   m_varobj_options.use_dynamic,
659                                                   scope_already_checked,
660                                                   m_varobj_options.flat_output);
661                 }
662                 else
663                 {
664                     result.AppendErrorWithFormat ("failed to create a value object for: (%s) %s\n",
665                                                   view_as_type_cstr,
666                                                   name_strm.GetString().c_str());
667                     result.SetStatus(eReturnStatusFailed);
668                     return false;
669                 }
670             }
671             return true;
672         }
673 
674         result.SetStatus(eReturnStatusSuccessFinishResult);
675         DataExtractor data (data_sp,
676                             exe_ctx.target->GetArchitecture().GetByteOrder(),
677                             exe_ctx.target->GetArchitecture().GetAddressByteSize());
678 
679 
680         assert (output_stream);
681         data.Dump (output_stream,
682                    0,
683                    m_format_options.GetFormat(),
684                    item_byte_size,
685                    item_count,
686                    num_per_line,
687                    addr,
688                    0,
689                    0);
690         output_stream->EOL();
691         return true;
692     }
693 
694 protected:
695 //    CommandOptions m_options;
696     OptionGroupOptions m_option_group;
697     OptionGroupFormat m_format_options;
698     OptionGroupReadMemory m_memory_options;
699     OptionGroupOutputFile m_outfile_options;
700     OptionGroupValueObjectDisplay m_varobj_options;
701 
702 };
703 
704 //OptionDefinition
705 //CommandObjectMemoryRead::CommandOptions::g_option_table[] =
706 //{
707 //{ LLDB_OPT_SET_1, false, "format"       ,'f', required_argument, NULL, 0, eArgTypeFormat        ,"The format that will be used to display the memory. Defaults to bytes with ASCII (--format=Y)."},
708 //{ LLDB_OPT_SET_1, false, "size"         ,'s', required_argument, NULL, 0, eArgTypeByteSize      ,"The size in bytes to use when displaying with the selected format."},
709 //{ LLDB_OPT_SET_1, false, "num-per-line" ,'l', required_argument, NULL, 0, eArgTypeNumberPerLine ,"The number of items per line to display."},
710 //{ LLDB_OPT_SET_1|
711 //  LLDB_OPT_SET_2|
712 //  LLDB_OPT_SET_3, false, "count"        ,'c', required_argument, NULL, 0, eArgTypeCount         ,"The number of total items to display."},
713 //{ LLDB_OPT_SET_1|
714 //  LLDB_OPT_SET_2|
715 //  LLDB_OPT_SET_3, false, "outfile"      ,'o', required_argument, NULL, 0, eArgTypeFilename      ,"Dump memory read results into a file."},
716 //{ LLDB_OPT_SET_1|
717 //  LLDB_OPT_SET_2|
718 //  LLDB_OPT_SET_3, false, "append"       ,'a', no_argument      , NULL, 0, eArgTypeNone          ,"Append memory read results to 'outfile'."},
719 //{ 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."},
720 //{ LLDB_OPT_SET_3, true , "view-as"      ,'t', required_argument, NULL, 0, eArgTypeNone          ,"The name of a type to view memory as."},
721 //{ 0             , false, NULL           , 0 , 0                , NULL, 0, eArgTypeNone          , NULL }
722 //};
723 
724 //----------------------------------------------------------------------
725 // Write memory to the inferior process
726 //----------------------------------------------------------------------
727 class CommandObjectMemoryWrite : public CommandObject
728 {
729 public:
730 
731     class CommandOptions : public Options
732     {
733     public:
734         CommandOptions (CommandInterpreter &interpreter) :
735             Options(interpreter)
736         {
737             OptionParsingStarting();
738         }
739 
740         virtual
741         ~CommandOptions ()
742         {
743         }
744 
745         virtual Error
746         SetOptionValue (uint32_t option_idx, const char *option_arg)
747         {
748             Error error;
749             char short_option = (char) m_getopt_table[option_idx].val;
750             switch (short_option)
751             {
752             case 'f':
753                 error = Args::StringToFormat (option_arg, m_format, &m_byte_size);
754                 break;
755 
756             case 's':
757                 m_byte_size = Args::StringToUInt32 (option_arg, 0);
758                 if (m_byte_size == 0)
759                     error.SetErrorStringWithFormat("Invalid value for --size option '%s'.  Must be positive integer value.\n", option_arg);
760                 break;
761 
762             case 'i':
763                 m_infile.SetFile (option_arg, true);
764                 if (!m_infile.Exists())
765                 {
766                     m_infile.Clear();
767                     error.SetErrorStringWithFormat("Input file does not exist: '%s'\n", option_arg);
768                 }
769                 break;
770 
771             case 'o':
772                 {
773                     bool success;
774                     m_infile_offset = Args::StringToUInt64(option_arg, 0, 0, &success);
775                     if (!success)
776                     {
777                         error.SetErrorStringWithFormat("Invalid offset string '%s'\n", option_arg);
778                     }
779                 }
780                 break;
781 
782             default:
783                 error.SetErrorStringWithFormat("Unrecognized short option '%c'\n", short_option);
784                 break;
785             }
786             return error;
787         }
788 
789         void
790         OptionParsingStarting ()
791         {
792             m_format = eFormatBytes;
793             m_byte_size = 1;
794             m_infile.Clear();
795             m_infile_offset = 0;
796         }
797 
798         const OptionDefinition*
799         GetDefinitions ()
800         {
801             return g_option_table;
802         }
803 
804         // Options table: Required for subclasses of Options.
805 
806         static OptionDefinition g_option_table[];
807 
808         // Instance variables to hold the values for command options.
809         lldb::Format m_format;
810         uint32_t m_byte_size;
811         FileSpec m_infile;
812         off_t m_infile_offset;
813     };
814 
815     CommandObjectMemoryWrite (CommandInterpreter &interpreter) :
816         CommandObject (interpreter,
817                        "memory write",
818                        "Write to the memory of the process being debugged.",
819                        //"memory write [<cmd-options>] <addr> [value1 value2 ...]",
820                        NULL,
821                        eFlagProcessMustBeLaunched),
822         m_options (interpreter)
823     {
824         CommandArgumentEntry arg1;
825         CommandArgumentEntry arg2;
826         CommandArgumentData addr_arg;
827         CommandArgumentData value_arg;
828 
829         // Define the first (and only) variant of this arg.
830         addr_arg.arg_type = eArgTypeAddress;
831         addr_arg.arg_repetition = eArgRepeatPlain;
832 
833         // There is only one variant this argument could be; put it into the argument entry.
834         arg1.push_back (addr_arg);
835 
836         // Define the first (and only) variant of this arg.
837         value_arg.arg_type = eArgTypeValue;
838         value_arg.arg_repetition = eArgRepeatPlus;
839 
840         // There is only one variant this argument could be; put it into the argument entry.
841         arg2.push_back (value_arg);
842 
843         // Push the data for the first argument into the m_arguments vector.
844         m_arguments.push_back (arg1);
845         m_arguments.push_back (arg2);
846     }
847 
848     virtual
849     ~CommandObjectMemoryWrite ()
850     {
851     }
852 
853     Options *
854     GetOptions ()
855     {
856         return &m_options;
857     }
858 
859     bool
860     UIntValueIsValidForSize (uint64_t uval64, size_t total_byte_size)
861     {
862         if (total_byte_size > 8)
863             return false;
864 
865         if (total_byte_size == 8)
866             return true;
867 
868         const uint64_t max = ((uint64_t)1 << (uint64_t)(total_byte_size * 8)) - 1;
869         return uval64 <= max;
870     }
871 
872     bool
873     SIntValueIsValidForSize (int64_t sval64, size_t total_byte_size)
874     {
875         if (total_byte_size > 8)
876             return false;
877 
878         if (total_byte_size == 8)
879             return true;
880 
881         const int64_t max = ((int64_t)1 << (uint64_t)(total_byte_size * 8 - 1)) - 1;
882         const int64_t min = ~(max);
883         return min <= sval64 && sval64 <= max;
884     }
885 
886     virtual bool
887     Execute (Args& command,
888              CommandReturnObject &result)
889     {
890         Process *process = m_interpreter.GetExecutionContext().process;
891         if (process == NULL)
892         {
893             result.AppendError("need a process to read memory");
894             result.SetStatus(eReturnStatusFailed);
895             return false;
896         }
897 
898         const size_t argc = command.GetArgumentCount();
899 
900         if (m_options.m_infile)
901         {
902             if (argc < 1)
903             {
904                 result.AppendErrorWithFormat ("%s takes a destination address when writing file contents.\n", m_cmd_name.c_str());
905                 result.SetStatus(eReturnStatusFailed);
906                 return false;
907             }
908         }
909         else if (argc < 2)
910         {
911             result.AppendErrorWithFormat ("%s takes a destination address and at least one value.\n", m_cmd_name.c_str());
912             result.SetStatus(eReturnStatusFailed);
913             return false;
914         }
915 
916         StreamString buffer (Stream::eBinary,
917                              process->GetTarget().GetArchitecture().GetAddressByteSize(),
918                              process->GetTarget().GetArchitecture().GetByteOrder());
919 
920         size_t item_byte_size = m_options.m_byte_size;
921 
922         lldb::addr_t addr = Args::StringToUInt64(command.GetArgumentAtIndex(0), LLDB_INVALID_ADDRESS, 0);
923 
924         if (addr == LLDB_INVALID_ADDRESS)
925         {
926             result.AppendErrorWithFormat("Invalid address string '%s'.\n", command.GetArgumentAtIndex(0));
927             result.SetStatus(eReturnStatusFailed);
928             return false;
929         }
930 
931         if (m_options.m_infile)
932         {
933             size_t length = SIZE_MAX;
934             if (m_options.m_byte_size > 0)
935                 length = m_options.m_byte_size;
936             lldb::DataBufferSP data_sp (m_options.m_infile.ReadFileContents (m_options.m_infile_offset, length));
937             if (data_sp)
938             {
939                 length = data_sp->GetByteSize();
940                 if (length > 0)
941                 {
942                     Error error;
943                     size_t bytes_written = process->WriteMemory (addr, data_sp->GetBytes(), length, error);
944 
945                     if (bytes_written == length)
946                     {
947                         // All bytes written
948                         result.GetOutputStream().Printf("%zu bytes were written to 0x%llx\n", bytes_written, addr);
949                         result.SetStatus(eReturnStatusSuccessFinishResult);
950                     }
951                     else if (bytes_written > 0)
952                     {
953                         // Some byte written
954                         result.GetOutputStream().Printf("%zu bytes of %zu requested were written to 0x%llx\n", bytes_written, length, addr);
955                         result.SetStatus(eReturnStatusSuccessFinishResult);
956                     }
957                     else
958                     {
959                         result.AppendErrorWithFormat ("Memory write to 0x%llx failed: %s.\n", addr, error.AsCString());
960                         result.SetStatus(eReturnStatusFailed);
961                     }
962                 }
963             }
964             else
965             {
966                 result.AppendErrorWithFormat ("Unable to read contents of file.\n");
967                 result.SetStatus(eReturnStatusFailed);
968             }
969             return result.Succeeded();
970         }
971         else if (m_options.m_byte_size == 0)
972         {
973             if (m_options.m_format == eFormatPointer)
974                 item_byte_size = buffer.GetAddressByteSize();
975             else
976                 item_byte_size = 1;
977         }
978 
979         command.Shift(); // shift off the address argument
980         uint64_t uval64;
981         int64_t sval64;
982         bool success = false;
983         const uint32_t num_value_args = command.GetArgumentCount();
984         uint32_t i;
985         for (i=0; i<num_value_args; ++i)
986         {
987             const char *value_str = command.GetArgumentAtIndex(i);
988 
989             switch (m_options.m_format)
990             {
991             case kNumFormats:
992             case eFormatFloat:  // TODO: add support for floats soon
993             case eFormatCharPrintable:
994             case eFormatBytesWithASCII:
995             case eFormatComplex:
996             case eFormatEnum:
997             case eFormatUnicode16:
998             case eFormatUnicode32:
999             case eFormatVectorOfChar:
1000             case eFormatVectorOfSInt8:
1001             case eFormatVectorOfUInt8:
1002             case eFormatVectorOfSInt16:
1003             case eFormatVectorOfUInt16:
1004             case eFormatVectorOfSInt32:
1005             case eFormatVectorOfUInt32:
1006             case eFormatVectorOfSInt64:
1007             case eFormatVectorOfUInt64:
1008             case eFormatVectorOfFloat32:
1009             case eFormatVectorOfFloat64:
1010             case eFormatVectorOfUInt128:
1011             case eFormatOSType:
1012             case eFormatComplexInteger:
1013                 result.AppendError("unsupported format for writing memory");
1014                 result.SetStatus(eReturnStatusFailed);
1015                 return false;
1016 
1017             case eFormatDefault:
1018             case eFormatBytes:
1019             case eFormatHex:
1020             case eFormatPointer:
1021 
1022                 // Decode hex bytes
1023                 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 16, &success);
1024                 if (!success)
1025                 {
1026                     result.AppendErrorWithFormat ("'%s' is not a valid hex string value.\n", value_str);
1027                     result.SetStatus(eReturnStatusFailed);
1028                     return false;
1029                 }
1030                 else if (!UIntValueIsValidForSize (uval64, item_byte_size))
1031                 {
1032                     result.AppendErrorWithFormat ("Value 0x%llx is too large to fit in a %u byte unsigned integer value.\n", uval64, item_byte_size);
1033                     result.SetStatus(eReturnStatusFailed);
1034                     return false;
1035                 }
1036                 buffer.PutMaxHex64 (uval64, item_byte_size);
1037                 break;
1038 
1039             case eFormatBoolean:
1040                 uval64 = Args::StringToBoolean(value_str, false, &success);
1041                 if (!success)
1042                 {
1043                     result.AppendErrorWithFormat ("'%s' is not a valid boolean string value.\n", value_str);
1044                     result.SetStatus(eReturnStatusFailed);
1045                     return false;
1046                 }
1047                 buffer.PutMaxHex64 (uval64, item_byte_size);
1048                 break;
1049 
1050             case eFormatBinary:
1051                 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 2, &success);
1052                 if (!success)
1053                 {
1054                     result.AppendErrorWithFormat ("'%s' is not a valid binary string value.\n", value_str);
1055                     result.SetStatus(eReturnStatusFailed);
1056                     return false;
1057                 }
1058                 else if (!UIntValueIsValidForSize (uval64, item_byte_size))
1059                 {
1060                     result.AppendErrorWithFormat ("Value 0x%llx is too large to fit in a %u byte unsigned integer value.\n", uval64, item_byte_size);
1061                     result.SetStatus(eReturnStatusFailed);
1062                     return false;
1063                 }
1064                 buffer.PutMaxHex64 (uval64, item_byte_size);
1065                 break;
1066 
1067             case eFormatCharArray:
1068             case eFormatChar:
1069             case eFormatCString:
1070                 if (value_str[0])
1071                 {
1072                     size_t len = strlen (value_str);
1073                     // Include the NULL for C strings...
1074                     if (m_options.m_format == eFormatCString)
1075                         ++len;
1076                     Error error;
1077                     if (process->WriteMemory (addr, value_str, len, error) == len)
1078                     {
1079                         addr += len;
1080                     }
1081                     else
1082                     {
1083                         result.AppendErrorWithFormat ("Memory write to 0x%llx failed: %s.\n", addr, error.AsCString());
1084                         result.SetStatus(eReturnStatusFailed);
1085                         return false;
1086                     }
1087                 }
1088                 break;
1089 
1090             case eFormatDecimal:
1091                 sval64 = Args::StringToSInt64(value_str, INT64_MAX, 0, &success);
1092                 if (!success)
1093                 {
1094                     result.AppendErrorWithFormat ("'%s' is not a valid signed decimal value.\n", value_str);
1095                     result.SetStatus(eReturnStatusFailed);
1096                     return false;
1097                 }
1098                 else if (!SIntValueIsValidForSize (sval64, item_byte_size))
1099                 {
1100                     result.AppendErrorWithFormat ("Value %lli is too large or small to fit in a %u byte signed integer value.\n", sval64, item_byte_size);
1101                     result.SetStatus(eReturnStatusFailed);
1102                     return false;
1103                 }
1104                 buffer.PutMaxHex64 (sval64, item_byte_size);
1105                 break;
1106 
1107             case eFormatUnsigned:
1108                 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 0, &success);
1109                 if (!success)
1110                 {
1111                     result.AppendErrorWithFormat ("'%s' is not a valid unsigned decimal 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 %llu 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             case eFormatOctal:
1125                 uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 8, &success);
1126                 if (!success)
1127                 {
1128                     result.AppendErrorWithFormat ("'%s' is not a valid octal string value.\n", value_str);
1129                     result.SetStatus(eReturnStatusFailed);
1130                     return false;
1131                 }
1132                 else if (!UIntValueIsValidForSize (uval64, item_byte_size))
1133                 {
1134                     result.AppendErrorWithFormat ("Value %llo is too large to fit in a %u byte unsigned integer value.\n", uval64, item_byte_size);
1135                     result.SetStatus(eReturnStatusFailed);
1136                     return false;
1137                 }
1138                 buffer.PutMaxHex64 (uval64, item_byte_size);
1139                 break;
1140             }
1141         }
1142 
1143         if (!buffer.GetString().empty())
1144         {
1145             Error error;
1146             if (process->WriteMemory (addr, buffer.GetString().c_str(), buffer.GetString().size(), error) == buffer.GetString().size())
1147                 return true;
1148             else
1149             {
1150                 result.AppendErrorWithFormat ("Memory write to 0x%llx failed: %s.\n", addr, error.AsCString());
1151                 result.SetStatus(eReturnStatusFailed);
1152                 return false;
1153             }
1154         }
1155         return true;
1156     }
1157 
1158 protected:
1159     CommandOptions m_options;
1160 };
1161 
1162 #define SET1 LLDB_OPT_SET_1
1163 #define SET2 LLDB_OPT_SET_2
1164 
1165 OptionDefinition
1166 CommandObjectMemoryWrite::CommandOptions::g_option_table[] =
1167 {
1168 { SET1       , false, "format", 'f', required_argument, NULL, 0, eArgTypeFormat,   "The format value types that will be decoded and written to memory."},
1169 { SET1 | SET2, false, "size",   's', required_argument, NULL, 0, eArgTypeByteSize, "The size in bytes of the values to write to memory."},
1170 {        SET2, true,  "infile", 'i', required_argument, NULL, 0, eArgTypeFilename, "Write memory using the contents of a file."},
1171 {        SET2, false, "offset", 'o', required_argument, NULL, 0, eArgTypeOffset,   "Start writng bytes from an offset within the input file."},
1172 { 0          , false, NULL    ,  0 , 0                , NULL, 0, eArgTypeNone,     NULL }
1173 };
1174 
1175 #undef SET1
1176 #undef SET2
1177 
1178 //-------------------------------------------------------------------------
1179 // CommandObjectMemory
1180 //-------------------------------------------------------------------------
1181 
1182 CommandObjectMemory::CommandObjectMemory (CommandInterpreter &interpreter) :
1183     CommandObjectMultiword (interpreter,
1184                             "memory",
1185                             "A set of commands for operating on memory.",
1186                             "memory <subcommand> [<subcommand-options>]")
1187 {
1188     LoadSubCommand ("read",  CommandObjectSP (new CommandObjectMemoryRead (interpreter)));
1189     LoadSubCommand ("write", CommandObjectSP (new CommandObjectMemoryWrite (interpreter)));
1190 }
1191 
1192 CommandObjectMemory::~CommandObjectMemory ()
1193 {
1194 }
1195