diff options
Diffstat (limited to 'lldb/source/Commands/CommandObjectMemory.cpp')
-rw-r--r-- | lldb/source/Commands/CommandObjectMemory.cpp | 3240 |
1 files changed, 1550 insertions, 1690 deletions
diff --git a/lldb/source/Commands/CommandObjectMemory.cpp b/lldb/source/Commands/CommandObjectMemory.cpp index 9c9abc55320..54dfdd1ecef 100644 --- a/lldb/source/Commands/CommandObjectMemory.cpp +++ b/lldb/source/Commands/CommandObjectMemory.cpp @@ -48,10 +48,8 @@ using namespace lldb; using namespace lldb_private; -static OptionDefinition -g_option_table[] = -{ - // clang-format off +static OptionDefinition g_option_table[] = { + // clang-format off {LLDB_OPT_SET_1, false, "num-per-line", 'l', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeNumberPerLine, "The number of items per line to display." }, {LLDB_OPT_SET_2, false, "binary", 'b', OptionParser::eNoArgument, nullptr, nullptr, 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." }, @@ -60,1766 +58,1634 @@ g_option_table[] = {LLDB_OPT_SET_1 | LLDB_OPT_SET_2 | LLDB_OPT_SET_3, false, "force", 'r', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Necessary if reading over target.max-memory-read-size bytes." }, - // clang-format on + // clang-format on }; -class OptionGroupReadMemory : public OptionGroup -{ +class OptionGroupReadMemory : public OptionGroup { public: - OptionGroupReadMemory () : - m_num_per_line (1,1), - m_output_as_binary (false), - m_view_as_type(), - m_offset(0,0) - { - } + OptionGroupReadMemory() + : m_num_per_line(1, 1), m_output_as_binary(false), m_view_as_type(), + m_offset(0, 0) {} - ~OptionGroupReadMemory() override = default; + ~OptionGroupReadMemory() override = default; - uint32_t - GetNumDefinitions () override - { - return sizeof (g_option_table) / sizeof (OptionDefinition); - } - - const OptionDefinition* - GetDefinitions () override - { - return g_option_table; - } - - Error - SetOptionValue (uint32_t option_idx, - const char *option_arg, - ExecutionContext *execution_context) override - { - Error error; - const int short_option = g_option_table[option_idx].short_option; - - switch (short_option) - { - case 'l': - error = m_num_per_line.SetValueFromString (option_arg); - if (m_num_per_line.GetCurrentValue() == 0) - error.SetErrorStringWithFormat("invalid value for --num-per-line option '%s'", option_arg); - break; - - case 'b': - m_output_as_binary = true; - break; - - case 't': - error = m_view_as_type.SetValueFromString (option_arg); - break; - - case 'r': - m_force = true; - break; - - case 'E': - error = m_offset.SetValueFromString(option_arg); - break; - - default: - error.SetErrorStringWithFormat("unrecognized short option '%c'", short_option); - break; - } - return error; - } - - void - OptionParsingStarting(ExecutionContext *execution_context) override - { - m_num_per_line.Clear(); - m_output_as_binary = false; - m_view_as_type.Clear(); - m_force = false; - m_offset.Clear(); + uint32_t GetNumDefinitions() override { + return sizeof(g_option_table) / sizeof(OptionDefinition); + } + + const OptionDefinition *GetDefinitions() override { return g_option_table; } + + Error SetOptionValue(uint32_t option_idx, const char *option_arg, + ExecutionContext *execution_context) override { + Error error; + const int short_option = g_option_table[option_idx].short_option; + + switch (short_option) { + case 'l': + error = m_num_per_line.SetValueFromString(option_arg); + if (m_num_per_line.GetCurrentValue() == 0) + error.SetErrorStringWithFormat( + "invalid value for --num-per-line option '%s'", option_arg); + break; + + case 'b': + m_output_as_binary = true; + break; + + case 't': + error = m_view_as_type.SetValueFromString(option_arg); + break; + + case 'r': + m_force = true; + break; + + case 'E': + error = m_offset.SetValueFromString(option_arg); + break; + + default: + error.SetErrorStringWithFormat("unrecognized short option '%c'", + short_option); + break; } - - Error - FinalizeSettings (Target *target, OptionGroupFormat& format_options) - { - Error error; - OptionValueUInt64 &byte_size_value = format_options.GetByteSizeValue(); - OptionValueUInt64 &count_value = format_options.GetCountValue(); - const bool byte_size_option_set = byte_size_value.OptionWasSet(); - const bool num_per_line_option_set = m_num_per_line.OptionWasSet(); - const bool count_option_set = format_options.GetCountValue().OptionWasSet(); - - switch (format_options.GetFormat()) - { - default: - break; - - case eFormatBoolean: - if (!byte_size_option_set) - byte_size_value = 1; - if (!num_per_line_option_set) - m_num_per_line = 1; - if (!count_option_set) - format_options.GetCountValue() = 8; - break; - - case eFormatCString: - break; - - case eFormatInstruction: - if (count_option_set) - byte_size_value = target->GetArchitecture().GetMaximumOpcodeByteSize(); - m_num_per_line = 1; - break; - - case eFormatAddressInfo: - if (!byte_size_option_set) - byte_size_value = target->GetArchitecture().GetAddressByteSize(); - m_num_per_line = 1; - if (!count_option_set) - format_options.GetCountValue() = 8; - break; - - case eFormatPointer: - byte_size_value = target->GetArchitecture().GetAddressByteSize(); - if (!num_per_line_option_set) - m_num_per_line = 4; - if (!count_option_set) - format_options.GetCountValue() = 8; - break; - - case eFormatBinary: - case eFormatFloat: - case eFormatOctal: - case eFormatDecimal: - case eFormatEnum: - case eFormatUnicode16: - case eFormatUnicode32: - case eFormatUnsigned: - case eFormatHexFloat: - if (!byte_size_option_set) - byte_size_value = 4; - if (!num_per_line_option_set) - m_num_per_line = 1; - if (!count_option_set) - format_options.GetCountValue() = 8; - break; - - case eFormatBytes: - case eFormatBytesWithASCII: - if (byte_size_option_set) - { - if (byte_size_value > 1) - error.SetErrorStringWithFormat( - "display format (bytes/bytes with ASCII) conflicts with the specified byte size %" PRIu64 - "\n" - "\tconsider using a different display format or don't specify the byte size.", - byte_size_value.GetCurrentValue()); - } - else - byte_size_value = 1; - if (!num_per_line_option_set) - m_num_per_line = 16; - if (!count_option_set) - format_options.GetCountValue() = 32; - break; - - case eFormatCharArray: - case eFormatChar: - case eFormatCharPrintable: - if (!byte_size_option_set) - byte_size_value = 1; - if (!num_per_line_option_set) - m_num_per_line = 32; - if (!count_option_set) - format_options.GetCountValue() = 64; - break; - - case eFormatComplex: - if (!byte_size_option_set) - byte_size_value = 8; - if (!num_per_line_option_set) - m_num_per_line = 1; - if (!count_option_set) - format_options.GetCountValue() = 8; - break; - - case eFormatComplexInteger: - if (!byte_size_option_set) - byte_size_value = 8; - if (!num_per_line_option_set) - m_num_per_line = 1; - if (!count_option_set) - format_options.GetCountValue() = 8; - break; - - case eFormatHex: - if (!byte_size_option_set) - byte_size_value = 4; - if (!num_per_line_option_set) - { - switch (byte_size_value) - { - case 1: - case 2: - m_num_per_line = 8; - break; - case 4: - m_num_per_line = 4; - break; - case 8: - m_num_per_line = 2; - break; - default: - m_num_per_line = 1; - break; - } - } - if (!count_option_set) - count_value = 8; - break; - - case eFormatVectorOfChar: - case eFormatVectorOfSInt8: - case eFormatVectorOfUInt8: - case eFormatVectorOfSInt16: - case eFormatVectorOfUInt16: - case eFormatVectorOfSInt32: - case eFormatVectorOfUInt32: - case eFormatVectorOfSInt64: - case eFormatVectorOfUInt64: - case eFormatVectorOfFloat16: - case eFormatVectorOfFloat32: - case eFormatVectorOfFloat64: - case eFormatVectorOfUInt128: - if (!byte_size_option_set) - byte_size_value = 128; - if (!num_per_line_option_set) - m_num_per_line = 1; - if (!count_option_set) - count_value = 4; - break; + return error; + } + + void OptionParsingStarting(ExecutionContext *execution_context) override { + m_num_per_line.Clear(); + m_output_as_binary = false; + m_view_as_type.Clear(); + m_force = false; + m_offset.Clear(); + } + + Error FinalizeSettings(Target *target, OptionGroupFormat &format_options) { + Error error; + OptionValueUInt64 &byte_size_value = format_options.GetByteSizeValue(); + OptionValueUInt64 &count_value = format_options.GetCountValue(); + const bool byte_size_option_set = byte_size_value.OptionWasSet(); + const bool num_per_line_option_set = m_num_per_line.OptionWasSet(); + const bool count_option_set = format_options.GetCountValue().OptionWasSet(); + + switch (format_options.GetFormat()) { + default: + break; + + case eFormatBoolean: + if (!byte_size_option_set) + byte_size_value = 1; + if (!num_per_line_option_set) + m_num_per_line = 1; + if (!count_option_set) + format_options.GetCountValue() = 8; + break; + + case eFormatCString: + break; + + case eFormatInstruction: + if (count_option_set) + byte_size_value = target->GetArchitecture().GetMaximumOpcodeByteSize(); + m_num_per_line = 1; + break; + + case eFormatAddressInfo: + if (!byte_size_option_set) + byte_size_value = target->GetArchitecture().GetAddressByteSize(); + m_num_per_line = 1; + if (!count_option_set) + format_options.GetCountValue() = 8; + break; + + case eFormatPointer: + byte_size_value = target->GetArchitecture().GetAddressByteSize(); + if (!num_per_line_option_set) + m_num_per_line = 4; + if (!count_option_set) + format_options.GetCountValue() = 8; + break; + + case eFormatBinary: + case eFormatFloat: + case eFormatOctal: + case eFormatDecimal: + case eFormatEnum: + case eFormatUnicode16: + case eFormatUnicode32: + case eFormatUnsigned: + case eFormatHexFloat: + if (!byte_size_option_set) + byte_size_value = 4; + if (!num_per_line_option_set) + m_num_per_line = 1; + if (!count_option_set) + format_options.GetCountValue() = 8; + break; + + case eFormatBytes: + case eFormatBytesWithASCII: + if (byte_size_option_set) { + if (byte_size_value > 1) + error.SetErrorStringWithFormat( + "display format (bytes/bytes with ASCII) conflicts with the " + "specified byte size %" PRIu64 "\n" + "\tconsider using a different display format or don't specify " + "the byte size.", + byte_size_value.GetCurrentValue()); + } else + byte_size_value = 1; + if (!num_per_line_option_set) + m_num_per_line = 16; + if (!count_option_set) + format_options.GetCountValue() = 32; + break; + + case eFormatCharArray: + case eFormatChar: + case eFormatCharPrintable: + if (!byte_size_option_set) + byte_size_value = 1; + if (!num_per_line_option_set) + m_num_per_line = 32; + if (!count_option_set) + format_options.GetCountValue() = 64; + break; + + case eFormatComplex: + if (!byte_size_option_set) + byte_size_value = 8; + if (!num_per_line_option_set) + m_num_per_line = 1; + if (!count_option_set) + format_options.GetCountValue() = 8; + break; + + case eFormatComplexInteger: + if (!byte_size_option_set) + byte_size_value = 8; + if (!num_per_line_option_set) + m_num_per_line = 1; + if (!count_option_set) + format_options.GetCountValue() = 8; + break; + + case eFormatHex: + if (!byte_size_option_set) + byte_size_value = 4; + if (!num_per_line_option_set) { + switch (byte_size_value) { + case 1: + case 2: + m_num_per_line = 8; + break; + case 4: + m_num_per_line = 4; + break; + case 8: + m_num_per_line = 2; + break; + default: + m_num_per_line = 1; + break; } - return error; + } + if (!count_option_set) + count_value = 8; + break; + + case eFormatVectorOfChar: + case eFormatVectorOfSInt8: + case eFormatVectorOfUInt8: + case eFormatVectorOfSInt16: + case eFormatVectorOfUInt16: + case eFormatVectorOfSInt32: + case eFormatVectorOfUInt32: + case eFormatVectorOfSInt64: + case eFormatVectorOfUInt64: + case eFormatVectorOfFloat16: + case eFormatVectorOfFloat32: + case eFormatVectorOfFloat64: + case eFormatVectorOfUInt128: + if (!byte_size_option_set) + byte_size_value = 128; + if (!num_per_line_option_set) + m_num_per_line = 1; + if (!count_option_set) + count_value = 4; + break; } + return error; + } - bool - AnyOptionWasSet () const - { - return m_num_per_line.OptionWasSet() || - m_output_as_binary || - m_view_as_type.OptionWasSet() || - m_offset.OptionWasSet(); - } - - OptionValueUInt64 m_num_per_line; - bool m_output_as_binary; - OptionValueString m_view_as_type; - bool m_force; - OptionValueUInt64 m_offset; + bool AnyOptionWasSet() const { + return m_num_per_line.OptionWasSet() || m_output_as_binary || + m_view_as_type.OptionWasSet() || m_offset.OptionWasSet(); + } + + OptionValueUInt64 m_num_per_line; + bool m_output_as_binary; + OptionValueString m_view_as_type; + bool m_force; + OptionValueUInt64 m_offset; }; //---------------------------------------------------------------------- // Read memory from the inferior process //---------------------------------------------------------------------- -class CommandObjectMemoryRead : public CommandObjectParsed -{ +class CommandObjectMemoryRead : public CommandObjectParsed { public: - CommandObjectMemoryRead(CommandInterpreter &interpreter) - : CommandObjectParsed(interpreter, "memory read", "Read from the memory of the current target process.", - nullptr, eCommandRequiresTarget | eCommandProcessMustBePaused), - m_option_group(), - m_format_options(eFormatBytesWithASCII, 1, 8), - m_memory_options(), - m_outfile_options(), - m_varobj_options(), - m_next_addr(LLDB_INVALID_ADDRESS), - m_prev_byte_size(0), - m_prev_format_options(eFormatBytesWithASCII, 1, 8), - m_prev_memory_options(), - m_prev_outfile_options(), - m_prev_varobj_options() - { - CommandArgumentEntry arg1; - CommandArgumentEntry arg2; - CommandArgumentData start_addr_arg; - CommandArgumentData end_addr_arg; - - // Define the first (and only) variant of this arg. - start_addr_arg.arg_type = eArgTypeAddressOrExpression; - start_addr_arg.arg_repetition = eArgRepeatPlain; - - // There is only one variant this argument could be; put it into the argument entry. - arg1.push_back (start_addr_arg); - - // Define the first (and only) variant of this arg. - end_addr_arg.arg_type = eArgTypeAddressOrExpression; - end_addr_arg.arg_repetition = eArgRepeatOptional; - - // There is only one variant this argument could be; put it into the argument entry. - arg2.push_back (end_addr_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back (arg1); - m_arguments.push_back (arg2); - - // Add the "--format" and "--count" options to group 1 and 3 - m_option_group.Append (&m_format_options, - OptionGroupFormat::OPTION_GROUP_FORMAT | OptionGroupFormat::OPTION_GROUP_COUNT, - LLDB_OPT_SET_1 | LLDB_OPT_SET_2 | LLDB_OPT_SET_3); - m_option_group.Append (&m_format_options, - OptionGroupFormat::OPTION_GROUP_GDB_FMT, - LLDB_OPT_SET_1 | LLDB_OPT_SET_3); - // Add the "--size" option to group 1 and 2 - m_option_group.Append (&m_format_options, - OptionGroupFormat::OPTION_GROUP_SIZE, - LLDB_OPT_SET_1 | LLDB_OPT_SET_2); - m_option_group.Append (&m_memory_options); - m_option_group.Append (&m_outfile_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1 | LLDB_OPT_SET_2 | LLDB_OPT_SET_3); - m_option_group.Append (&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_3); - m_option_group.Finalize(); - } + CommandObjectMemoryRead(CommandInterpreter &interpreter) + : CommandObjectParsed( + interpreter, "memory read", + "Read from the memory of the current target process.", nullptr, + eCommandRequiresTarget | eCommandProcessMustBePaused), + m_option_group(), m_format_options(eFormatBytesWithASCII, 1, 8), + m_memory_options(), m_outfile_options(), m_varobj_options(), + m_next_addr(LLDB_INVALID_ADDRESS), m_prev_byte_size(0), + m_prev_format_options(eFormatBytesWithASCII, 1, 8), + m_prev_memory_options(), m_prev_outfile_options(), + m_prev_varobj_options() { + CommandArgumentEntry arg1; + CommandArgumentEntry arg2; + CommandArgumentData start_addr_arg; + CommandArgumentData end_addr_arg; - ~CommandObjectMemoryRead() override = default; + // Define the first (and only) variant of this arg. + start_addr_arg.arg_type = eArgTypeAddressOrExpression; + start_addr_arg.arg_repetition = eArgRepeatPlain; - Options * - GetOptions () override - { - return &m_option_group; - } + // There is only one variant this argument could be; put it into the + // argument entry. + arg1.push_back(start_addr_arg); - const char * - GetRepeatCommand (Args ¤t_command_args, uint32_t index) override - { - return m_cmd_name.c_str(); - } + // Define the first (and only) variant of this arg. + end_addr_arg.arg_type = eArgTypeAddressOrExpression; + end_addr_arg.arg_repetition = eArgRepeatOptional; + + // There is only one variant this argument could be; put it into the + // argument entry. + arg2.push_back(end_addr_arg); + + // Push the data for the first argument into the m_arguments vector. + m_arguments.push_back(arg1); + m_arguments.push_back(arg2); + + // Add the "--format" and "--count" options to group 1 and 3 + m_option_group.Append(&m_format_options, + OptionGroupFormat::OPTION_GROUP_FORMAT | + OptionGroupFormat::OPTION_GROUP_COUNT, + LLDB_OPT_SET_1 | LLDB_OPT_SET_2 | LLDB_OPT_SET_3); + m_option_group.Append(&m_format_options, + OptionGroupFormat::OPTION_GROUP_GDB_FMT, + LLDB_OPT_SET_1 | LLDB_OPT_SET_3); + // Add the "--size" option to group 1 and 2 + m_option_group.Append(&m_format_options, + OptionGroupFormat::OPTION_GROUP_SIZE, + LLDB_OPT_SET_1 | LLDB_OPT_SET_2); + m_option_group.Append(&m_memory_options); + m_option_group.Append(&m_outfile_options, LLDB_OPT_SET_ALL, + LLDB_OPT_SET_1 | LLDB_OPT_SET_2 | LLDB_OPT_SET_3); + m_option_group.Append(&m_varobj_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_3); + m_option_group.Finalize(); + } + + ~CommandObjectMemoryRead() override = default; + + Options *GetOptions() override { return &m_option_group; } + + const char *GetRepeatCommand(Args ¤t_command_args, + uint32_t index) override { + return m_cmd_name.c_str(); + } protected: - bool - DoExecute (Args& command, CommandReturnObject &result) override - { - // No need to check "target" for validity as eCommandRequiresTarget ensures it is valid - Target *target = m_exe_ctx.GetTargetPtr(); - - const size_t argc = command.GetArgumentCount(); - - if ((argc == 0 && m_next_addr == LLDB_INVALID_ADDRESS) || argc > 2) - { - result.AppendErrorWithFormat ("%s takes a start address expression with an optional end address expression.\n", m_cmd_name.c_str()); - result.AppendRawWarning("Expressions should be quoted if they contain spaces or other special characters.\n"); - result.SetStatus(eReturnStatusFailed); - return false; - } + bool DoExecute(Args &command, CommandReturnObject &result) override { + // No need to check "target" for validity as eCommandRequiresTarget ensures + // it is valid + Target *target = m_exe_ctx.GetTargetPtr(); + + const size_t argc = command.GetArgumentCount(); + + if ((argc == 0 && m_next_addr == LLDB_INVALID_ADDRESS) || argc > 2) { + result.AppendErrorWithFormat("%s takes a start address expression with " + "an optional end address expression.\n", + m_cmd_name.c_str()); + result.AppendRawWarning("Expressions should be quoted if they contain " + "spaces or other special characters.\n"); + result.SetStatus(eReturnStatusFailed); + return false; + } - CompilerType clang_ast_type; - Error error; + CompilerType clang_ast_type; + Error error; + + const char *view_as_type_cstr = + m_memory_options.m_view_as_type.GetCurrentValue(); + if (view_as_type_cstr && view_as_type_cstr[0]) { + // We are viewing memory as a type + + SymbolContext sc; + const bool exact_match = false; + TypeList type_list; + uint32_t reference_count = 0; + uint32_t pointer_count = 0; + size_t idx; + +#define ALL_KEYWORDS \ + KEYWORD("const") \ + KEYWORD("volatile") \ + KEYWORD("restrict") \ + KEYWORD("struct") \ + KEYWORD("class") \ + KEYWORD("union") - const char *view_as_type_cstr = m_memory_options.m_view_as_type.GetCurrentValue(); - if (view_as_type_cstr && view_as_type_cstr[0]) - { - // We are viewing memory as a type - - SymbolContext sc; - const bool exact_match = false; - TypeList type_list; - uint32_t reference_count = 0; - uint32_t pointer_count = 0; - size_t idx; - -#define ALL_KEYWORDS \ - KEYWORD("const") \ - KEYWORD("volatile") \ - KEYWORD("restrict") \ - KEYWORD("struct") \ - KEYWORD("class") \ - KEYWORD("union") - #define KEYWORD(s) s, - static const char *g_keywords[] = - { - ALL_KEYWORDS - }; + static const char *g_keywords[] = {ALL_KEYWORDS}; #undef KEYWORD #define KEYWORD(s) (sizeof(s) - 1), - static const int g_keyword_lengths[] = - { - ALL_KEYWORDS - }; + static const int g_keyword_lengths[] = {ALL_KEYWORDS}; #undef KEYWORD - + #undef ALL_KEYWORDS - - static size_t g_num_keywords = sizeof(g_keywords) / sizeof(const char *); - std::string type_str(view_as_type_cstr); - - // Remove all instances of g_keywords that are followed by spaces - for (size_t i = 0; i < g_num_keywords; ++i) - { - const char *keyword = g_keywords[i]; - int keyword_len = g_keyword_lengths[i]; - - idx = 0; - while ((idx = type_str.find (keyword, idx)) != std::string::npos) - { - if (type_str[idx + keyword_len] == ' ' || type_str[idx + keyword_len] == '\t') - { - type_str.erase(idx, keyword_len+1); - idx = 0; - } - else - { - idx += keyword_len; - } - } - } - bool done = type_str.empty(); - // - idx = type_str.find_first_not_of (" \t"); - if (idx > 0 && idx != std::string::npos) - type_str.erase (0, idx); - while (!done) - { - // Strip trailing spaces - if (type_str.empty()) - done = true; - else - { - switch (type_str[type_str.size()-1]) - { - case '*': - ++pointer_count; - LLVM_FALLTHROUGH; - case ' ': - case '\t': - type_str.erase(type_str.size()-1); - break; - - case '&': - if (reference_count == 0) - { - reference_count = 1; - type_str.erase(type_str.size()-1); - } - else - { - result.AppendErrorWithFormat ("invalid type string: '%s'\n", view_as_type_cstr); - result.SetStatus(eReturnStatusFailed); - return false; - } - break; - - default: - done = true; - break; - } - } - } - - llvm::DenseSet<lldb_private::SymbolFile *> searched_symbol_files; - ConstString lookup_type_name(type_str.c_str()); - StackFrame *frame = m_exe_ctx.GetFramePtr(); - if (frame) - { - sc = frame->GetSymbolContext (eSymbolContextModule); - if (sc.module_sp) - { - sc.module_sp->FindTypes (sc, - lookup_type_name, - exact_match, - 1, - searched_symbol_files, - type_list); - } - } - if (type_list.GetSize() == 0) - { - target->GetImages().FindTypes (sc, - lookup_type_name, - exact_match, - 1, - searched_symbol_files, - type_list); - } - if (type_list.GetSize() == 0 && lookup_type_name.GetCString() && *lookup_type_name.GetCString() == '$') - { - if (ClangPersistentVariables *persistent_vars = llvm::dyn_cast_or_null<ClangPersistentVariables>(target->GetPersistentExpressionStateForLanguage(lldb::eLanguageTypeC))) - { - clang::TypeDecl *tdecl = llvm::dyn_cast_or_null<clang::TypeDecl>(persistent_vars->GetPersistentDecl(ConstString(lookup_type_name))); - - if (tdecl) - { - clang_ast_type.SetCompilerType(ClangASTContext::GetASTContext(&tdecl->getASTContext()), - reinterpret_cast<lldb::opaque_compiler_type_t>(const_cast<clang::Type*>(tdecl->getTypeForDecl()))); - } - } + static size_t g_num_keywords = sizeof(g_keywords) / sizeof(const char *); + std::string type_str(view_as_type_cstr); + + // Remove all instances of g_keywords that are followed by spaces + for (size_t i = 0; i < g_num_keywords; ++i) { + const char *keyword = g_keywords[i]; + int keyword_len = g_keyword_lengths[i]; + + idx = 0; + while ((idx = type_str.find(keyword, idx)) != std::string::npos) { + if (type_str[idx + keyword_len] == ' ' || + type_str[idx + keyword_len] == '\t') { + type_str.erase(idx, keyword_len + 1); + idx = 0; + } else { + idx += keyword_len; + } + } + } + bool done = type_str.empty(); + // + idx = type_str.find_first_not_of(" \t"); + if (idx > 0 && idx != std::string::npos) + type_str.erase(0, idx); + while (!done) { + // Strip trailing spaces + if (type_str.empty()) + done = true; + else { + switch (type_str[type_str.size() - 1]) { + case '*': + ++pointer_count; + LLVM_FALLTHROUGH; + case ' ': + case '\t': + type_str.erase(type_str.size() - 1); + break; + + case '&': + if (reference_count == 0) { + reference_count = 1; + type_str.erase(type_str.size() - 1); + } else { + result.AppendErrorWithFormat("invalid type string: '%s'\n", + view_as_type_cstr); + result.SetStatus(eReturnStatusFailed); + return false; } + break; - if (!clang_ast_type.IsValid()) - { - if (type_list.GetSize() == 0) - { - result.AppendErrorWithFormat ("unable to find any types that match the raw type '%s' for full type '%s'\n", - lookup_type_name.GetCString(), - view_as_type_cstr); - result.SetStatus(eReturnStatusFailed); - return false; - } - else - { - TypeSP type_sp (type_list.GetTypeAtIndex(0)); - clang_ast_type = type_sp->GetFullCompilerType (); - } - } - - while (pointer_count > 0) - { - CompilerType pointer_type = clang_ast_type.GetPointerType(); - if (pointer_type.IsValid()) - clang_ast_type = pointer_type; - else - { - result.AppendError ("unable make a pointer type\n"); - result.SetStatus(eReturnStatusFailed); - return false; - } - --pointer_count; - } + default: + done = true; + break; + } + } + } - m_format_options.GetByteSizeValue() = clang_ast_type.GetByteSize(nullptr); - - if (m_format_options.GetByteSizeValue() == 0) - { - result.AppendErrorWithFormat ("unable to get the byte size of the type '%s'\n", - view_as_type_cstr); - result.SetStatus(eReturnStatusFailed); - return false; - } - - if (!m_format_options.GetCountValue().OptionWasSet()) - m_format_options.GetCountValue() = 1; + llvm::DenseSet<lldb_private::SymbolFile *> searched_symbol_files; + ConstString lookup_type_name(type_str.c_str()); + StackFrame *frame = m_exe_ctx.GetFramePtr(); + if (frame) { + sc = frame->GetSymbolContext(eSymbolContextModule); + if (sc.module_sp) { + sc.module_sp->FindTypes(sc, lookup_type_name, exact_match, 1, + searched_symbol_files, type_list); } - else - { - error = m_memory_options.FinalizeSettings (target, m_format_options); + } + if (type_list.GetSize() == 0) { + target->GetImages().FindTypes(sc, lookup_type_name, exact_match, 1, + searched_symbol_files, type_list); + } + + if (type_list.GetSize() == 0 && lookup_type_name.GetCString() && + *lookup_type_name.GetCString() == '$') { + if (ClangPersistentVariables *persistent_vars = + llvm::dyn_cast_or_null<ClangPersistentVariables>( + target->GetPersistentExpressionStateForLanguage( + lldb::eLanguageTypeC))) { + clang::TypeDecl *tdecl = llvm::dyn_cast_or_null<clang::TypeDecl>( + persistent_vars->GetPersistentDecl( + ConstString(lookup_type_name))); + + if (tdecl) { + clang_ast_type.SetCompilerType( + ClangASTContext::GetASTContext(&tdecl->getASTContext()), + reinterpret_cast<lldb::opaque_compiler_type_t>( + const_cast<clang::Type *>(tdecl->getTypeForDecl()))); + } } + } - // Look for invalid combinations of settings - if (error.Fail()) - { - result.AppendError(error.AsCString()); - result.SetStatus(eReturnStatusFailed); - return false; + if (!clang_ast_type.IsValid()) { + if (type_list.GetSize() == 0) { + result.AppendErrorWithFormat("unable to find any types that match " + "the raw type '%s' for full type '%s'\n", + lookup_type_name.GetCString(), + view_as_type_cstr); + result.SetStatus(eReturnStatusFailed); + return false; + } else { + TypeSP type_sp(type_list.GetTypeAtIndex(0)); + clang_ast_type = type_sp->GetFullCompilerType(); } + } - lldb::addr_t addr; - size_t total_byte_size = 0; - if (argc == 0) - { - // Use the last address and byte size and all options as they were - // if no options have been set - addr = m_next_addr; - total_byte_size = m_prev_byte_size; - clang_ast_type = m_prev_clang_ast_type; - if (!m_format_options.AnyOptionWasSet() && - !m_memory_options.AnyOptionWasSet() && - !m_outfile_options.AnyOptionWasSet() && - !m_varobj_options.AnyOptionWasSet()) - { - m_format_options = m_prev_format_options; - m_memory_options = m_prev_memory_options; - m_outfile_options = m_prev_outfile_options; - m_varobj_options = m_prev_varobj_options; - } + while (pointer_count > 0) { + CompilerType pointer_type = clang_ast_type.GetPointerType(); + if (pointer_type.IsValid()) + clang_ast_type = pointer_type; + else { + result.AppendError("unable make a pointer type\n"); + result.SetStatus(eReturnStatusFailed); + return false; } + --pointer_count; + } - size_t item_count = m_format_options.GetCountValue().GetCurrentValue(); + m_format_options.GetByteSizeValue() = clang_ast_type.GetByteSize(nullptr); - // TODO For non-8-bit byte addressable architectures this needs to be - // revisited to fully support all lldb's range of formatting options. - // Furthermore code memory reads (for those architectures) will not - // be correctly formatted even w/o formatting options. - size_t item_byte_size = - target->GetArchitecture().GetDataByteSize() > 1 ? - target->GetArchitecture().GetDataByteSize() : - m_format_options.GetByteSizeValue().GetCurrentValue(); + if (m_format_options.GetByteSizeValue() == 0) { + result.AppendErrorWithFormat( + "unable to get the byte size of the type '%s'\n", + view_as_type_cstr); + result.SetStatus(eReturnStatusFailed); + return false; + } - const size_t num_per_line = m_memory_options.m_num_per_line.GetCurrentValue(); + if (!m_format_options.GetCountValue().OptionWasSet()) + m_format_options.GetCountValue() = 1; + } else { + error = m_memory_options.FinalizeSettings(target, m_format_options); + } - if (total_byte_size == 0) - { - total_byte_size = item_count * item_byte_size; - if (total_byte_size == 0) - total_byte_size = 32; - } + // Look for invalid combinations of settings + if (error.Fail()) { + result.AppendError(error.AsCString()); + result.SetStatus(eReturnStatusFailed); + return false; + } - if (argc > 0) - addr = Args::StringToAddress(&m_exe_ctx, command.GetArgumentAtIndex(0), LLDB_INVALID_ADDRESS, &error); + lldb::addr_t addr; + size_t total_byte_size = 0; + if (argc == 0) { + // Use the last address and byte size and all options as they were + // if no options have been set + addr = m_next_addr; + total_byte_size = m_prev_byte_size; + clang_ast_type = m_prev_clang_ast_type; + if (!m_format_options.AnyOptionWasSet() && + !m_memory_options.AnyOptionWasSet() && + !m_outfile_options.AnyOptionWasSet() && + !m_varobj_options.AnyOptionWasSet()) { + m_format_options = m_prev_format_options; + m_memory_options = m_prev_memory_options; + m_outfile_options = m_prev_outfile_options; + m_varobj_options = m_prev_varobj_options; + } + } - if (addr == LLDB_INVALID_ADDRESS) - { - result.AppendError("invalid start address expression."); - result.AppendError(error.AsCString()); - result.SetStatus(eReturnStatusFailed); - return false; - } + size_t item_count = m_format_options.GetCountValue().GetCurrentValue(); - if (argc == 2) - { - lldb::addr_t end_addr = Args::StringToAddress(&m_exe_ctx, command.GetArgumentAtIndex(1), - LLDB_INVALID_ADDRESS, nullptr); - if (end_addr == LLDB_INVALID_ADDRESS) - { - result.AppendError("invalid end address expression."); - result.AppendError(error.AsCString()); - result.SetStatus(eReturnStatusFailed); - return false; - } - else if (end_addr <= addr) - { - result.AppendErrorWithFormat("end address (0x%" PRIx64 ") must be greater that the start address (0x%" PRIx64 ").\n", end_addr, addr); - result.SetStatus(eReturnStatusFailed); - return false; - } - else if (m_format_options.GetCountValue().OptionWasSet()) - { - result.AppendErrorWithFormat("specify either the end address (0x%" PRIx64 ") or the count (--count %" PRIu64 "), not both.\n", end_addr, (uint64_t)item_count); - result.SetStatus(eReturnStatusFailed); - return false; - } + // TODO For non-8-bit byte addressable architectures this needs to be + // revisited to fully support all lldb's range of formatting options. + // Furthermore code memory reads (for those architectures) will not + // be correctly formatted even w/o formatting options. + size_t item_byte_size = + target->GetArchitecture().GetDataByteSize() > 1 + ? target->GetArchitecture().GetDataByteSize() + : m_format_options.GetByteSizeValue().GetCurrentValue(); - total_byte_size = end_addr - addr; - item_count = total_byte_size / item_byte_size; - } + const size_t num_per_line = + m_memory_options.m_num_per_line.GetCurrentValue(); - uint32_t max_unforced_size = target->GetMaximumMemReadSize(); - - if (total_byte_size > max_unforced_size && !m_memory_options.m_force) - { - result.AppendErrorWithFormat("Normally, \'memory read\' will not read over %" PRIu32 " bytes of data.\n",max_unforced_size); - result.AppendErrorWithFormat("Please use --force to override this restriction just once.\n"); - result.AppendErrorWithFormat("or set target.max-memory-read-size if you will often need a larger limit.\n"); - return false; - } - - DataBufferSP data_sp; - size_t bytes_read = 0; - if (clang_ast_type.GetOpaqueQualType()) - { - // Make sure we don't display our type as ASCII bytes like the default memory read - if (!m_format_options.GetFormatValue().OptionWasSet()) - m_format_options.GetFormatValue().SetCurrentValue(eFormatDefault); - - bytes_read = clang_ast_type.GetByteSize(nullptr) * m_format_options.GetCountValue().GetCurrentValue(); - - if (argc > 0) - addr = addr + (clang_ast_type.GetByteSize(nullptr) * m_memory_options.m_offset.GetCurrentValue()); - } - else if (m_format_options.GetFormatValue().GetCurrentValue() != eFormatCString) - { - data_sp.reset (new DataBufferHeap (total_byte_size, '\0')); - if (data_sp->GetBytes() == nullptr) - { - result.AppendErrorWithFormat ("can't allocate 0x%" PRIx32 " bytes for the memory read buffer, specify a smaller size to read", (uint32_t)total_byte_size); - result.SetStatus(eReturnStatusFailed); - return false; - } + if (total_byte_size == 0) { + total_byte_size = item_count * item_byte_size; + if (total_byte_size == 0) + total_byte_size = 32; + } - Address address(addr, nullptr); - bytes_read = target->ReadMemory(address, false, data_sp->GetBytes (), data_sp->GetByteSize(), error); - if (bytes_read == 0) - { - const char *error_cstr = error.AsCString(); - if (error_cstr && error_cstr[0]) - { - result.AppendError(error_cstr); - } - else - { - result.AppendErrorWithFormat("failed to read memory from 0x%" PRIx64 ".\n", addr); - } - result.SetStatus(eReturnStatusFailed); - return false; - } - - if (bytes_read < total_byte_size) - result.AppendWarningWithFormat("Not all bytes (%" PRIu64 "/%" PRIu64 ") were able to be read from 0x%" PRIx64 ".\n", (uint64_t)bytes_read, (uint64_t)total_byte_size, addr); - } - else - { - // we treat c-strings as a special case because they do not have a fixed size - if (m_format_options.GetByteSizeValue().OptionWasSet() && !m_format_options.HasGDBFormat()) - item_byte_size = m_format_options.GetByteSizeValue().GetCurrentValue(); - else - item_byte_size = target->GetMaximumSizeOfStringSummary(); - if (!m_format_options.GetCountValue().OptionWasSet()) - item_count = 1; - data_sp.reset (new DataBufferHeap ((item_byte_size+1) * item_count, '\0')); // account for NULLs as necessary - if (data_sp->GetBytes() == nullptr) - { - result.AppendErrorWithFormat ("can't allocate 0x%" PRIx64 " bytes for the memory read buffer, specify a smaller size to read", (uint64_t)((item_byte_size+1) * item_count)); - result.SetStatus(eReturnStatusFailed); - return false; - } - uint8_t *data_ptr = data_sp->GetBytes(); - auto data_addr = addr; - auto count = item_count; - item_count = 0; - bool break_on_no_NULL = false; - while (item_count < count) - { - std::string buffer; - buffer.resize(item_byte_size+1,0); - Error error; - size_t read = target->ReadCStringFromMemory(data_addr, &buffer[0], item_byte_size+1, error); - if (error.Fail()) - { - result.AppendErrorWithFormat("failed to read memory from 0x%" PRIx64 ".\n", addr); - result.SetStatus(eReturnStatusFailed); - return false; - } - - if (item_byte_size == read) - { - result.AppendWarningWithFormat("unable to find a NULL terminated string at 0x%" PRIx64 ".Consider increasing the maximum read length.\n", data_addr); - --read; - break_on_no_NULL = true; - } - else - ++read; // account for final NULL byte - - memcpy(data_ptr, &buffer[0], read); - data_ptr += read; - data_addr += read; - bytes_read += read; - item_count++; // if we break early we know we only read item_count strings - - if (break_on_no_NULL) - break; - } - data_sp.reset(new DataBufferHeap(data_sp->GetBytes(),bytes_read+1)); - } + if (argc > 0) + addr = Args::StringToAddress(&m_exe_ctx, command.GetArgumentAtIndex(0), + LLDB_INVALID_ADDRESS, &error); - m_next_addr = addr + bytes_read; - m_prev_byte_size = bytes_read; - m_prev_format_options = m_format_options; - m_prev_memory_options = m_memory_options; - m_prev_outfile_options = m_outfile_options; - m_prev_varobj_options = m_varobj_options; - m_prev_clang_ast_type = clang_ast_type; - - StreamFile outfile_stream; - Stream *output_stream = nullptr; - const FileSpec &outfile_spec = m_outfile_options.GetFile().GetCurrentValue(); - if (outfile_spec) - { - char path[PATH_MAX]; - outfile_spec.GetPath (path, sizeof(path)); - - uint32_t open_options = File::eOpenOptionWrite | File::eOpenOptionCanCreate; - const bool append = m_outfile_options.GetAppend().GetCurrentValue(); - if (append) - open_options |= File::eOpenOptionAppend; - - if (outfile_stream.GetFile ().Open (path, open_options).Success()) - { - if (m_memory_options.m_output_as_binary) - { - const size_t bytes_written = outfile_stream.Write (data_sp->GetBytes(), bytes_read); - if (bytes_written > 0) - { - result.GetOutputStream().Printf ("%zi bytes %s to '%s'\n", - bytes_written, - append ? "appended" : "written", - path); - return true; - } - else - { - result.AppendErrorWithFormat("Failed to write %" PRIu64 " bytes to '%s'.\n", (uint64_t)bytes_read, path); - result.SetStatus(eReturnStatusFailed); - return false; - } - } - else - { - // We are going to write ASCII to the file just point the - // output_stream to our outfile_stream... - output_stream = &outfile_stream; - } - } - else - { - result.AppendErrorWithFormat("Failed to open file '%s' for %s.\n", path, append ? "append" : "write"); - result.SetStatus(eReturnStatusFailed); - return false; - } + if (addr == LLDB_INVALID_ADDRESS) { + result.AppendError("invalid start address expression."); + result.AppendError(error.AsCString()); + result.SetStatus(eReturnStatusFailed); + return false; + } + + if (argc == 2) { + lldb::addr_t end_addr = + Args::StringToAddress(&m_exe_ctx, command.GetArgumentAtIndex(1), + LLDB_INVALID_ADDRESS, nullptr); + if (end_addr == LLDB_INVALID_ADDRESS) { + result.AppendError("invalid end address expression."); + result.AppendError(error.AsCString()); + result.SetStatus(eReturnStatusFailed); + return false; + } else if (end_addr <= addr) { + result.AppendErrorWithFormat( + "end address (0x%" PRIx64 + ") must be greater that the start address (0x%" PRIx64 ").\n", + end_addr, addr); + result.SetStatus(eReturnStatusFailed); + return false; + } else if (m_format_options.GetCountValue().OptionWasSet()) { + result.AppendErrorWithFormat( + "specify either the end address (0x%" PRIx64 + ") or the count (--count %" PRIu64 "), not both.\n", + end_addr, (uint64_t)item_count); + result.SetStatus(eReturnStatusFailed); + return false; + } + + total_byte_size = end_addr - addr; + item_count = total_byte_size / item_byte_size; + } + + uint32_t max_unforced_size = target->GetMaximumMemReadSize(); + + if (total_byte_size > max_unforced_size && !m_memory_options.m_force) { + result.AppendErrorWithFormat( + "Normally, \'memory read\' will not read over %" PRIu32 + " bytes of data.\n", + max_unforced_size); + result.AppendErrorWithFormat( + "Please use --force to override this restriction just once.\n"); + result.AppendErrorWithFormat("or set target.max-memory-read-size if you " + "will often need a larger limit.\n"); + return false; + } + + DataBufferSP data_sp; + size_t bytes_read = 0; + if (clang_ast_type.GetOpaqueQualType()) { + // Make sure we don't display our type as ASCII bytes like the default + // memory read + if (!m_format_options.GetFormatValue().OptionWasSet()) + m_format_options.GetFormatValue().SetCurrentValue(eFormatDefault); + + bytes_read = clang_ast_type.GetByteSize(nullptr) * + m_format_options.GetCountValue().GetCurrentValue(); + + if (argc > 0) + addr = addr + (clang_ast_type.GetByteSize(nullptr) * + m_memory_options.m_offset.GetCurrentValue()); + } else if (m_format_options.GetFormatValue().GetCurrentValue() != + eFormatCString) { + data_sp.reset(new DataBufferHeap(total_byte_size, '\0')); + if (data_sp->GetBytes() == nullptr) { + result.AppendErrorWithFormat( + "can't allocate 0x%" PRIx32 + " bytes for the memory read buffer, specify a smaller size to read", + (uint32_t)total_byte_size); + result.SetStatus(eReturnStatusFailed); + return false; + } + + Address address(addr, nullptr); + bytes_read = target->ReadMemory(address, false, data_sp->GetBytes(), + data_sp->GetByteSize(), error); + if (bytes_read == 0) { + const char *error_cstr = error.AsCString(); + if (error_cstr && error_cstr[0]) { + result.AppendError(error_cstr); + } else { + result.AppendErrorWithFormat( + "failed to read memory from 0x%" PRIx64 ".\n", addr); } - else - { - output_stream = &result.GetOutputStream(); + result.SetStatus(eReturnStatusFailed); + return false; + } + + if (bytes_read < total_byte_size) + result.AppendWarningWithFormat( + "Not all bytes (%" PRIu64 "/%" PRIu64 + ") were able to be read from 0x%" PRIx64 ".\n", + (uint64_t)bytes_read, (uint64_t)total_byte_size, addr); + } else { + // we treat c-strings as a special case because they do not have a fixed + // size + if (m_format_options.GetByteSizeValue().OptionWasSet() && + !m_format_options.HasGDBFormat()) + item_byte_size = m_format_options.GetByteSizeValue().GetCurrentValue(); + else + item_byte_size = target->GetMaximumSizeOfStringSummary(); + if (!m_format_options.GetCountValue().OptionWasSet()) + item_count = 1; + data_sp.reset(new DataBufferHeap((item_byte_size + 1) * item_count, + '\0')); // account for NULLs as necessary + if (data_sp->GetBytes() == nullptr) { + result.AppendErrorWithFormat( + "can't allocate 0x%" PRIx64 + " bytes for the memory read buffer, specify a smaller size to read", + (uint64_t)((item_byte_size + 1) * item_count)); + result.SetStatus(eReturnStatusFailed); + return false; + } + uint8_t *data_ptr = data_sp->GetBytes(); + auto data_addr = addr; + auto count = item_count; + item_count = 0; + bool break_on_no_NULL = false; + while (item_count < count) { + std::string buffer; + buffer.resize(item_byte_size + 1, 0); + Error error; + size_t read = target->ReadCStringFromMemory(data_addr, &buffer[0], + item_byte_size + 1, error); + if (error.Fail()) { + result.AppendErrorWithFormat( + "failed to read memory from 0x%" PRIx64 ".\n", addr); + result.SetStatus(eReturnStatusFailed); + return false; } - ExecutionContextScope *exe_scope = m_exe_ctx.GetBestExecutionContextScope(); - if (clang_ast_type.GetOpaqueQualType()) - { - for (uint32_t i = 0; i<item_count; ++i) - { - addr_t item_addr = addr + (i * item_byte_size); - Address address (item_addr); - StreamString name_strm; - name_strm.Printf ("0x%" PRIx64, item_addr); - ValueObjectSP valobj_sp (ValueObjectMemory::Create (exe_scope, - name_strm.GetString().c_str(), - address, - clang_ast_type)); - if (valobj_sp) - { - Format format = m_format_options.GetFormat(); - if (format != eFormatDefault) - valobj_sp->SetFormat (format); - - DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions(eLanguageRuntimeDescriptionDisplayVerbosityFull,format)); - - valobj_sp->Dump(*output_stream,options); - } - else - { - result.AppendErrorWithFormat ("failed to create a value object for: (%s) %s\n", - view_as_type_cstr, - name_strm.GetString().c_str()); - result.SetStatus(eReturnStatusFailed); - return false; - } - } + if (item_byte_size == read) { + result.AppendWarningWithFormat( + "unable to find a NULL terminated string at 0x%" PRIx64 + ".Consider increasing the maximum read length.\n", + data_addr); + --read; + break_on_no_NULL = true; + } else + ++read; // account for final NULL byte + + memcpy(data_ptr, &buffer[0], read); + data_ptr += read; + data_addr += read; + bytes_read += read; + item_count++; // if we break early we know we only read item_count + // strings + + if (break_on_no_NULL) + break; + } + data_sp.reset(new DataBufferHeap(data_sp->GetBytes(), bytes_read + 1)); + } + + m_next_addr = addr + bytes_read; + m_prev_byte_size = bytes_read; + m_prev_format_options = m_format_options; + m_prev_memory_options = m_memory_options; + m_prev_outfile_options = m_outfile_options; + m_prev_varobj_options = m_varobj_options; + m_prev_clang_ast_type = clang_ast_type; + + StreamFile outfile_stream; + Stream *output_stream = nullptr; + const FileSpec &outfile_spec = + m_outfile_options.GetFile().GetCurrentValue(); + if (outfile_spec) { + char path[PATH_MAX]; + outfile_spec.GetPath(path, sizeof(path)); + + uint32_t open_options = + File::eOpenOptionWrite | File::eOpenOptionCanCreate; + const bool append = m_outfile_options.GetAppend().GetCurrentValue(); + if (append) + open_options |= File::eOpenOptionAppend; + + if (outfile_stream.GetFile().Open(path, open_options).Success()) { + if (m_memory_options.m_output_as_binary) { + const size_t bytes_written = + outfile_stream.Write(data_sp->GetBytes(), bytes_read); + if (bytes_written > 0) { + result.GetOutputStream().Printf( + "%zi bytes %s to '%s'\n", bytes_written, + append ? "appended" : "written", path); return true; + } else { + result.AppendErrorWithFormat("Failed to write %" PRIu64 + " bytes to '%s'.\n", + (uint64_t)bytes_read, path); + result.SetStatus(eReturnStatusFailed); + return false; + } + } else { + // We are going to write ASCII to the file just point the + // output_stream to our outfile_stream... + output_stream = &outfile_stream; } + } else { + result.AppendErrorWithFormat("Failed to open file '%s' for %s.\n", path, + append ? "append" : "write"); + result.SetStatus(eReturnStatusFailed); + return false; + } + } else { + output_stream = &result.GetOutputStream(); + } - result.SetStatus(eReturnStatusSuccessFinishResult); - DataExtractor data (data_sp, - target->GetArchitecture().GetByteOrder(), - target->GetArchitecture().GetAddressByteSize(), - target->GetArchitecture().GetDataByteSize()); - - Format format = m_format_options.GetFormat(); - if ( ( (format == eFormatChar) || (format == eFormatCharPrintable) ) - && (item_byte_size != 1)) - { - // if a count was not passed, or it is 1 - if (!m_format_options.GetCountValue().OptionWasSet() || item_count == 1) - { - // this turns requests such as - // memory read -fc -s10 -c1 *charPtrPtr - // which make no sense (what is a char of size 10?) - // into a request for fetching 10 chars of size 1 from the same memory location - format = eFormatCharArray; - item_count = item_byte_size; - item_byte_size = 1; - } - else - { - // here we passed a count, and it was not 1 - // so we have a byte_size and a count - // we could well multiply those, but instead let's just fail - result.AppendErrorWithFormat("reading memory as characters of size %" PRIu64 " is not supported", (uint64_t)item_byte_size); - result.SetStatus(eReturnStatusFailed); - return false; - } + ExecutionContextScope *exe_scope = m_exe_ctx.GetBestExecutionContextScope(); + if (clang_ast_type.GetOpaqueQualType()) { + for (uint32_t i = 0; i < item_count; ++i) { + addr_t item_addr = addr + (i * item_byte_size); + Address address(item_addr); + StreamString name_strm; + name_strm.Printf("0x%" PRIx64, item_addr); + ValueObjectSP valobj_sp(ValueObjectMemory::Create( + exe_scope, name_strm.GetString().c_str(), address, clang_ast_type)); + if (valobj_sp) { + Format format = m_format_options.GetFormat(); + if (format != eFormatDefault) + valobj_sp->SetFormat(format); + + DumpValueObjectOptions options(m_varobj_options.GetAsDumpOptions( + eLanguageRuntimeDescriptionDisplayVerbosityFull, format)); + + valobj_sp->Dump(*output_stream, options); + } else { + result.AppendErrorWithFormat( + "failed to create a value object for: (%s) %s\n", + view_as_type_cstr, name_strm.GetString().c_str()); + result.SetStatus(eReturnStatusFailed); + return false; } + } + return true; + } - assert (output_stream); - size_t bytes_dumped = data.Dump (output_stream, - 0, - format, - item_byte_size, - item_count, - num_per_line / target->GetArchitecture().GetDataByteSize(), - addr, - 0, - 0, - exe_scope); - m_next_addr = addr + bytes_dumped; - output_stream->EOL(); - return true; + result.SetStatus(eReturnStatusSuccessFinishResult); + DataExtractor data(data_sp, target->GetArchitecture().GetByteOrder(), + target->GetArchitecture().GetAddressByteSize(), + target->GetArchitecture().GetDataByteSize()); + + Format format = m_format_options.GetFormat(); + if (((format == eFormatChar) || (format == eFormatCharPrintable)) && + (item_byte_size != 1)) { + // if a count was not passed, or it is 1 + if (!m_format_options.GetCountValue().OptionWasSet() || item_count == 1) { + // this turns requests such as + // memory read -fc -s10 -c1 *charPtrPtr + // which make no sense (what is a char of size 10?) + // into a request for fetching 10 chars of size 1 from the same memory + // location + format = eFormatCharArray; + item_count = item_byte_size; + item_byte_size = 1; + } else { + // here we passed a count, and it was not 1 + // so we have a byte_size and a count + // we could well multiply those, but instead let's just fail + result.AppendErrorWithFormat( + "reading memory as characters of size %" PRIu64 " is not supported", + (uint64_t)item_byte_size); + result.SetStatus(eReturnStatusFailed); + return false; + } } - OptionGroupOptions m_option_group; - OptionGroupFormat m_format_options; - OptionGroupReadMemory m_memory_options; - OptionGroupOutputFile m_outfile_options; - OptionGroupValueObjectDisplay m_varobj_options; - lldb::addr_t m_next_addr; - lldb::addr_t m_prev_byte_size; - OptionGroupFormat m_prev_format_options; - OptionGroupReadMemory m_prev_memory_options; - OptionGroupOutputFile m_prev_outfile_options; - OptionGroupValueObjectDisplay m_prev_varobj_options; - CompilerType m_prev_clang_ast_type; + assert(output_stream); + size_t bytes_dumped = + data.Dump(output_stream, 0, format, item_byte_size, item_count, + num_per_line / target->GetArchitecture().GetDataByteSize(), + addr, 0, 0, exe_scope); + m_next_addr = addr + bytes_dumped; + output_stream->EOL(); + return true; + } + + OptionGroupOptions m_option_group; + OptionGroupFormat m_format_options; + OptionGroupReadMemory m_memory_options; + OptionGroupOutputFile m_outfile_options; + OptionGroupValueObjectDisplay m_varobj_options; + lldb::addr_t m_next_addr; + lldb::addr_t m_prev_byte_size; + OptionGroupFormat m_prev_format_options; + OptionGroupReadMemory m_prev_memory_options; + OptionGroupOutputFile m_prev_outfile_options; + OptionGroupValueObjectDisplay m_prev_varobj_options; + CompilerType m_prev_clang_ast_type; }; -OptionDefinition -g_memory_find_option_table[] = -{ - // clang-format off +OptionDefinition g_memory_find_option_table[] = { + // clang-format off {LLDB_OPT_SET_1, true, "expression", 'e', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeExpression, "Evaluate an expression to obtain a byte pattern."}, {LLDB_OPT_SET_2, true, "string", 's', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeName, "Use text to find a byte pattern."}, {LLDB_OPT_SET_ALL, false, "count", 'c', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeCount, "How many times to perform the search."}, {LLDB_OPT_SET_ALL, false, "dump-offset", 'o', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeOffset, "When dumping memory for a match, an offset from the match location to start dumping from."}, - // clang-format on + // clang-format on }; //---------------------------------------------------------------------- // Find the specified data in memory //---------------------------------------------------------------------- -class CommandObjectMemoryFind : public CommandObjectParsed -{ +class CommandObjectMemoryFind : public CommandObjectParsed { public: - class OptionGroupFindMemory : public OptionGroup - { + class OptionGroupFindMemory : public OptionGroup { public: - OptionGroupFindMemory () : - OptionGroup(), - m_count(1), - m_offset(0) - { - } + OptionGroupFindMemory() : OptionGroup(), m_count(1), m_offset(0) {} ~OptionGroupFindMemory() override = default; - uint32_t - GetNumDefinitions () override - { - return sizeof (g_memory_find_option_table) / sizeof (OptionDefinition); + uint32_t GetNumDefinitions() override { + return sizeof(g_memory_find_option_table) / sizeof(OptionDefinition); } - - const OptionDefinition* - GetDefinitions () override - { + + const OptionDefinition *GetDefinitions() override { return g_memory_find_option_table; } - - Error - SetOptionValue (uint32_t option_idx, - const char *option_arg, - ExecutionContext *execution_context) override - { - Error error; - const int short_option = g_memory_find_option_table[option_idx].short_option; - - switch (short_option) - { - case 'e': - m_expr.SetValueFromString(option_arg); - break; - - case 's': - m_string.SetValueFromString(option_arg); - break; - - case 'c': - if (m_count.SetValueFromString(option_arg).Fail()) - error.SetErrorString("unrecognized value for count"); - break; - - case 'o': - if (m_offset.SetValueFromString(option_arg).Fail()) - error.SetErrorString("unrecognized value for dump-offset"); - break; - default: - error.SetErrorStringWithFormat("unrecognized short option '%c'", short_option); - break; - } - return error; + Error SetOptionValue(uint32_t option_idx, const char *option_arg, + ExecutionContext *execution_context) override { + Error error; + const int short_option = + g_memory_find_option_table[option_idx].short_option; + + switch (short_option) { + case 'e': + m_expr.SetValueFromString(option_arg); + break; + + case 's': + m_string.SetValueFromString(option_arg); + break; + + case 'c': + if (m_count.SetValueFromString(option_arg).Fail()) + error.SetErrorString("unrecognized value for count"); + break; + + case 'o': + if (m_offset.SetValueFromString(option_arg).Fail()) + error.SetErrorString("unrecognized value for dump-offset"); + break; + + default: + error.SetErrorStringWithFormat("unrecognized short option '%c'", + short_option); + break; + } + return error; } - - void - OptionParsingStarting(ExecutionContext *execution_context) override - { - m_expr.Clear(); - m_string.Clear(); - m_count.Clear(); + + void OptionParsingStarting(ExecutionContext *execution_context) override { + m_expr.Clear(); + m_string.Clear(); + m_count.Clear(); } - - OptionValueString m_expr; - OptionValueString m_string; - OptionValueUInt64 m_count; - OptionValueUInt64 m_offset; + + OptionValueString m_expr; + OptionValueString m_string; + OptionValueUInt64 m_count; + OptionValueUInt64 m_offset; }; CommandObjectMemoryFind(CommandInterpreter &interpreter) - : CommandObjectParsed(interpreter, "memory find", "Find a value in the memory of the current target process.", - nullptr, eCommandRequiresProcess | eCommandProcessMustBeLaunched), - m_option_group(), - m_memory_options() - { + : CommandObjectParsed( + interpreter, "memory find", + "Find a value in the memory of the current target process.", + nullptr, eCommandRequiresProcess | eCommandProcessMustBeLaunched), + m_option_group(), m_memory_options() { CommandArgumentEntry arg1; CommandArgumentEntry arg2; CommandArgumentData addr_arg; CommandArgumentData value_arg; - + // Define the first (and only) variant of this arg. addr_arg.arg_type = eArgTypeAddressOrExpression; addr_arg.arg_repetition = eArgRepeatPlain; - - // There is only one variant this argument could be; put it into the argument entry. - arg1.push_back (addr_arg); - + + // There is only one variant this argument could be; put it into the + // argument entry. + arg1.push_back(addr_arg); + // Define the first (and only) variant of this arg. value_arg.arg_type = eArgTypeAddressOrExpression; value_arg.arg_repetition = eArgRepeatPlain; - - // There is only one variant this argument could be; put it into the argument entry. - arg2.push_back (value_arg); - + + // There is only one variant this argument could be; put it into the + // argument entry. + arg2.push_back(value_arg); + // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back (arg1); - m_arguments.push_back (arg2); - - m_option_group.Append (&m_memory_options); + m_arguments.push_back(arg1); + m_arguments.push_back(arg2); + + m_option_group.Append(&m_memory_options); m_option_group.Finalize(); } ~CommandObjectMemoryFind() override = default; - Options * - GetOptions () override - { - return &m_option_group; - } - + Options *GetOptions() override { return &m_option_group; } + protected: - class ProcessMemoryIterator - { + class ProcessMemoryIterator { public: - ProcessMemoryIterator (ProcessSP process_sp, - lldb::addr_t base) : - m_process_sp(process_sp), - m_base_addr(base), - m_is_valid(true) - { - lldbassert(process_sp.get() != nullptr); - } - - bool - IsValid () - { - return m_is_valid; - } - - uint8_t - operator [](lldb::addr_t offset) - { - if (!IsValid()) - return 0; - - uint8_t retval = 0; - Error error; - if (0 == m_process_sp->ReadMemory(m_base_addr+offset, &retval, 1, error)) - { - m_is_valid = false; - return 0; - } + ProcessMemoryIterator(ProcessSP process_sp, lldb::addr_t base) + : m_process_sp(process_sp), m_base_addr(base), m_is_valid(true) { + lldbassert(process_sp.get() != nullptr); + } - return retval; + bool IsValid() { return m_is_valid; } + + uint8_t operator[](lldb::addr_t offset) { + if (!IsValid()) + return 0; + + uint8_t retval = 0; + Error error; + if (0 == + m_process_sp->ReadMemory(m_base_addr + offset, &retval, 1, error)) { + m_is_valid = false; + return 0; } + + return retval; + } + private: - ProcessSP m_process_sp; - lldb::addr_t m_base_addr; - bool m_is_valid; + ProcessSP m_process_sp; + lldb::addr_t m_base_addr; + bool m_is_valid; }; - bool - DoExecute (Args& command, CommandReturnObject &result) override - { - // No need to check "process" for validity as eCommandRequiresProcess ensures it is valid - Process *process = m_exe_ctx.GetProcessPtr(); + bool DoExecute(Args &command, CommandReturnObject &result) override { + // No need to check "process" for validity as eCommandRequiresProcess + // ensures it is valid + Process *process = m_exe_ctx.GetProcessPtr(); - const size_t argc = command.GetArgumentCount(); + const size_t argc = command.GetArgumentCount(); - if (argc != 2) - { - result.AppendError("two addresses needed for memory find"); - return false; - } + if (argc != 2) { + result.AppendError("two addresses needed for memory find"); + return false; + } - Error error; - lldb::addr_t low_addr = Args::StringToAddress(&m_exe_ctx, command.GetArgumentAtIndex(0),LLDB_INVALID_ADDRESS,&error); - if (low_addr == LLDB_INVALID_ADDRESS || error.Fail()) - { - result.AppendError("invalid low address"); + Error error; + lldb::addr_t low_addr = + Args::StringToAddress(&m_exe_ctx, command.GetArgumentAtIndex(0), + LLDB_INVALID_ADDRESS, &error); + if (low_addr == LLDB_INVALID_ADDRESS || error.Fail()) { + result.AppendError("invalid low address"); + return false; + } + lldb::addr_t high_addr = + Args::StringToAddress(&m_exe_ctx, command.GetArgumentAtIndex(1), + LLDB_INVALID_ADDRESS, &error); + if (high_addr == LLDB_INVALID_ADDRESS || error.Fail()) { + result.AppendError("invalid high address"); + return false; + } + + if (high_addr <= low_addr) { + result.AppendError( + "starting address must be smaller than ending address"); + return false; + } + + lldb::addr_t found_location = LLDB_INVALID_ADDRESS; + + DataBufferHeap buffer; + + if (m_memory_options.m_string.OptionWasSet()) + buffer.CopyData(m_memory_options.m_string.GetStringValue(), + strlen(m_memory_options.m_string.GetStringValue())); + else if (m_memory_options.m_expr.OptionWasSet()) { + StackFrame *frame = m_exe_ctx.GetFramePtr(); + ValueObjectSP result_sp; + if ((eExpressionCompleted == + process->GetTarget().EvaluateExpression( + m_memory_options.m_expr.GetStringValue(), frame, result_sp)) && + result_sp) { + uint64_t value = result_sp->GetValueAsUnsigned(0); + switch (result_sp->GetCompilerType().GetByteSize(nullptr)) { + case 1: { + uint8_t byte = (uint8_t)value; + buffer.CopyData(&byte, 1); + } break; + case 2: { + uint16_t word = (uint16_t)value; + buffer.CopyData(&word, 2); + } break; + case 4: { + uint32_t lword = (uint32_t)value; + buffer.CopyData(&lword, 4); + } break; + case 8: { + buffer.CopyData(&value, 8); + } break; + case 3: + case 5: + case 6: + case 7: + result.AppendError("unknown type. pass a string instead"); return false; - } - lldb::addr_t high_addr = Args::StringToAddress(&m_exe_ctx, command.GetArgumentAtIndex(1),LLDB_INVALID_ADDRESS,&error); - if (high_addr == LLDB_INVALID_ADDRESS || error.Fail()) - { - result.AppendError("invalid high address"); + default: + result.AppendError( + "result size larger than 8 bytes. pass a string instead"); return false; + } + } else { + result.AppendError( + "expression evaluation failed. pass a string instead"); + return false; } + } else { + result.AppendError( + "please pass either a block of text, or an expression to evaluate."); + return false; + } - if (high_addr <= low_addr) - { - result.AppendError("starting address must be smaller than ending address"); - return false; + size_t count = m_memory_options.m_count.GetCurrentValue(); + found_location = low_addr; + bool ever_found = false; + while (count) { + found_location = FastSearch(found_location, high_addr, buffer.GetBytes(), + buffer.GetByteSize()); + if (found_location == LLDB_INVALID_ADDRESS) { + if (!ever_found) { + result.AppendMessage("data not found within the range.\n"); + result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult); + } else + result.AppendMessage("no more matches within the range.\n"); + break; } - - lldb::addr_t found_location = LLDB_INVALID_ADDRESS; - - DataBufferHeap buffer; - - if (m_memory_options.m_string.OptionWasSet()) - buffer.CopyData(m_memory_options.m_string.GetStringValue(), strlen(m_memory_options.m_string.GetStringValue())); - else if (m_memory_options.m_expr.OptionWasSet()) - { - StackFrame* frame = m_exe_ctx.GetFramePtr(); - ValueObjectSP result_sp; - if ((eExpressionCompleted == process->GetTarget().EvaluateExpression(m_memory_options.m_expr.GetStringValue(), frame, result_sp)) && - result_sp) - { - uint64_t value = result_sp->GetValueAsUnsigned(0); - switch (result_sp->GetCompilerType().GetByteSize(nullptr)) - { - case 1: { - uint8_t byte = (uint8_t)value; - buffer.CopyData(&byte,1); - } - break; - case 2: { - uint16_t word = (uint16_t)value; - buffer.CopyData(&word,2); - } - break; - case 4: { - uint32_t lword = (uint32_t)value; - buffer.CopyData(&lword,4); - } - break; - case 8: { - buffer.CopyData(&value, 8); - } - break; - case 3: - case 5: - case 6: - case 7: - result.AppendError("unknown type. pass a string instead"); - return false; - default: - result.AppendError("result size larger than 8 bytes. pass a string instead"); - return false; - } - } - else - { - result.AppendError("expression evaluation failed. pass a string instead"); - return false; - } + result.AppendMessageWithFormat("data found at location: 0x%" PRIx64 "\n", + found_location); + + DataBufferHeap dumpbuffer(32, 0); + process->ReadMemory( + found_location + m_memory_options.m_offset.GetCurrentValue(), + dumpbuffer.GetBytes(), dumpbuffer.GetByteSize(), error); + if (!error.Fail()) { + DataExtractor data(dumpbuffer.GetBytes(), dumpbuffer.GetByteSize(), + process->GetByteOrder(), + process->GetAddressByteSize()); + data.Dump(&result.GetOutputStream(), 0, lldb::eFormatBytesWithASCII, 1, + dumpbuffer.GetByteSize(), 16, + found_location + m_memory_options.m_offset.GetCurrentValue(), + 0, 0); + result.GetOutputStream().EOL(); } - else - { - result.AppendError("please pass either a block of text, or an expression to evaluate."); - return false; - } - - size_t count = m_memory_options.m_count.GetCurrentValue(); - found_location = low_addr; - bool ever_found = false; - while (count) - { - found_location = FastSearch(found_location, high_addr, buffer.GetBytes(), buffer.GetByteSize()); - if (found_location == LLDB_INVALID_ADDRESS) - { - if (!ever_found) - { - result.AppendMessage("data not found within the range.\n"); - result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult); - } - else - result.AppendMessage("no more matches within the range.\n"); - break; - } - result.AppendMessageWithFormat("data found at location: 0x%" PRIx64 "\n", found_location); - - DataBufferHeap dumpbuffer(32,0); - process->ReadMemory(found_location+m_memory_options.m_offset.GetCurrentValue(), dumpbuffer.GetBytes(), dumpbuffer.GetByteSize(), error); - if (!error.Fail()) - { - DataExtractor data(dumpbuffer.GetBytes(), dumpbuffer.GetByteSize(), process->GetByteOrder(), process->GetAddressByteSize()); - data.Dump(&result.GetOutputStream(), 0, lldb::eFormatBytesWithASCII, 1, dumpbuffer.GetByteSize(), 16, found_location+m_memory_options.m_offset.GetCurrentValue(), 0, 0); - result.GetOutputStream().EOL(); - } - --count; - found_location++; - ever_found = true; - } - - result.SetStatus(lldb::eReturnStatusSuccessFinishResult); - return true; + --count; + found_location++; + ever_found = true; + } + + result.SetStatus(lldb::eReturnStatusSuccessFinishResult); + return true; } - - lldb::addr_t - FastSearch (lldb::addr_t low, - lldb::addr_t high, - uint8_t *buffer, - size_t buffer_size) - { - const size_t region_size = high-low; - - if (region_size < buffer_size) - return LLDB_INVALID_ADDRESS; - - std::vector<size_t> bad_char_heuristic(256, buffer_size); - ProcessSP process_sp = m_exe_ctx.GetProcessSP(); - ProcessMemoryIterator iterator(process_sp, low); - - for (size_t idx = 0; - idx < buffer_size-1; - idx++) - { - decltype(bad_char_heuristic)::size_type bcu_idx = buffer[idx]; - bad_char_heuristic[bcu_idx] = buffer_size - idx - 1; - } - for (size_t s = 0; - s <= (region_size - buffer_size); - ) - { - int64_t j = buffer_size-1; - while (j >= 0 && buffer[j] == iterator[s + j]) - j--; - if (j < 0) - return low+s; - else - s += bad_char_heuristic[iterator[s + buffer_size - 1]]; - } - - return LLDB_INVALID_ADDRESS; + + lldb::addr_t FastSearch(lldb::addr_t low, lldb::addr_t high, uint8_t *buffer, + size_t buffer_size) { + const size_t region_size = high - low; + + if (region_size < buffer_size) + return LLDB_INVALID_ADDRESS; + + std::vector<size_t> bad_char_heuristic(256, buffer_size); + ProcessSP process_sp = m_exe_ctx.GetProcessSP(); + ProcessMemoryIterator iterator(process_sp, low); + + for (size_t idx = 0; idx < buffer_size - 1; idx++) { + decltype(bad_char_heuristic)::size_type bcu_idx = buffer[idx]; + bad_char_heuristic[bcu_idx] = buffer_size - idx - 1; } - - OptionGroupOptions m_option_group; - OptionGroupFindMemory m_memory_options; + for (size_t s = 0; s <= (region_size - buffer_size);) { + int64_t j = buffer_size - 1; + while (j >= 0 && buffer[j] == iterator[s + j]) + j--; + if (j < 0) + return low + s; + else + s += bad_char_heuristic[iterator[s + buffer_size - 1]]; + } + + return LLDB_INVALID_ADDRESS; + } + + OptionGroupOptions m_option_group; + OptionGroupFindMemory m_memory_options; }; -OptionDefinition -g_memory_write_option_table[] = -{ - // clang-format off +OptionDefinition g_memory_write_option_table[] = { + // clang-format off {LLDB_OPT_SET_1, true, "infile", 'i', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeFilename, "Write memory using the contents of a file."}, {LLDB_OPT_SET_1, false, "offset", 'o', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeOffset, "Start writing bytes from an offset within the input file."}, - // clang-format on + // clang-format on }; //---------------------------------------------------------------------- // Write memory to the inferior process //---------------------------------------------------------------------- -class CommandObjectMemoryWrite : public CommandObjectParsed -{ +class CommandObjectMemoryWrite : public CommandObjectParsed { public: - class OptionGroupWriteMemory : public OptionGroup - { - public: - OptionGroupWriteMemory () : - OptionGroup() - { - } + class OptionGroupWriteMemory : public OptionGroup { + public: + OptionGroupWriteMemory() : OptionGroup() {} - ~OptionGroupWriteMemory() override = default; + ~OptionGroupWriteMemory() override = default; - uint32_t - GetNumDefinitions () override - { - return sizeof (g_memory_write_option_table) / sizeof (OptionDefinition); - } - - const OptionDefinition* - GetDefinitions () override - { - return g_memory_write_option_table; - } - - Error - SetOptionValue (uint32_t option_idx, - const char *option_arg, - ExecutionContext *execution_context) override - { - Error error; - const int short_option = g_memory_write_option_table[option_idx].short_option; - - switch (short_option) - { - case 'i': - m_infile.SetFile (option_arg, true); - if (!m_infile.Exists()) - { - m_infile.Clear(); - error.SetErrorStringWithFormat("input file does not exist: '%s'", option_arg); - } - break; - - case 'o': - { - bool success; - m_infile_offset = StringConvert::ToUInt64(option_arg, 0, 0, &success); - if (!success) - { - error.SetErrorStringWithFormat("invalid offset string '%s'", option_arg); - } - } - break; - - default: - error.SetErrorStringWithFormat("unrecognized short option '%c'", short_option); - break; - } - return error; + uint32_t GetNumDefinitions() override { + return sizeof(g_memory_write_option_table) / sizeof(OptionDefinition); + } + + const OptionDefinition *GetDefinitions() override { + return g_memory_write_option_table; + } + + Error SetOptionValue(uint32_t option_idx, const char *option_arg, + ExecutionContext *execution_context) override { + Error error; + const int short_option = + g_memory_write_option_table[option_idx].short_option; + + switch (short_option) { + case 'i': + m_infile.SetFile(option_arg, true); + if (!m_infile.Exists()) { + m_infile.Clear(); + error.SetErrorStringWithFormat("input file does not exist: '%s'", + option_arg); } - - void - OptionParsingStarting(ExecutionContext *execution_context) override - { - m_infile.Clear(); - m_infile_offset = 0; + break; + + case 'o': { + bool success; + m_infile_offset = StringConvert::ToUInt64(option_arg, 0, 0, &success); + if (!success) { + error.SetErrorStringWithFormat("invalid offset string '%s'", + option_arg); } + } break; - FileSpec m_infile; - off_t m_infile_offset; - }; - - CommandObjectMemoryWrite(CommandInterpreter &interpreter) - : CommandObjectParsed(interpreter, "memory write", "Write to the memory of the current target process.", - nullptr, eCommandRequiresProcess | eCommandProcessMustBeLaunched), - m_option_group(), - m_format_options(eFormatBytes, 1, UINT64_MAX), - m_memory_options() - { - CommandArgumentEntry arg1; - CommandArgumentEntry arg2; - CommandArgumentData addr_arg; - CommandArgumentData value_arg; - - // Define the first (and only) variant of this arg. - addr_arg.arg_type = eArgTypeAddress; - addr_arg.arg_repetition = eArgRepeatPlain; - - // There is only one variant this argument could be; put it into the argument entry. - arg1.push_back (addr_arg); - - // Define the first (and only) variant of this arg. - value_arg.arg_type = eArgTypeValue; - value_arg.arg_repetition = eArgRepeatPlus; - - // There is only one variant this argument could be; put it into the argument entry. - arg2.push_back (value_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back (arg1); - m_arguments.push_back (arg2); - - m_option_group.Append (&m_format_options, OptionGroupFormat::OPTION_GROUP_FORMAT, LLDB_OPT_SET_1); - m_option_group.Append (&m_format_options, OptionGroupFormat::OPTION_GROUP_SIZE , LLDB_OPT_SET_1|LLDB_OPT_SET_2); - m_option_group.Append (&m_memory_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_2); - m_option_group.Finalize(); + default: + error.SetErrorStringWithFormat("unrecognized short option '%c'", + short_option); + break; + } + return error; } - ~CommandObjectMemoryWrite() override = default; - - Options * - GetOptions () override - { - return &m_option_group; + void OptionParsingStarting(ExecutionContext *execution_context) override { + m_infile.Clear(); + m_infile_offset = 0; } - bool - UIntValueIsValidForSize (uint64_t uval64, size_t total_byte_size) - { - if (total_byte_size > 8) - return false; + FileSpec m_infile; + off_t m_infile_offset; + }; - if (total_byte_size == 8) - return true; + CommandObjectMemoryWrite(CommandInterpreter &interpreter) + : CommandObjectParsed( + interpreter, "memory write", + "Write to the memory of the current target process.", nullptr, + eCommandRequiresProcess | eCommandProcessMustBeLaunched), + m_option_group(), m_format_options(eFormatBytes, 1, UINT64_MAX), + m_memory_options() { + CommandArgumentEntry arg1; + CommandArgumentEntry arg2; + CommandArgumentData addr_arg; + CommandArgumentData value_arg; - const uint64_t max = ((uint64_t)1 << (uint64_t)(total_byte_size * 8)) - 1; - return uval64 <= max; + // Define the first (and only) variant of this arg. + addr_arg.arg_type = eArgTypeAddress; + addr_arg.arg_repetition = eArgRepeatPlain; + + // There is only one variant this argument could be; put it into the + // argument entry. + arg1.push_back(addr_arg); + + // Define the first (and only) variant of this arg. + value_arg.arg_type = eArgTypeValue; + value_arg.arg_repetition = eArgRepeatPlus; + + // There is only one variant this argument could be; put it into the + // argument entry. + arg2.push_back(value_arg); + + // Push the data for the first argument into the m_arguments vector. + m_arguments.push_back(arg1); + m_arguments.push_back(arg2); + + m_option_group.Append(&m_format_options, + OptionGroupFormat::OPTION_GROUP_FORMAT, + LLDB_OPT_SET_1); + m_option_group.Append(&m_format_options, + OptionGroupFormat::OPTION_GROUP_SIZE, + LLDB_OPT_SET_1 | LLDB_OPT_SET_2); + m_option_group.Append(&m_memory_options, LLDB_OPT_SET_ALL, LLDB_OPT_SET_2); + m_option_group.Finalize(); + } + + ~CommandObjectMemoryWrite() override = default; + + Options *GetOptions() override { return &m_option_group; } + + 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; + } + +protected: + bool DoExecute(Args &command, CommandReturnObject &result) override { + // No need to check "process" for validity as eCommandRequiresProcess + // ensures it is valid + Process *process = m_exe_ctx.GetProcessPtr(); + + const size_t argc = command.GetArgumentCount(); + + if (m_memory_options.m_infile) { + if (argc < 1) { + result.AppendErrorWithFormat( + "%s takes a destination address when writing file contents.\n", + m_cmd_name.c_str()); + result.SetStatus(eReturnStatusFailed); + return false; + } + } else if (argc < 2) { + result.AppendErrorWithFormat( + "%s takes a destination address and at least one value.\n", + m_cmd_name.c_str()); + result.SetStatus(eReturnStatusFailed); + return false; } - bool - SIntValueIsValidForSize (int64_t sval64, size_t total_byte_size) - { - if (total_byte_size > 8) - return false; + StreamString buffer( + Stream::eBinary, + process->GetTarget().GetArchitecture().GetAddressByteSize(), + process->GetTarget().GetArchitecture().GetByteOrder()); - if (total_byte_size == 8) - return true; + OptionValueUInt64 &byte_size_value = m_format_options.GetByteSizeValue(); + size_t item_byte_size = byte_size_value.GetCurrentValue(); + + Error error; + lldb::addr_t addr = + Args::StringToAddress(&m_exe_ctx, command.GetArgumentAtIndex(0), + LLDB_INVALID_ADDRESS, &error); - 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; + if (addr == LLDB_INVALID_ADDRESS) { + result.AppendError("invalid address expression\n"); + result.AppendError(error.AsCString()); + result.SetStatus(eReturnStatusFailed); + return false; } -protected: - bool - DoExecute (Args& command, CommandReturnObject &result) override - { - // No need to check "process" for validity as eCommandRequiresProcess ensures it is valid - Process *process = m_exe_ctx.GetProcessPtr(); - - const size_t argc = command.GetArgumentCount(); - - if (m_memory_options.m_infile) - { - if (argc < 1) - { - result.AppendErrorWithFormat ("%s takes a destination address when writing file contents.\n", m_cmd_name.c_str()); - result.SetStatus(eReturnStatusFailed); - return false; - } - } - else if (argc < 2) - { - result.AppendErrorWithFormat ("%s takes a destination address and at least one value.\n", m_cmd_name.c_str()); + if (m_memory_options.m_infile) { + size_t length = SIZE_MAX; + if (item_byte_size > 1) + length = item_byte_size; + lldb::DataBufferSP data_sp(m_memory_options.m_infile.ReadFileContents( + m_memory_options.m_infile_offset, length)); + if (data_sp) { + length = data_sp->GetByteSize(); + if (length > 0) { + Error error; + size_t bytes_written = + process->WriteMemory(addr, data_sp->GetBytes(), length, error); + + if (bytes_written == length) { + // All bytes written + result.GetOutputStream().Printf( + "%" PRIu64 " bytes were written to 0x%" PRIx64 "\n", + (uint64_t)bytes_written, addr); + result.SetStatus(eReturnStatusSuccessFinishResult); + } else if (bytes_written > 0) { + // Some byte written + result.GetOutputStream().Printf( + "%" PRIu64 " bytes of %" PRIu64 + " requested were written to 0x%" PRIx64 "\n", + (uint64_t)bytes_written, (uint64_t)length, addr); + result.SetStatus(eReturnStatusSuccessFinishResult); + } else { + result.AppendErrorWithFormat("Memory write to 0x%" PRIx64 + " failed: %s.\n", + addr, error.AsCString()); result.SetStatus(eReturnStatusFailed); - return false; + } } + } else { + result.AppendErrorWithFormat("Unable to read contents of file.\n"); + result.SetStatus(eReturnStatusFailed); + } + return result.Succeeded(); + } else if (item_byte_size == 0) { + if (m_format_options.GetFormat() == eFormatPointer) + item_byte_size = buffer.GetAddressByteSize(); + else + item_byte_size = 1; + } - StreamString buffer (Stream::eBinary, - process->GetTarget().GetArchitecture().GetAddressByteSize(), - process->GetTarget().GetArchitecture().GetByteOrder()); - - OptionValueUInt64 &byte_size_value = m_format_options.GetByteSizeValue(); - size_t item_byte_size = byte_size_value.GetCurrentValue(); - - Error error; - lldb::addr_t addr = Args::StringToAddress (&m_exe_ctx, - command.GetArgumentAtIndex(0), - LLDB_INVALID_ADDRESS, - &error); - - if (addr == LLDB_INVALID_ADDRESS) - { - result.AppendError("invalid address expression\n"); - result.AppendError(error.AsCString()); + command.Shift(); // shift off the address argument + uint64_t uval64; + int64_t sval64; + bool success = false; + const size_t num_value_args = command.GetArgumentCount(); + for (size_t i = 0; i < num_value_args; ++i) { + const char *value_str = command.GetArgumentAtIndex(i); + + switch (m_format_options.GetFormat()) { + case kNumFormats: + 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 eFormatVectorOfFloat16: + case eFormatVectorOfFloat32: + case eFormatVectorOfFloat64: + case eFormatVectorOfUInt128: + case eFormatOSType: + case eFormatComplexInteger: + case eFormatAddressInfo: + case eFormatHexFloat: + case eFormatInstruction: + case eFormatVoid: + result.AppendError("unsupported format for writing memory"); + result.SetStatus(eReturnStatusFailed); + return false; + + case eFormatDefault: + case eFormatBytes: + case eFormatHex: + case eFormatHexUppercase: + case eFormatPointer: + // Decode hex bytes + uval64 = StringConvert::ToUInt64(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%" PRIx64 + " is too large to fit in a %" PRIu64 + " byte unsigned integer value.\n", + uval64, (uint64_t)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 = StringConvert::ToUInt64(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%" PRIx64 + " is too large to fit in a %" PRIu64 + " byte unsigned integer value.\n", + uval64, (uint64_t)item_byte_size); + result.SetStatus(eReturnStatusFailed); + return false; + } + buffer.PutMaxHex64(uval64, item_byte_size); + break; + + case eFormatCharArray: + case eFormatChar: + case eFormatCString: + if (value_str[0]) { + size_t len = strlen(value_str); + // Include the NULL for C strings... + if (m_format_options.GetFormat() == eFormatCString) + ++len; + Error error; + if (process->WriteMemory(addr, value_str, len, error) == len) { + addr += len; + } else { + result.AppendErrorWithFormat("Memory write to 0x%" PRIx64 + " failed: %s.\n", + addr, error.AsCString()); result.SetStatus(eReturnStatusFailed); return false; + } } - - if (m_memory_options.m_infile) - { - size_t length = SIZE_MAX; - if (item_byte_size > 1) - length = item_byte_size; - lldb::DataBufferSP data_sp (m_memory_options.m_infile.ReadFileContents (m_memory_options.m_infile_offset, length)); - if (data_sp) - { - length = data_sp->GetByteSize(); - if (length > 0) - { - Error error; - size_t bytes_written = process->WriteMemory (addr, data_sp->GetBytes(), length, error); - - if (bytes_written == length) - { - // All bytes written - result.GetOutputStream().Printf("%" PRIu64 " bytes were written to 0x%" PRIx64 "\n", (uint64_t)bytes_written, addr); - result.SetStatus(eReturnStatusSuccessFinishResult); - } - else if (bytes_written > 0) - { - // Some byte written - result.GetOutputStream().Printf("%" PRIu64 " bytes of %" PRIu64 " requested were written to 0x%" PRIx64 "\n", (uint64_t)bytes_written, (uint64_t)length, addr); - result.SetStatus(eReturnStatusSuccessFinishResult); - } - else - { - result.AppendErrorWithFormat ("Memory write to 0x%" PRIx64 " failed: %s.\n", addr, error.AsCString()); - result.SetStatus(eReturnStatusFailed); - } - } - } - else - { - result.AppendErrorWithFormat ("Unable to read contents of file.\n"); - result.SetStatus(eReturnStatusFailed); - } - return result.Succeeded(); + break; + + case eFormatDecimal: + sval64 = StringConvert::ToSInt64(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 %" PRIi64 " is too large or small to fit in a %" PRIu64 + " byte signed integer value.\n", + sval64, (uint64_t)item_byte_size); + result.SetStatus(eReturnStatusFailed); + return false; } - else if (item_byte_size == 0) - { - if (m_format_options.GetFormat() == eFormatPointer) - item_byte_size = buffer.GetAddressByteSize(); - else - item_byte_size = 1; + buffer.PutMaxHex64(sval64, item_byte_size); + break; + + case eFormatUnsigned: + uval64 = StringConvert::ToUInt64(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 %" PRIu64 + " is too large to fit in a %" PRIu64 + " byte unsigned integer value.\n", + uval64, (uint64_t)item_byte_size); + result.SetStatus(eReturnStatusFailed); + return false; } - - command.Shift(); // shift off the address argument - uint64_t uval64; - int64_t sval64; - bool success = false; - const size_t num_value_args = command.GetArgumentCount(); - for (size_t i=0; i<num_value_args; ++i) - { - const char *value_str = command.GetArgumentAtIndex(i); - - switch (m_format_options.GetFormat()) - { - case kNumFormats: - 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 eFormatVectorOfFloat16: - case eFormatVectorOfFloat32: - case eFormatVectorOfFloat64: - case eFormatVectorOfUInt128: - case eFormatOSType: - case eFormatComplexInteger: - case eFormatAddressInfo: - case eFormatHexFloat: - case eFormatInstruction: - case eFormatVoid: - result.AppendError("unsupported format for writing memory"); - result.SetStatus(eReturnStatusFailed); - return false; - - case eFormatDefault: - case eFormatBytes: - case eFormatHex: - case eFormatHexUppercase: - case eFormatPointer: - // Decode hex bytes - uval64 = StringConvert::ToUInt64(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%" PRIx64 " is too large to fit in a %" PRIu64 " byte unsigned integer value.\n", uval64, (uint64_t)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 = StringConvert::ToUInt64(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%" PRIx64 " is too large to fit in a %" PRIu64 " byte unsigned integer value.\n", uval64, (uint64_t)item_byte_size); - result.SetStatus(eReturnStatusFailed); - return false; - } - buffer.PutMaxHex64 (uval64, item_byte_size); - break; - - case eFormatCharArray: - case eFormatChar: - case eFormatCString: - if (value_str[0]) - { - size_t len = strlen (value_str); - // Include the NULL for C strings... - if (m_format_options.GetFormat() == eFormatCString) - ++len; - Error error; - if (process->WriteMemory (addr, value_str, len, error) == len) - { - addr += len; - } - else - { - result.AppendErrorWithFormat ("Memory write to 0x%" PRIx64 " failed: %s.\n", addr, error.AsCString()); - result.SetStatus(eReturnStatusFailed); - return false; - } - } - break; - - case eFormatDecimal: - sval64 = StringConvert::ToSInt64(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 %" PRIi64 " is too large or small to fit in a %" PRIu64 " byte signed integer value.\n", sval64, (uint64_t)item_byte_size); - result.SetStatus(eReturnStatusFailed); - return false; - } - buffer.PutMaxHex64 (sval64, item_byte_size); - break; - - case eFormatUnsigned: - uval64 = StringConvert::ToUInt64(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 %" PRIu64 " is too large to fit in a %" PRIu64 " byte unsigned integer value.\n", uval64, (uint64_t)item_byte_size); - result.SetStatus(eReturnStatusFailed); - return false; - } - buffer.PutMaxHex64 (uval64, item_byte_size); - break; - - case eFormatOctal: - uval64 = StringConvert::ToUInt64(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 %" PRIo64 " is too large to fit in a %" PRIu64 " byte unsigned integer value.\n", uval64, (uint64_t)item_byte_size); - result.SetStatus(eReturnStatusFailed); - return false; - } - buffer.PutMaxHex64 (uval64, item_byte_size); - break; - } + buffer.PutMaxHex64(uval64, item_byte_size); + break; + + case eFormatOctal: + uval64 = StringConvert::ToUInt64(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 %" PRIo64 + " is too large to fit in a %" PRIu64 + " byte unsigned integer value.\n", + uval64, (uint64_t)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%" PRIx64 " failed: %s.\n", addr, error.AsCString()); - result.SetStatus(eReturnStatusFailed); - return false; - } - } + 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%" PRIx64 + " failed: %s.\n", + addr, error.AsCString()); + result.SetStatus(eReturnStatusFailed); + return false; + } } + return true; + } - OptionGroupOptions m_option_group; - OptionGroupFormat m_format_options; - OptionGroupWriteMemory m_memory_options; + OptionGroupOptions m_option_group; + OptionGroupFormat m_format_options; + OptionGroupWriteMemory m_memory_options; }; //---------------------------------------------------------------------- // Get malloc/free history of a memory address. //---------------------------------------------------------------------- -class CommandObjectMemoryHistory : public CommandObjectParsed -{ +class CommandObjectMemoryHistory : public CommandObjectParsed { public: - CommandObjectMemoryHistory(CommandInterpreter &interpreter) - : CommandObjectParsed( - interpreter, "memory history", - "Print recorded stack traces for allocation/deallocation events associated with an address.", nullptr, - eCommandRequiresTarget | eCommandRequiresProcess | eCommandProcessMustBePaused | - eCommandProcessMustBeLaunched) - { - CommandArgumentEntry arg1; - CommandArgumentData addr_arg; - - // Define the first (and only) variant of this arg. - addr_arg.arg_type = eArgTypeAddress; - addr_arg.arg_repetition = eArgRepeatPlain; - - // There is only one variant this argument could be; put it into the argument entry. - arg1.push_back (addr_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back (arg1); + CommandObjectMemoryHistory(CommandInterpreter &interpreter) + : CommandObjectParsed( + interpreter, "memory history", "Print recorded stack traces for " + "allocation/deallocation events " + "associated with an address.", + nullptr, + eCommandRequiresTarget | eCommandRequiresProcess | + eCommandProcessMustBePaused | eCommandProcessMustBeLaunched) { + CommandArgumentEntry arg1; + CommandArgumentData addr_arg; + + // Define the first (and only) variant of this arg. + addr_arg.arg_type = eArgTypeAddress; + addr_arg.arg_repetition = eArgRepeatPlain; + + // There is only one variant this argument could be; put it into the + // argument entry. + arg1.push_back(addr_arg); + + // Push the data for the first argument into the m_arguments vector. + m_arguments.push_back(arg1); + } + + ~CommandObjectMemoryHistory() override = default; + + const char *GetRepeatCommand(Args ¤t_command_args, + uint32_t index) override { + return m_cmd_name.c_str(); + } + +protected: + bool DoExecute(Args &command, CommandReturnObject &result) override { + const size_t argc = command.GetArgumentCount(); + + if (argc == 0 || argc > 1) { + result.AppendErrorWithFormat("%s takes an address expression", + m_cmd_name.c_str()); + result.SetStatus(eReturnStatusFailed); + return false; } - ~CommandObjectMemoryHistory() override = default; + Error error; + lldb::addr_t addr = + Args::StringToAddress(&m_exe_ctx, command.GetArgumentAtIndex(0), + LLDB_INVALID_ADDRESS, &error); - const char * - GetRepeatCommand (Args ¤t_command_args, uint32_t index) override - { - return m_cmd_name.c_str(); + if (addr == LLDB_INVALID_ADDRESS) { + result.AppendError("invalid address expression"); + result.AppendError(error.AsCString()); + result.SetStatus(eReturnStatusFailed); + return false; } - -protected: - bool - DoExecute (Args& command, CommandReturnObject &result) override - { - const size_t argc = command.GetArgumentCount(); - - if (argc == 0 || argc > 1) - { - result.AppendErrorWithFormat ("%s takes an address expression", m_cmd_name.c_str()); - result.SetStatus(eReturnStatusFailed); - return false; - } - - Error error; - lldb::addr_t addr = Args::StringToAddress (&m_exe_ctx, - command.GetArgumentAtIndex(0), - LLDB_INVALID_ADDRESS, - &error); - - if (addr == LLDB_INVALID_ADDRESS) - { - result.AppendError("invalid address expression"); - result.AppendError(error.AsCString()); - result.SetStatus(eReturnStatusFailed); - return false; - } - - Stream *output_stream = &result.GetOutputStream(); - - const ProcessSP &process_sp = m_exe_ctx.GetProcessSP(); - const MemoryHistorySP &memory_history = MemoryHistory::FindPlugin(process_sp); - - if (!memory_history) - { - result.AppendError("no available memory history provider"); - result.SetStatus(eReturnStatusFailed); - return false; - } - - HistoryThreads thread_list = memory_history->GetHistoryThreads(addr); - - for (auto thread : thread_list) { - thread->GetStatus(*output_stream, 0, UINT32_MAX, 0); - } - - result.SetStatus(eReturnStatusSuccessFinishResult); - - return true; + + Stream *output_stream = &result.GetOutputStream(); + + const ProcessSP &process_sp = m_exe_ctx.GetProcessSP(); + const MemoryHistorySP &memory_history = + MemoryHistory::FindPlugin(process_sp); + + if (!memory_history) { + result.AppendError("no available memory history provider"); + result.SetStatus(eReturnStatusFailed); + return false; } + + HistoryThreads thread_list = memory_history->GetHistoryThreads(addr); + + for (auto thread : thread_list) { + thread->GetStatus(*output_stream, 0, UINT32_MAX, 0); + } + + result.SetStatus(eReturnStatusSuccessFinishResult); + + return true; + } }; //------------------------------------------------------------------------- @@ -1827,102 +1693,90 @@ protected: //------------------------------------------------------------------------- #pragma mark CommandObjectMemoryRegion -class CommandObjectMemoryRegion : public CommandObjectParsed -{ +class CommandObjectMemoryRegion : public CommandObjectParsed { public: - CommandObjectMemoryRegion(CommandInterpreter &interpreter) - : CommandObjectParsed( - interpreter, "memory region", - "Get information on the memory region containing an address in the current target process.", - "memory region ADDR", eCommandRequiresProcess | eCommandTryTargetAPILock | eCommandProcessMustBeLaunched), - m_prev_end_addr(LLDB_INVALID_ADDRESS) - { - } + CommandObjectMemoryRegion(CommandInterpreter &interpreter) + : CommandObjectParsed(interpreter, "memory region", + "Get information on the memory region containing " + "an address in the current target process.", + "memory region ADDR", + eCommandRequiresProcess | eCommandTryTargetAPILock | + eCommandProcessMustBeLaunched), + m_prev_end_addr(LLDB_INVALID_ADDRESS) {} - ~CommandObjectMemoryRegion() override = default; + ~CommandObjectMemoryRegion() override = default; protected: - bool - DoExecute(Args &command, CommandReturnObject &result) override - { - ProcessSP process_sp = m_exe_ctx.GetProcessSP(); - if (process_sp) - { - Error error; - lldb::addr_t load_addr = m_prev_end_addr; - m_prev_end_addr = LLDB_INVALID_ADDRESS; - - const size_t argc = command.GetArgumentCount(); - if (argc > 1 || (argc == 0 && load_addr == LLDB_INVALID_ADDRESS)) - { - result.AppendErrorWithFormat("'%s' takes one argument:\nUsage: %s\n", m_cmd_name.c_str(), - m_cmd_syntax.c_str()); - result.SetStatus(eReturnStatusFailed); - } - else - { - const char *load_addr_cstr = command.GetArgumentAtIndex(0); - if (command.GetArgumentCount() == 1) - { - load_addr = Args::StringToAddress(&m_exe_ctx, load_addr_cstr, LLDB_INVALID_ADDRESS, &error); - if (error.Fail() || load_addr == LLDB_INVALID_ADDRESS) - { - result.AppendErrorWithFormat("invalid address argument \"%s\": %s\n", load_addr_cstr, - error.AsCString()); - result.SetStatus(eReturnStatusFailed); - } - } - - lldb_private::MemoryRegionInfo range_info; - error = process_sp->GetMemoryRegionInfo(load_addr, range_info); - if (error.Success()) - { - lldb_private::Address addr; - ConstString section_name; - if (process_sp->GetTarget().ResolveLoadAddress(load_addr, addr)) - { - SectionSP section_sp(addr.GetSection()); - if (section_sp) - { - // Got the top most section, not the deepest section - while (section_sp->GetParent()) - section_sp = section_sp->GetParent(); - section_name = section_sp->GetName(); - } - } - result.AppendMessageWithFormat( - "[0x%16.16" PRIx64 "-0x%16.16" PRIx64 ") %c%c%c%s%s\n", range_info.GetRange().GetRangeBase(), - range_info.GetRange().GetRangeEnd(), range_info.GetReadable() ? 'r' : '-', - range_info.GetWritable() ? 'w' : '-', range_info.GetExecutable() ? 'x' : '-', - section_name ? " " : "", section_name ? section_name.AsCString() : ""); - m_prev_end_addr = range_info.GetRange().GetRangeEnd(); - result.SetStatus(eReturnStatusSuccessFinishResult); - } - else - { - result.SetStatus(eReturnStatusFailed); - result.AppendErrorWithFormat("%s\n", error.AsCString()); - } - } - } - else - { - m_prev_end_addr = LLDB_INVALID_ADDRESS; - result.AppendError("invalid process"); + bool DoExecute(Args &command, CommandReturnObject &result) override { + ProcessSP process_sp = m_exe_ctx.GetProcessSP(); + if (process_sp) { + Error error; + lldb::addr_t load_addr = m_prev_end_addr; + m_prev_end_addr = LLDB_INVALID_ADDRESS; + + const size_t argc = command.GetArgumentCount(); + if (argc > 1 || (argc == 0 && load_addr == LLDB_INVALID_ADDRESS)) { + result.AppendErrorWithFormat("'%s' takes one argument:\nUsage: %s\n", + m_cmd_name.c_str(), m_cmd_syntax.c_str()); + result.SetStatus(eReturnStatusFailed); + } else { + const char *load_addr_cstr = command.GetArgumentAtIndex(0); + if (command.GetArgumentCount() == 1) { + load_addr = Args::StringToAddress(&m_exe_ctx, load_addr_cstr, + LLDB_INVALID_ADDRESS, &error); + if (error.Fail() || load_addr == LLDB_INVALID_ADDRESS) { + result.AppendErrorWithFormat( + "invalid address argument \"%s\": %s\n", load_addr_cstr, + error.AsCString()); result.SetStatus(eReturnStatusFailed); + } } - return result.Succeeded(); - } - const char * - GetRepeatCommand(Args ¤t_command_args, uint32_t index) override - { - // If we repeat this command, repeat it without any arguments so we can - // show the next memory range - return m_cmd_name.c_str(); + lldb_private::MemoryRegionInfo range_info; + error = process_sp->GetMemoryRegionInfo(load_addr, range_info); + if (error.Success()) { + lldb_private::Address addr; + ConstString section_name; + if (process_sp->GetTarget().ResolveLoadAddress(load_addr, addr)) { + SectionSP section_sp(addr.GetSection()); + if (section_sp) { + // Got the top most section, not the deepest section + while (section_sp->GetParent()) + section_sp = section_sp->GetParent(); + section_name = section_sp->GetName(); + } + } + result.AppendMessageWithFormat( + "[0x%16.16" PRIx64 "-0x%16.16" PRIx64 ") %c%c%c%s%s\n", + range_info.GetRange().GetRangeBase(), + range_info.GetRange().GetRangeEnd(), + range_info.GetReadable() ? 'r' : '-', + range_info.GetWritable() ? 'w' : '-', + range_info.GetExecutable() ? 'x' : '-', section_name ? " " : "", + section_name ? section_name.AsCString() : ""); + m_prev_end_addr = range_info.GetRange().GetRangeEnd(); + result.SetStatus(eReturnStatusSuccessFinishResult); + } else { + result.SetStatus(eReturnStatusFailed); + result.AppendErrorWithFormat("%s\n", error.AsCString()); + } + } + } else { + m_prev_end_addr = LLDB_INVALID_ADDRESS; + result.AppendError("invalid process"); + result.SetStatus(eReturnStatusFailed); } + return result.Succeeded(); + } + + const char *GetRepeatCommand(Args ¤t_command_args, + uint32_t index) override { + // If we repeat this command, repeat it without any arguments so we can + // show the next memory range + return m_cmd_name.c_str(); + } - lldb::addr_t m_prev_end_addr; + lldb::addr_t m_prev_end_addr; }; //------------------------------------------------------------------------- @@ -1930,14 +1784,20 @@ protected: //------------------------------------------------------------------------- CommandObjectMemory::CommandObjectMemory(CommandInterpreter &interpreter) - : CommandObjectMultiword(interpreter, "memory", "Commands for operating on memory in the current target process.", - "memory <subcommand> [<subcommand-options>]") -{ - LoadSubCommand("find", CommandObjectSP(new CommandObjectMemoryFind(interpreter))); - LoadSubCommand("read", CommandObjectSP(new CommandObjectMemoryRead(interpreter))); - LoadSubCommand("write", CommandObjectSP(new CommandObjectMemoryWrite(interpreter))); - LoadSubCommand("history", CommandObjectSP(new CommandObjectMemoryHistory(interpreter))); - LoadSubCommand("region", CommandObjectSP(new CommandObjectMemoryRegion(interpreter))); + : CommandObjectMultiword( + interpreter, "memory", + "Commands for operating on memory in the current target process.", + "memory <subcommand> [<subcommand-options>]") { + LoadSubCommand("find", + CommandObjectSP(new CommandObjectMemoryFind(interpreter))); + LoadSubCommand("read", + CommandObjectSP(new CommandObjectMemoryRead(interpreter))); + LoadSubCommand("write", + CommandObjectSP(new CommandObjectMemoryWrite(interpreter))); + LoadSubCommand("history", + CommandObjectSP(new CommandObjectMemoryHistory(interpreter))); + LoadSubCommand("region", + CommandObjectSP(new CommandObjectMemoryRegion(interpreter))); } CommandObjectMemory::~CommandObjectMemory() = default; |