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