diff options
Diffstat (limited to 'lldb/source/Commands')
-rw-r--r-- | lldb/source/Commands/CommandObjectBreakpoint.cpp | 348 | ||||
-rw-r--r-- | lldb/source/Commands/CommandObjectBreakpointCommand.cpp | 67 |
2 files changed, 339 insertions, 76 deletions
diff --git a/lldb/source/Commands/CommandObjectBreakpoint.cpp b/lldb/source/Commands/CommandObjectBreakpoint.cpp index a5bfe1d1c90..222bb5f4601 100644 --- a/lldb/source/Commands/CommandObjectBreakpoint.cpp +++ b/lldb/source/Commands/CommandObjectBreakpoint.cpp @@ -523,25 +523,26 @@ protected: case eSetTypeFunctionRegexp: // Breakpoint by regular expression function // name - { - RegularExpression regexp(m_options.m_func_regexp.c_str()); - if (!regexp.IsValid()) { - char err_str[1024]; - regexp.GetErrorAsCString(err_str, sizeof(err_str)); - result.AppendErrorWithFormat( - "Function name regular expression could not be compiled: \"%s\"", - err_str); - result.SetStatus(eReturnStatusFailed); - return false; - } + { + RegularExpression regexp(m_options.m_func_regexp.c_str()); + if (!regexp.IsValid()) { + char err_str[1024]; + regexp.GetErrorAsCString(err_str, sizeof(err_str)); + result.AppendErrorWithFormat( + "Function name regular expression could not be compiled: \"%s\"", + err_str); + result.SetStatus(eReturnStatusFailed); + return false; + } - bp = target - ->CreateFuncRegexBreakpoint( - &(m_options.m_modules), &(m_options.m_filenames), regexp, - m_options.m_language, m_options.m_skip_prologue, internal, - m_options.m_hardware) - .get(); - } break; + bp = target + ->CreateFuncRegexBreakpoint( + &(m_options.m_modules), &(m_options.m_filenames), regexp, + m_options.m_language, m_options.m_skip_prologue, internal, + m_options.m_hardware) + .get(); + } + break; case eSetTypeSourceRegexp: // Breakpoint by regexp on source text. { const size_t num_files = m_options.m_filenames.GetSize(); @@ -2058,7 +2059,7 @@ private: }; //------------------------------------------------------------------------- -// CommandObjectMultiwordBreakpoint +// CommandObjectBreakpointName //------------------------------------------------------------------------- class CommandObjectBreakpointName : public CommandObjectMultiword { public: @@ -2082,6 +2083,307 @@ public: }; //------------------------------------------------------------------------- +// CommandObjectBreakpointRead +//------------------------------------------------------------------------- +#pragma mark Restore + +class CommandObjectBreakpointRead : public CommandObjectParsed { +public: + CommandObjectBreakpointRead(CommandInterpreter &interpreter) + : CommandObjectParsed(interpreter, "breakpoint read", + "Read and set the breakpoints previously saved to " + "a file with \"breakpoint write\". ", + nullptr), + m_options() { + CommandArgumentEntry arg; + CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID, + eArgTypeBreakpointIDRange); + // Add the entry for the first argument for this command to the object's + // arguments vector. + m_arguments.push_back(arg); + } + + ~CommandObjectBreakpointRead() override = default; + + Options *GetOptions() override { return &m_options; } + + class CommandOptions : public Options { + public: + CommandOptions() : Options() {} + + ~CommandOptions() override = default; + + Error SetOptionValue(uint32_t option_idx, const char *option_arg, + ExecutionContext *execution_context) override { + Error error; + const int short_option = m_getopt_table[option_idx].val; + + switch (short_option) { + case 'f': + m_filename.assign(option_arg); + break; + default: + error.SetErrorStringWithFormat("unrecognized option '%c'", + short_option); + break; + } + + return error; + } + + void OptionParsingStarting(ExecutionContext *execution_context) override { + m_filename.clear(); + } + + const OptionDefinition *GetDefinitions() override { return g_option_table; } + + // Options table: Required for subclasses of Options. + + static OptionDefinition g_option_table[]; + + // Instance variables to hold the values for command options. + + std::string m_filename; + }; + +protected: + bool DoExecute(Args &command, CommandReturnObject &result) override { + Target *target = GetSelectedOrDummyTarget(); + if (target == nullptr) { + result.AppendError("Invalid target. No existing target or breakpoints."); + result.SetStatus(eReturnStatusFailed); + return false; + } + + std::unique_lock<std::recursive_mutex> lock; + target->GetBreakpointList().GetListMutex(lock); + + FileSpec input_spec(m_options.m_filename, true); + Error error; + StructuredData::ObjectSP input_data_sp = + StructuredData::ParseJSONFromFile(input_spec, error); + if (!error.Success()) { + result.AppendErrorWithFormat("Error reading data from input file: %s.", + error.AsCString()); + result.SetStatus(eReturnStatusFailed); + return false; + } else if (!input_data_sp || !input_data_sp->IsValid()) { + result.AppendErrorWithFormat("Invalid JSON from input file: %s.", + input_spec.GetPath().c_str()); + result.SetStatus(eReturnStatusFailed); + return false; + } + + StructuredData::Array *bkpt_array = input_data_sp->GetAsArray(); + if (!bkpt_array) { + result.AppendErrorWithFormat( + "Invalid breakpoint data from input file: %s.", + input_spec.GetPath().c_str()); + result.SetStatus(eReturnStatusFailed); + return false; + } + + size_t num_bkpts = bkpt_array->GetSize(); + for (size_t i = 0; i < num_bkpts; i++) { + StructuredData::ObjectSP bkpt_object_sp = bkpt_array->GetItemAtIndex(i); + // Peel off the breakpoint key, and feed the rest to the Breakpoint: + StructuredData::Dictionary *bkpt_dict = bkpt_object_sp->GetAsDictionary(); + if (!bkpt_dict) { + result.AppendErrorWithFormat( + "Invalid breakpoint data for element %zu from input file: %s.", i, + input_spec.GetPath().c_str()); + result.SetStatus(eReturnStatusFailed); + return false; + } + StructuredData::ObjectSP bkpt_data_sp = + bkpt_dict->GetValueForKey(Breakpoint::GetSerializationKey()); + BreakpointSP bkpt_sp = + Breakpoint::CreateFromStructuredData(*target, bkpt_data_sp, error); + if (!error.Success()) { + result.AppendErrorWithFormat( + "Error restoring breakpoint %zu from %s: %s.", i, + input_spec.GetPath().c_str(), error.AsCString()); + result.SetStatus(eReturnStatusFailed); + } + } + return result.Succeeded(); + } + +private: + CommandOptions m_options; +}; + +#pragma mark Modify::CommandOptions +OptionDefinition CommandObjectBreakpointRead::CommandOptions::g_option_table[] = + { + // clang-format off + {LLDB_OPT_SET_ALL, true, "file", 'f', OptionParser::eRequiredArgument, nullptr, nullptr, CommandCompletions::eDiskFileCompletion, eArgTypeFilename, "The file from which to read the breakpoints."}, + {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr} + // clang-format on +}; + +//------------------------------------------------------------------------- +// CommandObjectBreakpointWrite +//------------------------------------------------------------------------- +#pragma mark Save +class CommandObjectBreakpointWrite : public CommandObjectParsed { +public: + CommandObjectBreakpointWrite(CommandInterpreter &interpreter) + : CommandObjectParsed(interpreter, "breakpoint write", + "Write the breakpoints listed to a file that can " + "be read in with \"breakpoint read\". " + "If given no arguments, writes all breakpoints.", + nullptr), + m_options() { + CommandArgumentEntry arg; + CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID, + eArgTypeBreakpointIDRange); + // Add the entry for the first argument for this command to the object's + // arguments vector. + m_arguments.push_back(arg); + } + + ~CommandObjectBreakpointWrite() override = default; + + Options *GetOptions() override { return &m_options; } + + class CommandOptions : public Options { + public: + CommandOptions() : Options() {} + + ~CommandOptions() override = default; + + Error SetOptionValue(uint32_t option_idx, const char *option_arg, + ExecutionContext *execution_context) override { + Error error; + const int short_option = m_getopt_table[option_idx].val; + + switch (short_option) { + case 'f': + m_filename.assign(option_arg); + break; + default: + error.SetErrorStringWithFormat("unrecognized option '%c'", + short_option); + break; + } + + return error; + } + + void OptionParsingStarting(ExecutionContext *execution_context) override { + m_filename.clear(); + } + + const OptionDefinition *GetDefinitions() override { return g_option_table; } + + // Options table: Required for subclasses of Options. + + static OptionDefinition g_option_table[]; + + // Instance variables to hold the values for command options. + + std::string m_filename; + }; + +protected: + bool DoExecute(Args &command, CommandReturnObject &result) override { + Target *target = GetSelectedOrDummyTarget(); + if (target == nullptr) { + result.AppendError("Invalid target. No existing target or breakpoints."); + result.SetStatus(eReturnStatusFailed); + return false; + } + + // Before we do anything else make sure we can actually write to this file: + StreamFile out_file(m_options.m_filename.c_str(), + File::OpenOptions::eOpenOptionTruncate | + File::OpenOptions::eOpenOptionWrite | + File::OpenOptions::eOpenOptionCanCreate | + File::OpenOptions::eOpenOptionCloseOnExec, + lldb::eFilePermissionsFileDefault); + if (!out_file.GetFile().IsValid()) { + result.AppendErrorWithFormat("Unable to open output file: %s.", + m_options.m_filename.c_str()); + result.SetStatus(eReturnStatusFailed); + return false; + } + + std::unique_lock<std::recursive_mutex> lock; + target->GetBreakpointList().GetListMutex(lock); + + StructuredData::ArraySP break_store_sp(new StructuredData::Array()); + + if (command.GetArgumentCount() == 0) { + const BreakpointList &breakpoints = target->GetBreakpointList(); + + size_t num_breakpoints = breakpoints.GetSize(); + for (size_t i = 0; i < num_breakpoints; i++) { + Breakpoint *bp = breakpoints.GetBreakpointAtIndex(i).get(); + StructuredData::ObjectSP bkpt_save_sp = bp->SerializeToStructuredData(); + // If a breakpoint can't serialize it, just ignore it for now: + if (bkpt_save_sp) + break_store_sp->AddItem(bkpt_save_sp); + } + } else { + + BreakpointIDList valid_bp_ids; + + CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs( + command, target, result, &valid_bp_ids); + + if (result.Succeeded()) { + std::unordered_set<lldb::break_id_t> processed_bkpts; + const size_t count = valid_bp_ids.GetSize(); + for (size_t i = 0; i < count; ++i) { + BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i); + lldb::break_id_t bp_id = cur_bp_id.GetBreakpointID(); + + if (bp_id != LLDB_INVALID_BREAK_ID) { + // Only do each breakpoint once: + std::pair<std::unordered_set<lldb::break_id_t>::iterator, bool> + insert_result = processed_bkpts.insert(bp_id); + if (!insert_result.second) + continue; + + Breakpoint *bp = target->GetBreakpointByID(bp_id).get(); + StructuredData::ObjectSP bkpt_save_sp = + bp->SerializeToStructuredData(); + // If the user explicitly asked to serialize a breakpoint, and we + // can't, then + // raise an error: + if (!bkpt_save_sp) { + result.AppendErrorWithFormat("Unable to serialize breakpoint %d", + bp_id); + result.SetStatus(eReturnStatusFailed); + return false; + } + break_store_sp->AddItem(bkpt_save_sp); + } + } + } + } + + break_store_sp->Dump(out_file, false); + out_file.PutChar('\n'); + + return result.Succeeded(); + } + +private: + CommandOptions m_options; +}; + +#pragma mark Modify::CommandOptions +OptionDefinition + CommandObjectBreakpointWrite::CommandOptions::g_option_table[] = { + // clang-format off + {LLDB_OPT_SET_ALL, true, "file", 'f', OptionParser::eRequiredArgument, nullptr, nullptr, CommandCompletions::eDiskFileCompletion, eArgTypeFilename, "The file into which to write the breakpoints."}, + {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr} + // clang-format on +}; + +//------------------------------------------------------------------------- // CommandObjectMultiwordBreakpoint //------------------------------------------------------------------------- #pragma mark MultiwordBreakpoint @@ -2110,6 +2412,10 @@ CommandObjectMultiwordBreakpoint::CommandObjectMultiwordBreakpoint( new CommandObjectBreakpointModify(interpreter)); CommandObjectSP name_command_object( new CommandObjectBreakpointName(interpreter)); + CommandObjectSP write_command_object( + new CommandObjectBreakpointWrite(interpreter)); + CommandObjectSP read_command_object( + new CommandObjectBreakpointRead(interpreter)); list_command_object->SetCommandName("breakpoint list"); enable_command_object->SetCommandName("breakpoint enable"); @@ -2120,6 +2426,8 @@ CommandObjectMultiwordBreakpoint::CommandObjectMultiwordBreakpoint( command_command_object->SetCommandName("breakpoint command"); modify_command_object->SetCommandName("breakpoint modify"); name_command_object->SetCommandName("breakpoint name"); + write_command_object->SetCommandName("breakpoint write"); + read_command_object->SetCommandName("breakpoint read"); LoadSubCommand("list", list_command_object); LoadSubCommand("enable", enable_command_object); @@ -2130,6 +2438,8 @@ CommandObjectMultiwordBreakpoint::CommandObjectMultiwordBreakpoint( LoadSubCommand("command", command_command_object); LoadSubCommand("modify", modify_command_object); LoadSubCommand("name", name_command_object); + LoadSubCommand("write", write_command_object); + LoadSubCommand("read", read_command_object); } CommandObjectMultiwordBreakpoint::~CommandObjectMultiwordBreakpoint() = default; diff --git a/lldb/source/Commands/CommandObjectBreakpointCommand.cpp b/lldb/source/Commands/CommandObjectBreakpointCommand.cpp index 557cb5f13a9..7884728e478 100644 --- a/lldb/source/Commands/CommandObjectBreakpointCommand.cpp +++ b/lldb/source/Commands/CommandObjectBreakpointCommand.cpp @@ -215,14 +215,10 @@ are no syntax errors may indicate that a function was declared but never called. if (!bp_options) continue; - std::unique_ptr<BreakpointOptions::CommandData> data_ap( - new BreakpointOptions::CommandData()); - if (data_ap) { - data_ap->user_source.SplitIntoLines(line.c_str(), line.size()); - BatonSP baton_sp( - new BreakpointOptions::CommandBaton(data_ap.release())); - bp_options->SetCallback(BreakpointOptionsCallbackFunction, baton_sp); - } + BreakpointOptions::CommandData *cmd_data = + new BreakpointOptions::CommandData(); + cmd_data->user_source.SplitIntoLines(line.c_str(), line.size()); + bp_options->SetCommandDataCallback(cmd_data); } } @@ -242,8 +238,8 @@ are no syntax errors may indicate that a function was declared but never called. SetBreakpointCommandCallback(std::vector<BreakpointOptions *> &bp_options_vec, const char *oneliner) { for (auto bp_options : bp_options_vec) { - std::unique_ptr<BreakpointOptions::CommandData> data_ap( - new BreakpointOptions::CommandData()); + BreakpointOptions::CommandData *cmd_data = + new BreakpointOptions::CommandData(); // It's necessary to set both user_source and script_source to the // oneliner. @@ -251,55 +247,12 @@ are no syntax errors may indicate that a function was declared but never called. // command list) // while the latter is used for Python to interpret during the actual // callback. - data_ap->user_source.AppendString(oneliner); - data_ap->script_source.assign(oneliner); - data_ap->stop_on_error = m_options.m_stop_on_error; + cmd_data->user_source.AppendString(oneliner); + cmd_data->script_source.assign(oneliner); + cmd_data->stop_on_error = m_options.m_stop_on_error; - BatonSP baton_sp(new BreakpointOptions::CommandBaton(data_ap.release())); - bp_options->SetCallback(BreakpointOptionsCallbackFunction, baton_sp); - } - } - - static bool BreakpointOptionsCallbackFunction( - void *baton, StoppointCallbackContext *context, lldb::user_id_t break_id, - lldb::user_id_t break_loc_id) { - bool ret_value = true; - if (baton == nullptr) - return true; - - BreakpointOptions::CommandData *data = - (BreakpointOptions::CommandData *)baton; - StringList &commands = data->user_source; - - if (commands.GetSize() > 0) { - ExecutionContext exe_ctx(context->exe_ctx_ref); - Target *target = exe_ctx.GetTargetPtr(); - if (target) { - CommandReturnObject result; - Debugger &debugger = target->GetDebugger(); - // Rig up the results secondary output stream to the debugger's, so the - // output will come out synchronously - // if the debugger is set up that way. - - StreamSP output_stream(debugger.GetAsyncOutputStream()); - StreamSP error_stream(debugger.GetAsyncErrorStream()); - result.SetImmediateOutputStream(output_stream); - result.SetImmediateErrorStream(error_stream); - - CommandInterpreterRunOptions options; - options.SetStopOnContinue(true); - options.SetStopOnError(data->stop_on_error); - options.SetEchoCommands(true); - options.SetPrintResults(true); - options.SetAddToHistory(false); - - debugger.GetCommandInterpreter().HandleCommands(commands, &exe_ctx, - options, result); - result.GetImmediateOutputStream()->Flush(); - result.GetImmediateErrorStream()->Flush(); - } + bp_options->SetCommandDataCallback(cmd_data); } - return ret_value; } class CommandOptions : public Options { |