diff options
Diffstat (limited to 'source/Commands/CommandObjectThread.cpp')
-rw-r--r-- | source/Commands/CommandObjectThread.cpp | 666 |
1 files changed, 446 insertions, 220 deletions
diff --git a/source/Commands/CommandObjectThread.cpp b/source/Commands/CommandObjectThread.cpp index e7a8652..bace4e5 100644 --- a/source/Commands/CommandObjectThread.cpp +++ b/source/Commands/CommandObjectThread.cpp @@ -46,7 +46,108 @@ using namespace lldb_private; // CommandObjectThreadBacktrace //------------------------------------------------------------------------- -class CommandObjectThreadBacktrace : public CommandObjectParsed +class CommandObjectIterateOverThreads : public CommandObjectParsed +{ +public: + CommandObjectIterateOverThreads (CommandInterpreter &interpreter, + const char *name, + const char *help, + const char *syntax, + uint32_t flags) : + CommandObjectParsed (interpreter, name, help, syntax, flags) + { + } + + virtual ~CommandObjectIterateOverThreads() {} + virtual bool + DoExecute (Args& command, CommandReturnObject &result) + { + result.SetStatus (m_success_return); + + if (command.GetArgumentCount() == 0) + { + Thread *thread = m_exe_ctx.GetThreadPtr(); + if (!HandleOneThread (*thread, result)) + return false; + } + else if (command.GetArgumentCount() == 1 && ::strcmp (command.GetArgumentAtIndex(0), "all") == 0) + { + Process *process = m_exe_ctx.GetProcessPtr(); + uint32_t idx = 0; + for (ThreadSP thread_sp : process->Threads()) + { + if (idx != 0 && m_add_return) + result.AppendMessage(""); + + if (!HandleOneThread(*(thread_sp.get()), result)) + return false; + ++idx; + } + } + else + { + const size_t num_args = command.GetArgumentCount(); + Process *process = m_exe_ctx.GetProcessPtr(); + Mutex::Locker locker (process->GetThreadList().GetMutex()); + std::vector<ThreadSP> thread_sps; + + for (size_t i = 0; i < num_args; i++) + { + bool success; + + uint32_t thread_idx = Args::StringToUInt32(command.GetArgumentAtIndex(i), 0, 0, &success); + if (!success) + { + result.AppendErrorWithFormat ("invalid thread specification: \"%s\"\n", command.GetArgumentAtIndex(i)); + result.SetStatus (eReturnStatusFailed); + return false; + } + + thread_sps.push_back(process->GetThreadList().FindThreadByIndexID(thread_idx)); + + if (!thread_sps[i]) + { + result.AppendErrorWithFormat ("no thread with index: \"%s\"\n", command.GetArgumentAtIndex(i)); + result.SetStatus (eReturnStatusFailed); + return false; + } + + } + + for (uint32_t i = 0; i < num_args; i++) + { + if (!HandleOneThread (*(thread_sps[i].get()), result)) + return false; + + if (i < num_args - 1 && m_add_return) + result.AppendMessage(""); + } + } + return result.Succeeded(); + } + +protected: + + // Override this to do whatever you need to do for one thread. + // + // If you return false, the iteration will stop, otherwise it will proceed. + // The result is set to m_success_return (defaults to eReturnStatusSuccessFinishResult) before the iteration, + // so you only need to set the return status in HandleOneThread if you want to indicate an error. + // If m_add_return is true, a blank line will be inserted between each of the listings (except the last one.) + + virtual bool + HandleOneThread (Thread &thread, CommandReturnObject &result) = 0; + + ReturnStatus m_success_return = eReturnStatusSuccessFinishResult; + bool m_add_return = true; + +}; + +//------------------------------------------------------------------------- +// CommandObjectThreadBacktrace +//------------------------------------------------------------------------- + +class CommandObjectThreadBacktrace : public CommandObjectIterateOverThreads { public: @@ -134,7 +235,7 @@ public: }; CommandObjectThreadBacktrace (CommandInterpreter &interpreter) : - CommandObjectParsed (interpreter, + CommandObjectIterateOverThreads (interpreter, "thread backtrace", "Show the stack for one or more threads. If no threads are specified, show the currently selected thread. Use the thread-index \"all\" to see all threads.", NULL, @@ -145,18 +246,6 @@ public: eFlagProcessMustBePaused ), m_options(interpreter) { - CommandArgumentEntry arg; - CommandArgumentData thread_idx_arg; - - // Define the first (and only) variant of this arg. - thread_idx_arg.arg_type = eArgTypeThreadIndex; - thread_idx_arg.arg_repetition = eArgRepeatStar; - - // There is only one variant this argument could be; put it into the argument entry. - arg.push_back (thread_idx_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back (arg); } ~CommandObjectThreadBacktrace() @@ -197,106 +286,28 @@ protected: } virtual bool - DoExecute (Args& command, CommandReturnObject &result) - { - result.SetStatus (eReturnStatusSuccessFinishResult); + HandleOneThread (Thread &thread, CommandReturnObject &result) + { Stream &strm = result.GetOutputStream(); // Don't show source context when doing backtraces. const uint32_t num_frames_with_source = 0; - if (command.GetArgumentCount() == 0) - { - Thread *thread = m_exe_ctx.GetThreadPtr(); - // Thread::GetStatus() returns the number of frames shown. - if (thread->GetStatus (strm, + + if (!thread.GetStatus (strm, m_options.m_start, m_options.m_count, num_frames_with_source)) - { - result.SetStatus (eReturnStatusSuccessFinishResult); - if (m_options.m_extended_backtrace) - { - DoExtendedBacktrace (thread, result); - } - } - } - else if (command.GetArgumentCount() == 1 && ::strcmp (command.GetArgumentAtIndex(0), "all") == 0) { - Process *process = m_exe_ctx.GetProcessPtr(); - uint32_t idx = 0; - for (ThreadSP thread_sp : process->Threads()) - { - if (idx != 0) - result.AppendMessage(""); - - if (!thread_sp->GetStatus (strm, - m_options.m_start, - m_options.m_count, - num_frames_with_source)) - { - result.AppendErrorWithFormat ("error displaying backtrace for thread: \"0x%4.4x\"\n", idx); - result.SetStatus (eReturnStatusFailed); - return false; - } - if (m_options.m_extended_backtrace) - { - DoExtendedBacktrace (thread_sp.get(), result); - } - - ++idx; - } + result.AppendErrorWithFormat ("error displaying backtrace for thread: \"0x%4.4x\"\n", thread.GetIndexID()); + result.SetStatus (eReturnStatusFailed); + return false; } - else + if (m_options.m_extended_backtrace) { - const size_t num_args = command.GetArgumentCount(); - Process *process = m_exe_ctx.GetProcessPtr(); - Mutex::Locker locker (process->GetThreadList().GetMutex()); - std::vector<ThreadSP> thread_sps; - - for (size_t i = 0; i < num_args; i++) - { - bool success; - - uint32_t thread_idx = Args::StringToUInt32(command.GetArgumentAtIndex(i), 0, 0, &success); - if (!success) - { - result.AppendErrorWithFormat ("invalid thread specification: \"%s\"\n", command.GetArgumentAtIndex(i)); - result.SetStatus (eReturnStatusFailed); - return false; - } - - thread_sps.push_back(process->GetThreadList().FindThreadByIndexID(thread_idx)); - - if (!thread_sps[i]) - { - result.AppendErrorWithFormat ("no thread with index: \"%s\"\n", command.GetArgumentAtIndex(i)); - result.SetStatus (eReturnStatusFailed); - return false; - } - - } - - for (uint32_t i = 0; i < num_args; i++) - { - if (!thread_sps[i]->GetStatus (strm, - m_options.m_start, - m_options.m_count, - num_frames_with_source)) - { - result.AppendErrorWithFormat ("error displaying backtrace for thread: \"%s\"\n", command.GetArgumentAtIndex(i)); - result.SetStatus (eReturnStatusFailed); - return false; - } - if (m_options.m_extended_backtrace) - { - DoExtendedBacktrace (thread_sps[i].get(), result); - } - - if (i < num_args - 1) - result.AppendMessage(""); - } + DoExtendedBacktrace (&thread, result); } - return result.Succeeded(); + + return true; } CommandOptions m_options; @@ -379,6 +390,12 @@ public: break; } break; + case 'C': + { + m_class_name.clear(); + m_class_name.assign(option_arg); + } + break; case 'm': { OptionEnumValueElement *enum_values = g_option_table[option_idx].enum_values; @@ -416,6 +433,7 @@ public: m_run_mode = eOnlyDuringStepping; m_avoid_regexp.clear(); m_step_in_target.clear(); + m_class_name.clear(); m_step_count = 1; } @@ -435,7 +453,8 @@ public: RunMode m_run_mode; std::string m_avoid_regexp; std::string m_step_in_target; - int32_t m_step_count; + std::string m_class_name; + uint32_t m_step_count; }; CommandObjectThreadStepWithTypeAndScope (CommandInterpreter &interpreter, @@ -520,6 +539,22 @@ protected: } } + if (m_step_type == eStepTypeScripted) + { + if (m_options.m_class_name.empty()) + { + result.AppendErrorWithFormat ("empty class name for scripted step."); + result.SetStatus(eReturnStatusFailed); + return false; + } + else if (!m_interpreter.GetScriptInterpreter()->CheckObjectExists(m_options.m_class_name.c_str())) + { + result.AppendErrorWithFormat ("class for scripted step: \"%s\" does not exist.", m_options.m_class_name.c_str()); + result.SetStatus(eReturnStatusFailed); + return false; + } + } + const bool abort_other_plans = false; const lldb::RunMode stop_other_threads = m_options.m_run_mode; @@ -530,7 +565,7 @@ protected: bool_stop_other_threads = false; else if (m_options.m_run_mode == eOnlyDuringStepping) { - if (m_step_type == eStepTypeOut) + if (m_step_type == eStepTypeOut || m_step_type == eStepTypeScripted) bool_stop_other_threads = false; else bool_stop_other_threads = true; @@ -599,6 +634,12 @@ protected: thread->GetSelectedFrameIndex(), m_options.m_step_out_avoid_no_debug); } + else if (m_step_type == eStepTypeScripted) + { + new_plan_sp = thread->QueueThreadPlanForStepScripted (abort_other_plans, + m_options.m_class_name.c_str(), + bool_stop_other_threads); + } else { result.AppendError ("step type is not supported"); @@ -622,8 +663,15 @@ protected: } } + process->GetThreadList().SetSelectedThreadByID (thread->GetID()); - process->Resume (); + + StreamString stream; + Error error; + if (synchronous_execution) + error = process->ResumeSynchronous (&stream); + else + error = process->Resume (); // There is a race condition where this thread will return up the call stack to the main command handler // and show an (lldb) prompt before HandlePrivateEvent (from PrivateStateThread) has @@ -632,17 +680,12 @@ protected: if (synchronous_execution) { - StateType state = process->WaitForProcessToStop (NULL); - - //EventSP event_sp; - //StateType state = process->WaitForStateChangedEvents (NULL, event_sp); - //while (! StateIsStoppedState (state)) - // { - // state = process->WaitForStateChangedEvents (NULL, event_sp); - // } + // If any state changed events had anything to say, add that to the result + if (stream.GetData()) + result.AppendMessage(stream.GetData()); + process->GetThreadList().SetSelectedThreadByID (thread->GetID()); result.SetDidChangeProcessState (true); - result.AppendMessageWithFormat ("Process %" PRIu64 " %s\n", process->GetID(), StateAsCString (state)); result.SetStatus (eReturnStatusSuccessFinishNoResult); } else @@ -686,10 +729,11 @@ CommandObjectThreadStepWithTypeAndScope::CommandOptions::g_option_table[] = { { LLDB_OPT_SET_1, false, "step-in-avoids-no-debug", 'a', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean, "A boolean value that sets whether stepping into functions will step over functions with no debug information."}, { LLDB_OPT_SET_1, false, "step-out-avoids-no-debug", 'A', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean, "A boolean value, if true stepping out of functions will continue to step out till it hits a function with debug information."}, -{ LLDB_OPT_SET_1, false, "count", 'c', OptionParser::eRequiredArgument, NULL, NULL, 1, eArgTypeCount, "How many times to perform the stepping operation - currently only supported for step-inst and next-inst."}, -{ LLDB_OPT_SET_1, false, "run-mode", 'm', OptionParser::eRequiredArgument, NULL, g_tri_running_mode, 0, eArgTypeRunMode, "Determine how to run other threads while stepping the current thread."}, -{ LLDB_OPT_SET_1, false, "step-over-regexp",'r', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeRegularExpression, "A regular expression that defines function names to not to stop at when stepping in."}, -{ LLDB_OPT_SET_1, false, "step-in-target", 't', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeFunctionName, "The name of the directly called function step in should stop at when stepping into."}, +{ LLDB_OPT_SET_1, false, "count", 'c', OptionParser::eRequiredArgument, NULL, NULL, 1, eArgTypeCount, "How many times to perform the stepping operation - currently only supported for step-inst and next-inst."}, +{ LLDB_OPT_SET_1, false, "run-mode", 'm', OptionParser::eRequiredArgument, NULL, g_tri_running_mode, 0, eArgTypeRunMode, "Determine how to run other threads while stepping the current thread."}, +{ LLDB_OPT_SET_1, false, "step-over-regexp", 'r', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeRegularExpression, "A regular expression that defines function names to not to stop at when stepping in."}, +{ LLDB_OPT_SET_1, false, "step-in-target", 't', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeFunctionName, "The name of the directly called function step in should stop at when stepping into."}, +{ LLDB_OPT_SET_2, false, "python-class", 'C', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypePythonClass, "The name of the class that will manage this step - only supported for Scripted Step."}, { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } }; @@ -860,17 +904,25 @@ public: } } + + StreamString stream; + Error error; + if (synchronous_execution) + error = process->ResumeSynchronous (&stream); + else + error = process->Resume (); + // We should not be holding the thread list lock when we do this. - Error error (process->Resume()); if (error.Success()) { result.AppendMessageWithFormat ("Process %" PRIu64 " resuming\n", process->GetID()); if (synchronous_execution) { - state = process->WaitForProcessToStop (NULL); + // If any state changed events had anything to say, add that to the result + if (stream.GetData()) + result.AppendMessage(stream.GetData()); result.SetDidChangeProcessState (true); - result.AppendMessageWithFormat ("Process %" PRIu64 " %s\n", process->GetID(), StateAsCString (state)); result.SetStatus (eReturnStatusSuccessFinishNoResult); } else @@ -1191,17 +1243,27 @@ protected: } + + process->GetThreadList().SetSelectedThreadByID (m_options.m_thread_idx); - Error error (process->Resume ()); + + StreamString stream; + Error error; + if (synchronous_execution) + error = process->ResumeSynchronous (&stream); + else + error = process->Resume (); + if (error.Success()) { result.AppendMessageWithFormat ("Process %" PRIu64 " resuming\n", process->GetID()); if (synchronous_execution) { - StateType state = process->WaitForProcessToStop (NULL); + // If any state changed events had anything to say, add that to the result + if (stream.GetData()) + result.AppendMessage(stream.GetData()); result.SetDidChangeProcessState (true); - result.AppendMessageWithFormat ("Process %" PRIu64 " %s\n", process->GetID(), StateAsCString (state)); result.SetStatus (eReturnStatusSuccessFinishNoResult); } else @@ -1358,32 +1420,22 @@ protected: // CommandObjectThreadInfo //------------------------------------------------------------------------- -class CommandObjectThreadInfo : public CommandObjectParsed +class CommandObjectThreadInfo : public CommandObjectIterateOverThreads { public: CommandObjectThreadInfo (CommandInterpreter &interpreter) : - CommandObjectParsed (interpreter, - "thread info", - "Show an extended summary of information about thread(s) in a process.", - "thread info", - eFlagRequiresProcess | - eFlagTryTargetAPILock | - eFlagProcessMustBeLaunched | - eFlagProcessMustBePaused), + CommandObjectIterateOverThreads (interpreter, + "thread info", + "Show an extended summary of information about thread(s) in a process.", + "thread info", + eFlagRequiresProcess | + eFlagTryTargetAPILock | + eFlagProcessMustBeLaunched | + eFlagProcessMustBePaused), m_options (interpreter) { - CommandArgumentEntry arg; - CommandArgumentData thread_idx_arg; - - thread_idx_arg.arg_type = eArgTypeThreadIndex; - thread_idx_arg.arg_repetition = eArgRepeatStar; - - // There is only one variant this argument could be; put it into the argument entry. - arg.push_back (thread_idx_arg); - - // Push the data for the first argument into the m_arguments vector. - m_arguments.push_back (arg); + m_add_return = false; } class CommandOptions : public Options @@ -1399,7 +1451,8 @@ public: void OptionParsingStarting () { - m_json = false; + m_json_thread = false; + m_json_stopinfo = false; } virtual @@ -1416,10 +1469,14 @@ public: switch (short_option) { case 'j': - m_json = true; + m_json_thread = true; + break; + + case 's': + m_json_stopinfo = true; break; - default: + default: return Error("invalid short option character '%c'", short_option); } @@ -1432,7 +1489,8 @@ public: return g_option_table; } - bool m_json; + bool m_json_thread; + bool m_json_stopinfo; static OptionDefinition g_option_table[]; }; @@ -1451,81 +1509,16 @@ public: } virtual bool - DoExecute (Args& command, CommandReturnObject &result) + HandleOneThread (Thread &thread, CommandReturnObject &result) { - result.SetStatus (eReturnStatusSuccessFinishResult); Stream &strm = result.GetOutputStream(); - - if (command.GetArgumentCount() == 0) - { - Thread *thread = m_exe_ctx.GetThreadPtr(); - if (thread->GetDescription (strm, eDescriptionLevelFull, m_options.m_json)) - { - result.SetStatus (eReturnStatusSuccessFinishResult); - } - } - else if (command.GetArgumentCount() == 1 && ::strcmp (command.GetArgumentAtIndex(0), "all") == 0) - { - Process *process = m_exe_ctx.GetProcessPtr(); - uint32_t idx = 0; - for (ThreadSP thread_sp : process->Threads()) - { - if (idx != 0) - result.AppendMessage(""); - if (!thread_sp->GetDescription (strm, eDescriptionLevelFull, m_options.m_json)) - { - result.AppendErrorWithFormat ("error displaying info for thread: \"0x%4.4x\"\n", idx); - result.SetStatus (eReturnStatusFailed); - return false; - } - ++idx; - } - } - else + if (!thread.GetDescription (strm, eDescriptionLevelFull, m_options.m_json_thread, m_options.m_json_stopinfo)) { - const size_t num_args = command.GetArgumentCount(); - Process *process = m_exe_ctx.GetProcessPtr(); - Mutex::Locker locker (process->GetThreadList().GetMutex()); - std::vector<ThreadSP> thread_sps; - - for (size_t i = 0; i < num_args; i++) - { - bool success; - - uint32_t thread_idx = Args::StringToUInt32(command.GetArgumentAtIndex(i), 0, 0, &success); - if (!success) - { - result.AppendErrorWithFormat ("invalid thread specification: \"%s\"\n", command.GetArgumentAtIndex(i)); - result.SetStatus (eReturnStatusFailed); - return false; - } - - thread_sps.push_back(process->GetThreadList().FindThreadByIndexID(thread_idx)); - - if (!thread_sps[i]) - { - result.AppendErrorWithFormat ("no thread with index: \"%s\"\n", command.GetArgumentAtIndex(i)); - result.SetStatus (eReturnStatusFailed); - return false; - } - - } - - for (uint32_t i = 0; i < num_args; i++) - { - if (!thread_sps[i]->GetDescription (strm, eDescriptionLevelFull, m_options.m_json)) - { - result.AppendErrorWithFormat ("error displaying info for thread: \"%s\"\n", command.GetArgumentAtIndex(i)); - result.SetStatus (eReturnStatusFailed); - return false; - } - - if (i < num_args - 1) - result.AppendMessage(""); - } - + result.AppendErrorWithFormat ("error displaying info for thread: \"%d\"\n", thread.GetIndexID()); + result.SetStatus (eReturnStatusFailed); + return false; } - return result.Succeeded(); + return true; } CommandOptions m_options; @@ -1536,6 +1529,7 @@ OptionDefinition CommandObjectThreadInfo::CommandOptions::g_option_table[] = { { LLDB_OPT_SET_ALL, false, "json",'j', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Display the thread info in JSON format."}, + { LLDB_OPT_SET_ALL, false, "stop-info",'s', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Display the extended stop info in JSON format."}, { 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } }; @@ -1958,6 +1952,228 @@ CommandObjectThreadJump::CommandOptions::g_option_table[] = }; //------------------------------------------------------------------------- +// Next are the subcommands of CommandObjectMultiwordThreadPlan +//------------------------------------------------------------------------- + + +//------------------------------------------------------------------------- +// CommandObjectThreadPlanList +//------------------------------------------------------------------------- +class CommandObjectThreadPlanList : public CommandObjectIterateOverThreads +{ +public: + + class CommandOptions : public Options + { + public: + + CommandOptions (CommandInterpreter &interpreter) : + Options(interpreter) + { + // Keep default values of all options in one place: OptionParsingStarting () + OptionParsingStarting (); + } + + virtual + ~CommandOptions () + { + } + + virtual Error + SetOptionValue (uint32_t option_idx, const char *option_arg) + { + Error error; + const int short_option = m_getopt_table[option_idx].val; + + switch (short_option) + { + case 'i': + { + m_internal = true; + } + break; + case 'v': + { + m_verbose = true; + } + break; + default: + error.SetErrorStringWithFormat("invalid short option character '%c'", short_option); + break; + + } + return error; + } + + void + OptionParsingStarting () + { + m_verbose = false; + m_internal = false; + } + + const OptionDefinition* + GetDefinitions () + { + 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. + bool m_verbose; + bool m_internal; + }; + + CommandObjectThreadPlanList (CommandInterpreter &interpreter) : + CommandObjectIterateOverThreads (interpreter, + "thread plan list", + "Show thread plans for one or more threads. If no threads are specified, show the " + "currently selected thread. Use the thread-index \"all\" to see all threads.", + NULL, + eFlagRequiresProcess | + eFlagRequiresThread | + eFlagTryTargetAPILock | + eFlagProcessMustBeLaunched | + eFlagProcessMustBePaused ), + m_options(interpreter) + { + } + + ~CommandObjectThreadPlanList () + { + } + + virtual Options * + GetOptions () + { + return &m_options; + } + +protected: + virtual bool + HandleOneThread (Thread &thread, CommandReturnObject &result) + { + Stream &strm = result.GetOutputStream(); + DescriptionLevel desc_level = eDescriptionLevelFull; + if (m_options.m_verbose) + desc_level = eDescriptionLevelVerbose; + + thread.DumpThreadPlans (&strm, desc_level, m_options.m_internal, true); + return true; + } + CommandOptions m_options; +}; + +OptionDefinition +CommandObjectThreadPlanList::CommandOptions::g_option_table[] = +{ +{ LLDB_OPT_SET_1, false, "verbose", 'v', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Display more information about the thread plans"}, +{ LLDB_OPT_SET_1, false, "internal", 'i', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Display internal as well as user thread plans"}, +{ 0, false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL } +}; + +class CommandObjectThreadPlanDiscard : public CommandObjectParsed +{ +public: + CommandObjectThreadPlanDiscard (CommandInterpreter &interpreter) : + CommandObjectParsed (interpreter, + "thread plan discard", + "Discards thread plans up to and including the plan passed as the command argument." + "Only user visible plans can be discarded, use the index from \"thread plan list\"" + " without the \"-i\" argument.", + NULL, + eFlagRequiresProcess | + eFlagRequiresThread | + eFlagTryTargetAPILock | + eFlagProcessMustBeLaunched | + eFlagProcessMustBePaused ) + { + CommandArgumentEntry arg; + CommandArgumentData plan_index_arg; + + // Define the first (and only) variant of this arg. + plan_index_arg.arg_type = eArgTypeUnsignedInteger; + plan_index_arg.arg_repetition = eArgRepeatPlain; + + // There is only one variant this argument could be; put it into the argument entry. + arg.push_back (plan_index_arg); + + // Push the data for the first argument into the m_arguments vector. + m_arguments.push_back (arg); + } + + virtual ~CommandObjectThreadPlanDiscard () {} + + bool + DoExecute (Args& args, CommandReturnObject &result) + { + Thread *thread = m_exe_ctx.GetThreadPtr(); + if (args.GetArgumentCount() != 1) + { + result.AppendErrorWithFormat("Too many arguments, expected one - the thread plan index - but got %zu.", + args.GetArgumentCount()); + result.SetStatus (eReturnStatusFailed); + return false; + } + + bool success; + uint32_t thread_plan_idx = Args::StringToUInt32(args.GetArgumentAtIndex(0), 0, 0, &success); + if (!success) + { + result.AppendErrorWithFormat("Invalid thread index: \"%s\" - should be unsigned int.", + args.GetArgumentAtIndex(0)); + result.SetStatus (eReturnStatusFailed); + return false; + } + + if (thread_plan_idx == 0) + { + result.AppendErrorWithFormat("You wouldn't really want me to discard the base thread plan."); + result.SetStatus (eReturnStatusFailed); + return false; + } + + if (thread->DiscardUserThreadPlansUpToIndex(thread_plan_idx)) + { + result.SetStatus(eReturnStatusSuccessFinishNoResult); + return true; + } + else + { + result.AppendErrorWithFormat("Could not find User thread plan with index %s.", + args.GetArgumentAtIndex(0)); + result.SetStatus (eReturnStatusFailed); + return false; + } + } +}; + +//------------------------------------------------------------------------- +// CommandObjectMultiwordThreadPlan +//------------------------------------------------------------------------- + +class CommandObjectMultiwordThreadPlan : public CommandObjectMultiword +{ +public: + CommandObjectMultiwordThreadPlan(CommandInterpreter &interpreter) : + CommandObjectMultiword (interpreter, + "plan", + "A set of subcommands for accessing the thread plans controlling execution control on one or more threads.", + "thread plan <subcommand> [<subcommand objects]") + { + LoadSubCommand ("list", CommandObjectSP (new CommandObjectThreadPlanList (interpreter))); + LoadSubCommand ("discard", CommandObjectSP (new CommandObjectThreadPlanDiscard (interpreter))); + } + + virtual ~CommandObjectMultiwordThreadPlan () {} + + +}; + +//------------------------------------------------------------------------- // CommandObjectMultiwordThread //------------------------------------------------------------------------- @@ -2014,6 +2230,16 @@ CommandObjectMultiwordThread::CommandObjectMultiwordThread (CommandInterpreter & NULL, eStepTypeTraceOver, eStepScopeInstruction))); + + LoadSubCommand ("step-scripted", CommandObjectSP (new CommandObjectThreadStepWithTypeAndScope ( + interpreter, + "thread step-scripted", + "Step as instructed by the script class passed in the -C option.", + NULL, + eStepTypeScripted, + eStepScopeSource))); + + LoadSubCommand ("plan", CommandObjectSP (new CommandObjectMultiwordThreadPlan(interpreter))); } CommandObjectMultiwordThread::~CommandObjectMultiwordThread () |