diff options
| author | Ed Maste <emaste@FreeBSD.org> | 2015-02-06 21:38:51 +0000 | 
|---|---|---|
| committer | Ed Maste <emaste@FreeBSD.org> | 2015-02-06 21:38:51 +0000 | 
| commit | 205afe679855a4ce8149cdaa94d3f0868ce796dc (patch) | |
| tree | 09bc83f73246ee3c7a779605cd0122093d2a8a19 /source/Commands/CommandObjectThread.cpp | |
| parent | 0cac4ca3916ac24ab6139d03cbfd18db9e715bfe (diff) | |
Notes
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 e7a8652ac898..bace4e58b4ad 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 ()  | 
