Initial checkin of lldb code from internal Apple repo.

llvm-svn: 105619
diff --git a/lldb/source/Commands/CommandObjectMemory.cpp b/lldb/source/Commands/CommandObjectMemory.cpp
new file mode 100644
index 0000000..91abd81
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectMemory.cpp
@@ -0,0 +1,680 @@
+//===-- CommandObjectMemory.cpp ---------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CommandObjectMemory.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Args.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Options.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/CommandContext.h"
+#include "lldb/Target/Process.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Read memory from the inferior process
+//----------------------------------------------------------------------
+class CommandObjectMemoryRead : public CommandObject
+{
+public:
+
+    class CommandOptions : public Options
+    {
+    public:
+        CommandOptions () :
+            Options()
+        {
+            ResetOptionValues();
+        }
+
+        virtual
+        ~CommandOptions ()
+        {
+        }
+
+        virtual Error
+        SetOptionValue (int option_idx, const char *option_arg)
+        {
+            Error error;
+            char short_option = (char) m_getopt_table[option_idx].val;
+
+            switch (short_option)
+            {
+            case 'f':
+                error = Args::StringToFormat (option_arg, m_format);
+
+                switch (m_format)
+                {
+                default:
+                    break;
+
+                case eFormatBoolean:
+                    if (m_byte_size == 0)
+                        m_byte_size = 1;
+                    if (m_num_per_line == 0)
+                        m_num_per_line = 1;
+                    break;
+
+                case eFormatCString:
+                    if (m_num_per_line == 0)
+                        m_num_per_line = 1;
+                    break;
+
+                case eFormatPointer:
+                    break;
+
+                case eFormatBinary:
+                case eFormatFloat:
+                case eFormatOctal:
+                case eFormatDecimal:
+                case eFormatEnum:
+                case eFormatUnicode16:
+                case eFormatUnicode32:
+                case eFormatUnsigned:
+                    if (m_byte_size == 0)
+                        m_byte_size = 4;
+                    if (m_num_per_line == 0)
+                        m_num_per_line = 1;
+                    break;
+
+                case eFormatBytes:
+                case eFormatBytesWithASCII:
+                case eFormatChar:
+                case eFormatCharPrintable:
+                    if (m_byte_size == 0)
+                        m_byte_size = 1;
+                    break;
+                case eFormatComplex:
+                    if (m_byte_size == 0)
+                        m_byte_size = 8;
+                    break;
+                case eFormatHex:
+                    if (m_byte_size == 0)
+                        m_byte_size = 4;
+                    break;
+
+                case eFormatVectorOfChar:
+                case eFormatVectorOfSInt8:
+                case eFormatVectorOfUInt8:
+                case eFormatVectorOfSInt16:
+                case eFormatVectorOfUInt16:
+                case eFormatVectorOfSInt32:
+                case eFormatVectorOfUInt32:
+                case eFormatVectorOfSInt64:
+                case eFormatVectorOfUInt64:
+                case eFormatVectorOfFloat32:
+                case eFormatVectorOfFloat64:
+                case eFormatVectorOfUInt128:
+                    break;
+                }
+                break;
+
+            case 'l':
+                m_num_per_line = Args::StringToUInt32 (option_arg, 0);
+                if (m_num_per_line == 0)
+                    error.SetErrorStringWithFormat("Invalid value for --num-per-line option '%s'. Must be positive integer value.\n", option_arg);
+                break;
+
+            case 'c':
+                m_count = Args::StringToUInt32 (option_arg, 0);
+                if (m_count == 0)
+                    error.SetErrorStringWithFormat("Invalid value for --count option '%s'. Must be positive integer value.\n", option_arg);
+                break;
+
+            case 's':
+                m_byte_size = Args::StringToUInt32 (option_arg, 0);
+                if (m_byte_size == 0)
+                    error.SetErrorStringWithFormat("Invalid value for --size option '%s'. Must be positive integer value.\n", option_arg);
+                break;
+
+            default:
+                error.SetErrorStringWithFormat("Unrecognized short option '%c'.\n", short_option);
+                break;
+            }
+            return error;
+        }
+
+        void
+        ResetOptionValues ()
+        {
+            Options::ResetOptionValues();
+            m_format = eFormatBytesWithASCII;
+            m_byte_size = 0;
+            m_count = 0;
+            m_num_per_line = 0;
+        }
+
+        const lldb::OptionDefinition*
+        GetDefinitions ()
+        {
+            return g_option_table;
+        }
+
+        // Options table: Required for subclasses of Options.
+
+        static lldb::OptionDefinition g_option_table[];
+
+        // Instance variables to hold the values for command options.
+        lldb::Format m_format;
+        uint32_t m_byte_size;
+        uint32_t m_count;
+        uint32_t m_num_per_line;
+    };
+
+    CommandObjectMemoryRead () :
+        CommandObject ("memory read",
+                       "Read memory from the process being debugged.",
+                       "memory read [<cmd-options>] <start-addr> [<end-addr>]",
+                       eFlagProcessMustBeLaunched)
+    {
+    }
+
+    virtual
+    ~CommandObjectMemoryRead ()
+    {
+    }
+
+    Options *
+    GetOptions ()
+    {
+        return &m_options;
+    }
+
+    virtual bool
+    Execute (Args& command,
+             CommandContext *context,
+             CommandInterpreter *interpreter,
+             CommandReturnObject &result)
+    {
+        Process *process = context->GetExecutionContext().process;
+        if (process == NULL)
+        {
+            result.AppendError("need a process to read memory");
+            result.SetStatus(eReturnStatusFailed);
+            return false;
+        }
+        const size_t argc = command.GetArgumentCount();
+
+        if (argc == 0 || argc > 2)
+        {
+            result.AppendErrorWithFormat ("%s takes 1 or two args.\n", m_cmd_name.c_str());
+            result.SetStatus(eReturnStatusFailed);
+            return false;
+        }
+
+        size_t item_byte_size = m_options.m_byte_size;
+        if (item_byte_size == 0)
+        {
+            if (m_options.m_format == eFormatPointer)
+                item_byte_size = process->GetAddressByteSize();
+            else
+                item_byte_size = 1;
+        }
+
+        size_t item_count = m_options.m_count;
+
+        size_t num_per_line = m_options.m_num_per_line;
+        if (num_per_line == 0)
+        {
+            num_per_line = (16/item_byte_size);
+            if (num_per_line == 0)
+                num_per_line = 1;
+        }
+
+        size_t total_byte_size = m_options.m_count * item_byte_size;
+        if (total_byte_size == 0)
+            total_byte_size = 32;
+
+        lldb::addr_t addr = Args::StringToUInt64(command.GetArgumentAtIndex(0), LLDB_INVALID_ADDRESS, 0);
+
+        if (addr == LLDB_INVALID_ADDRESS)
+        {
+            result.AppendErrorWithFormat("invalid start address string '%s'.\n", command.GetArgumentAtIndex(0));
+            result.SetStatus(eReturnStatusFailed);
+            return false;
+        }
+
+        if (argc == 2)
+        {
+            lldb::addr_t end_addr = Args::StringToUInt64(command.GetArgumentAtIndex(1), LLDB_INVALID_ADDRESS, 0);
+            if (end_addr == LLDB_INVALID_ADDRESS)
+            {
+                result.AppendErrorWithFormat("Invalid end address string '%s'.\n", command.GetArgumentAtIndex(1));
+                result.SetStatus(eReturnStatusFailed);
+                return false;
+            }
+            else if (end_addr <= addr)
+            {
+                result.AppendErrorWithFormat("End address (0x%llx) must be greater that the start address (0x%llx).\n", end_addr, addr);
+                result.SetStatus(eReturnStatusFailed);
+                return false;
+            }
+            else if (item_count != 0)
+            {
+                result.AppendErrorWithFormat("Specify either the end address (0x%llx) or the count (--count %u), not both.\n", end_addr, item_count);
+                result.SetStatus(eReturnStatusFailed);
+                return false;
+            }
+
+            total_byte_size = end_addr - addr;
+            item_count = total_byte_size / item_byte_size;
+        }
+        else
+        {
+            if (item_count == 0)
+                item_count = 32;
+        }
+
+        DataBufferSP data_sp(new DataBufferHeap (total_byte_size, '\0'));
+        Error error;
+        size_t bytes_read = process->ReadMemory(addr, data_sp->GetBytes (), data_sp->GetByteSize(), error);
+        if (bytes_read == 0)
+        {
+            result.AppendWarningWithFormat("Read from 0x%llx failed.\n", addr);
+            result.AppendError(error.AsCString());
+            result.SetStatus(eReturnStatusFailed);
+            return false;
+        }
+
+        if (bytes_read < total_byte_size)
+            result.AppendWarningWithFormat("Not all bytes (%u/%u) were able to be read from 0x%llx.\n", bytes_read, total_byte_size, addr);
+
+        result.SetStatus(eReturnStatusSuccessFinishResult);
+        DataExtractor data(data_sp, process->GetByteOrder(), process->GetAddressByteSize());
+
+        Stream &output_stream = result.GetOutputStream();
+        data.Dump(&output_stream,
+                  0,
+                  m_options.m_format,
+                  item_byte_size,
+                  item_count,
+                  num_per_line,
+                  addr,
+                  0,
+                  0);
+        output_stream.EOL();
+        return true;
+    }
+
+protected:
+    CommandOptions m_options;
+};
+
+lldb::OptionDefinition
+CommandObjectMemoryRead::CommandOptions::g_option_table[] =
+{
+    { 0, false, "format",       'f', required_argument, NULL, 0, "<format>",   "The format that will be used to display the memory. Defaults to bytes with ASCII (--format=Y)."},
+    { 0, false, "size",         's', required_argument, NULL, 0, "<byte-size>","The size in bytes to use when displaying with the selected format."},
+    { 0, false, "num-per-line", 'l', required_argument, NULL, 0, "<N>",        "The number of items per line to display."},
+    { 0, false, "count",        'c', required_argument, NULL, 0, "<N>",        "The number of total items to display."},
+    { 0, false, NULL, 0, 0, NULL, 0, NULL, NULL }
+};
+
+
+//----------------------------------------------------------------------
+// Write memory to the inferior process
+//----------------------------------------------------------------------
+class CommandObjectMemoryWrite : public CommandObject
+{
+public:
+
+    class CommandOptions : public Options
+    {
+    public:
+        CommandOptions () :
+            Options()
+        {
+            ResetOptionValues();
+        }
+
+        virtual
+        ~CommandOptions ()
+        {
+        }
+
+        virtual Error
+        SetOptionValue (int option_idx, const char *option_arg)
+        {
+            Error error;
+            char short_option = (char) m_getopt_table[option_idx].val;
+            switch (short_option)
+            {
+            case 'f':
+                error = Args::StringToFormat (option_arg, m_format);
+                break;
+
+            case 's':
+                m_byte_size = Args::StringToUInt32 (option_arg, 0);
+                if (m_byte_size == 0)
+                    error.SetErrorStringWithFormat("Invalid value for --size option '%s'.  Must be positive integer value.\n", option_arg);
+                break;
+
+
+            default:
+                error.SetErrorStringWithFormat("Unrecognized short option '%c'\n", short_option);
+                break;
+            }
+            return error;
+        }
+
+        void
+        ResetOptionValues ()
+        {
+            Options::ResetOptionValues();
+            m_format = eFormatBytes;
+            m_byte_size = 1;
+        }
+
+        const lldb::OptionDefinition*
+        GetDefinitions ()
+        {
+            return g_option_table;
+        }
+
+        // Options table: Required for subclasses of Options.
+
+        static lldb::OptionDefinition g_option_table[];
+
+        // Instance variables to hold the values for command options.
+        lldb::Format m_format;
+        uint32_t m_byte_size;
+    };
+
+    CommandObjectMemoryWrite () :
+        CommandObject ("memory write",
+                       "Write memory to the process being debugged.",
+                       "memory write [<cmd-options>] <addr> [value1 value2 ...]",
+                       eFlagProcessMustBeLaunched)
+    {
+    }
+
+    virtual
+    ~CommandObjectMemoryWrite ()
+    {
+    }
+
+    Options *
+    GetOptions ()
+    {
+        return &m_options;
+    }
+
+    bool
+    UIntValueIsValidForSize (uint64_t uval64, size_t total_byte_size)
+    {
+        if (total_byte_size > 8)
+            return false;
+
+        if (total_byte_size == 8)
+            return true;
+
+        const uint64_t max = ((uint64_t)1 << (uint64_t)(total_byte_size * 8)) - 1;
+        return uval64 <= max;
+    }
+
+    bool
+    SIntValueIsValidForSize (int64_t sval64, size_t total_byte_size)
+    {
+        if (total_byte_size > 8)
+            return false;
+
+        if (total_byte_size == 8)
+            return true;
+
+        const int64_t max = ((int64_t)1 << (uint64_t)(total_byte_size * 8 - 1)) - 1;
+        const int64_t min = ~(max);
+        return min <= sval64 && sval64 <= max;
+    }
+
+    virtual bool
+    Execute (Args& command,
+             CommandContext *context,
+             CommandInterpreter *interpreter,
+             CommandReturnObject &result)
+    {
+        Process *process = context->GetExecutionContext().process;
+        if (process == NULL)
+        {
+            result.AppendError("need a process to read memory");
+            result.SetStatus(eReturnStatusFailed);
+            return false;
+        }
+
+        const size_t argc = command.GetArgumentCount();
+
+        if (argc < 2)
+        {
+            result.AppendErrorWithFormat ("%s takes an address and at least one value.\n", m_cmd_name.c_str());
+            result.SetStatus(eReturnStatusFailed);
+            return false;
+        }
+
+        size_t item_byte_size = m_options.m_byte_size ? m_options.m_byte_size : 1;
+        StreamString buffer (Stream::eBinary,
+                             process->GetAddressByteSize(),
+                             process->GetByteOrder());
+
+        lldb::addr_t addr = Args::StringToUInt64(command.GetArgumentAtIndex(0), LLDB_INVALID_ADDRESS, 0);
+
+        if (addr == LLDB_INVALID_ADDRESS)
+        {
+            result.AppendErrorWithFormat("Invalid address string '%s'.\n", command.GetArgumentAtIndex(0));
+            result.SetStatus(eReturnStatusFailed);
+            return false;
+        }
+        command.Shift(); // shift off the address argument
+        uint64_t uval64;
+        int64_t sval64;
+        bool success = false;
+        const uint32_t num_value_args = command.GetArgumentCount();
+        uint32_t i;
+        for (i=0; i<num_value_args; ++i)
+        {
+            const char *value_str = command.GetArgumentAtIndex(i);
+
+            switch (m_options.m_format)
+            {
+            case eFormatFloat:  // TODO: add support for floats soon
+            case eFormatCharPrintable:
+            case eFormatBytesWithASCII:
+            case eFormatComplex:
+            case eFormatEnum:
+            case eFormatUnicode16:
+            case eFormatUnicode32:
+            case eFormatVectorOfChar:
+            case eFormatVectorOfSInt8:
+            case eFormatVectorOfUInt8:
+            case eFormatVectorOfSInt16:
+            case eFormatVectorOfUInt16:
+            case eFormatVectorOfSInt32:
+            case eFormatVectorOfUInt32:
+            case eFormatVectorOfSInt64:
+            case eFormatVectorOfUInt64:
+            case eFormatVectorOfFloat32:
+            case eFormatVectorOfFloat64:
+            case eFormatVectorOfUInt128:
+                result.AppendError("unsupported format for writing memory");
+                result.SetStatus(eReturnStatusFailed);
+                return false;
+
+            case eFormatDefault:
+            case eFormatBytes:
+            case eFormatHex:
+                // Decode hex bytes
+                uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 16, &success);
+                if (!success)
+                {
+                    result.AppendErrorWithFormat ("'%s' is not a valid hex string value.\n", value_str);
+                    result.SetStatus(eReturnStatusFailed);
+                    return false;
+                }
+                else if (!UIntValueIsValidForSize (uval64, item_byte_size))
+                {
+                    result.AppendErrorWithFormat ("Value 0x%llx is too large to fit in a %u byte unsigned integer value.\n", uval64, item_byte_size);
+                    result.SetStatus(eReturnStatusFailed);
+                    return false;
+                }
+                buffer.PutMaxHex64 (uval64, item_byte_size);
+                break;
+
+            case eFormatBoolean:
+                uval64 = Args::StringToBoolean(value_str, false, &success);
+                if (!success)
+                {
+                    result.AppendErrorWithFormat ("'%s' is not a valid boolean string value.\n", value_str);
+                    result.SetStatus(eReturnStatusFailed);
+                    return false;
+                }
+                buffer.PutMaxHex64 (uval64, item_byte_size);
+                break;
+
+            case eFormatBinary:
+                uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 2, &success);
+                if (!success)
+                {
+                    result.AppendErrorWithFormat ("'%s' is not a valid binary string value.\n", value_str);
+                    result.SetStatus(eReturnStatusFailed);
+                    return false;
+                }
+                else if (!UIntValueIsValidForSize (uval64, item_byte_size))
+                {
+                    result.AppendErrorWithFormat ("Value 0x%llx is too large to fit in a %u byte unsigned integer value.\n", uval64, item_byte_size);
+                    result.SetStatus(eReturnStatusFailed);
+                    return false;
+                }
+                buffer.PutMaxHex64 (uval64, item_byte_size);
+                break;
+
+            case eFormatChar:
+            case eFormatCString:
+                if (value_str[0])
+                {
+                    size_t len = strlen (value_str);
+                    // Include the NULL for C strings...
+                    if (m_options.m_format == eFormatCString)
+                        ++len;
+                    Error error;
+                    if (process->WriteMemory (addr, value_str, len, error) == len)
+                    {
+                        addr += len;
+                    }
+                    else
+                    {
+                        result.AppendErrorWithFormat ("Memory write to 0x%llx failed: %s.\n", addr, error.AsCString());
+                        result.SetStatus(eReturnStatusFailed);
+                        return false;
+                    }
+                }
+                break;
+
+            case eFormatDecimal:
+                sval64 = Args::StringToSInt64(value_str, INT64_MAX, 0, &success);
+                if (!success)
+                {
+                    result.AppendErrorWithFormat ("'%s' is not a valid signed decimal value.\n", value_str);
+                    result.SetStatus(eReturnStatusFailed);
+                    return false;
+                }
+                else if (!SIntValueIsValidForSize (sval64, item_byte_size))
+                {
+                    result.AppendErrorWithFormat ("Value %lli is too large or small to fit in a %u byte signed integer value.\n", sval64, item_byte_size);
+                    result.SetStatus(eReturnStatusFailed);
+                    return false;
+                }
+                buffer.PutMaxHex64 (sval64, item_byte_size);
+                break;
+
+            case eFormatUnsigned:
+                uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 0, &success);
+                if (!success)
+                {
+                    result.AppendErrorWithFormat ("'%s' is not a valid unsigned decimal string value.\n", value_str);
+                    result.SetStatus(eReturnStatusFailed);
+                    return false;
+                }
+                else if (!UIntValueIsValidForSize (uval64, item_byte_size))
+                {
+                    result.AppendErrorWithFormat ("Value %llu is too large to fit in a %u byte unsigned integer value.\n", uval64, item_byte_size);
+                    result.SetStatus(eReturnStatusFailed);
+                    return false;
+                }
+                buffer.PutMaxHex64 (uval64, item_byte_size);
+                break;
+
+            case eFormatOctal:
+                uval64 = Args::StringToUInt64(value_str, UINT64_MAX, 8, &success);
+                if (!success)
+                {
+                    result.AppendErrorWithFormat ("'%s' is not a valid octal string value.\n", value_str);
+                    result.SetStatus(eReturnStatusFailed);
+                    return false;
+                }
+                else if (!UIntValueIsValidForSize (uval64, item_byte_size))
+                {
+                    result.AppendErrorWithFormat ("Value %llo is too large to fit in a %u byte unsigned integer value.\n", uval64, item_byte_size);
+                    result.SetStatus(eReturnStatusFailed);
+                    return false;
+                }
+                buffer.PutMaxHex64 (uval64, item_byte_size);
+                break;
+            }
+        }
+
+        if (!buffer.GetString().empty())
+        {
+            Error error;
+            if (process->WriteMemory (addr, buffer.GetString().data(), buffer.GetString().size(), error) == buffer.GetString().size())
+                return true;
+            else
+            {
+                result.AppendErrorWithFormat ("Memory write to 0x%llx failed: %s.\n", addr, error.AsCString());
+                result.SetStatus(eReturnStatusFailed);
+                return false;
+            }
+        }
+        return true;
+    }
+
+protected:
+    CommandOptions m_options;
+};
+
+lldb::OptionDefinition
+CommandObjectMemoryWrite::CommandOptions::g_option_table[] =
+{
+    { 0, false, "format", 'f', required_argument, NULL, 0, "<format>",   "The format value types that will be decoded and written to memory."},
+    { 0, false, "size",   's', required_argument, NULL, 0, "<byte-size>","The size in bytes of the values to write to memory."},
+    { 0, false, NULL, 0, 0, NULL, 0, NULL, NULL }
+};
+
+
+//-------------------------------------------------------------------------
+// CommandObjectMemory
+//-------------------------------------------------------------------------
+
+CommandObjectMemory::CommandObjectMemory (CommandInterpreter *interpreter) :
+    CommandObjectMultiword ("memory",
+                            "A set of commands for operating on a memory.",
+                            "memory <subcommand> [<subcommand-options>]")
+{
+    LoadSubCommand (CommandObjectSP (new CommandObjectMemoryRead ()), "read", interpreter);
+    LoadSubCommand (CommandObjectSP (new CommandObjectMemoryWrite ()), "write", interpreter);
+}
+
+CommandObjectMemory::~CommandObjectMemory ()
+{
+}