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