|  | //===-- 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/DataBufferHeap.h" | 
|  | #include "lldb/Core/DataExtractor.h" | 
|  | #include "lldb/Core/Debugger.h" | 
|  | #include "lldb/Core/StreamString.h" | 
|  | #include "lldb/Interpreter/Args.h" | 
|  | #include "lldb/Interpreter/CommandReturnObject.h" | 
|  | #include "lldb/Interpreter/CommandInterpreter.h" | 
|  | #include "lldb/Interpreter/Options.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 (CommandInterpreter &interpreter) : | 
|  | CommandObject (interpreter, | 
|  | "memory read", | 
|  | "Read from the memory of 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, | 
|  | CommandReturnObject &result) | 
|  | { | 
|  | Process *process = m_interpreter.GetDebugger().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[] = | 
|  | { | 
|  | { LLDB_OPT_SET_1, 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)."}, | 
|  | { LLDB_OPT_SET_1, false, "size",         's', required_argument, NULL, 0, "<byte-size>","The size in bytes to use when displaying with the selected format."}, | 
|  | { LLDB_OPT_SET_1, false, "num-per-line", 'l', required_argument, NULL, 0, "<N>",        "The number of items per line to display."}, | 
|  | { LLDB_OPT_SET_1, 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 (CommandInterpreter &interpreter) : | 
|  | CommandObject (interpreter, | 
|  | "memory write", | 
|  | "Write to the memory of 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, | 
|  | CommandReturnObject &result) | 
|  | { | 
|  | Process *process = m_interpreter.GetDebugger().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; | 
|  | } | 
|  |  | 
|  | StreamString buffer (Stream::eBinary, | 
|  | process->GetAddressByteSize(), | 
|  | process->GetByteOrder()); | 
|  |  | 
|  | size_t item_byte_size = m_options.m_byte_size; | 
|  |  | 
|  | if (m_options.m_byte_size == 0) | 
|  | { | 
|  | if (m_options.m_format == eFormatPointer) | 
|  | item_byte_size = buffer.GetAddressByteSize(); | 
|  | else | 
|  | item_byte_size = 1; | 
|  | } | 
|  |  | 
|  | 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: | 
|  | case eFormatPointer: | 
|  |  | 
|  | // 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().c_str(), 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[] = | 
|  | { | 
|  | { LLDB_OPT_SET_1, false, "format", 'f', required_argument, NULL, 0, "<format>",   "The format value types that will be decoded and written to memory."}, | 
|  | { LLDB_OPT_SET_1, 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 (interpreter, | 
|  | "memory", | 
|  | "A set of commands for operating on memory.", | 
|  | "memory <subcommand> [<subcommand-options>]") | 
|  | { | 
|  | LoadSubCommand ("read",  CommandObjectSP (new CommandObjectMemoryRead (interpreter))); | 
|  | LoadSubCommand ("write", CommandObjectSP (new CommandObjectMemoryWrite (interpreter))); | 
|  | } | 
|  |  | 
|  | CommandObjectMemory::~CommandObjectMemory () | 
|  | { | 
|  | } |