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