Initial checkin of lldb code from internal Apple repo.

llvm-svn: 105619
diff --git a/lldb/source/Commands/CommandObjectThread.cpp b/lldb/source/Commands/CommandObjectThread.cpp
new file mode 100644
index 0000000..07777a1
--- /dev/null
+++ b/lldb/source/Commands/CommandObjectThread.cpp
@@ -0,0 +1,1277 @@
+//===-- CommandObjectThread.cpp ---------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CommandObjectThread.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Options.h"
+#include "lldb/Core/State.h"
+#include "lldb/Core/SourceManager.h"
+
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlan.h"
+#include "lldb/Target/ThreadPlanContinue.h"
+#include "lldb/Target/ThreadPlanStepInstruction.h"
+#include "lldb/Target/ThreadPlanStepOut.h"
+#include "lldb/Target/ThreadPlanStepRange.h"
+#include "lldb/Target/ThreadPlanStepInRange.h"
+#include "lldb/Symbol/LineTable.h"
+#include "lldb/Symbol/LineEntry.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+bool
+lldb_private::DisplayThreadInfo
+(
+    CommandInterpreter *interpreter,
+    Stream &strm,
+    Thread *thread,
+    bool only_threads_with_stop_reason,
+    bool show_source
+)
+{
+    if (thread)
+    {
+        if (only_threads_with_stop_reason)
+        {
+            StopReason thread_stop_reason = eStopReasonNone;
+            Thread::StopInfo thread_stop_info;
+            if (thread->GetStopInfo(&thread_stop_info))
+            {
+                thread_stop_reason = thread_stop_info.GetStopReason();
+                if (thread_stop_reason == eStopReasonNone)
+                    return false;
+            }
+        }
+
+        strm.Indent();
+        strm.Printf("%c ", thread->GetProcess().GetThreadList().GetCurrentThread().get() == thread ? '*' : ' ');
+
+        // Show one frame with only the first showing source
+        if (show_source)
+        {
+            DisplayFramesForExecutionContext (thread,
+                                              interpreter,
+                                              strm,
+                                              true,
+                                              0,    // Start at first frame
+                                              1,    // Number of frames to show
+                                              false,// Don't show the frame info since we already displayed most of it above...
+                                              1,    // Show source for the first frame
+                                              3,    // lines of source context before
+                                              3);   // lines of source context after
+        }
+        else
+        {
+            thread->DumpInfo (strm,
+                              true, // Dump the stop reason?
+                              true, // Dump the thread name?
+                              true, // Dump the queue name?
+                              0);   // Display context info for stack frame zero
+
+            strm.EOL();
+        }
+
+        return true;
+    }
+    return false;
+}
+
+size_t
+lldb_private::DisplayThreadsInfo
+(
+    CommandInterpreter *interpreter,
+    ExecutionContext *exe_ctx,
+    CommandReturnObject &result,
+    bool only_threads_with_stop_reason,
+    bool show_source
+)
+{
+    StreamString strm;
+
+    size_t num_thread_infos_dumped = 0;
+
+    if (!exe_ctx->process)
+        return 0;
+
+    const size_t num_threads = exe_ctx->process->GetThreadList().GetSize();
+    if (num_threads > 0)
+    {
+
+        for (uint32_t i = 0; i < num_threads; i++)
+        {
+            Thread *thread = exe_ctx->process->GetThreadList().GetThreadAtIndex(i).get();
+            if (thread)
+            {
+                if (DisplayThreadInfo (interpreter,
+                                       strm,
+                                       thread,
+                                       only_threads_with_stop_reason,
+                                       show_source))
+                    ++num_thread_infos_dumped;
+            }
+        }
+    }
+
+    if (num_thread_infos_dumped > 0)
+    {
+        if (num_thread_infos_dumped < num_threads)
+            result.GetOutputStream().Printf("%u of %u threads stopped with reasons:\n", num_thread_infos_dumped, num_threads);
+
+        result.GetOutputStream().GetString().append(strm.GetString());
+        result.SetStatus (eReturnStatusSuccessFinishNoResult);
+    }
+    return num_thread_infos_dumped;
+}
+
+
+size_t
+lldb_private::DisplayFramesForExecutionContext
+(
+    Thread *thread,
+    CommandInterpreter *interpreter,
+    Stream& strm,
+    bool ascending,
+    uint32_t first_frame,
+    uint32_t num_frames,
+    bool show_frame_info,
+    uint32_t num_frames_with_source,
+    uint32_t source_lines_before,
+    uint32_t source_lines_after
+)
+{
+    if (thread == NULL)
+        return 0;
+
+    size_t num_frames_displayed = 0;
+
+    if (num_frames == 0)
+        return 0;
+    
+    thread->DumpInfo (strm,
+                      true,     // Dump the stop reason?
+                      true,     // Dump the thread name?
+                      true,     // Dump the queue name?
+                      0);       // Dump info for stack frame zero
+    strm.EOL();
+    strm.IndentMore();
+
+    StackFrameSP frame_sp;
+    int frame_idx = 0;
+
+    if (ascending)
+    {
+        for (frame_idx = first_frame; frame_idx < first_frame + num_frames; ++frame_idx)
+        {
+            frame_sp = thread->GetStackFrameAtIndex (frame_idx);
+            if (frame_sp.get() == NULL)
+                break;
+
+            if (DisplayFrameForExecutionContext (thread,
+                                                 frame_sp.get(),
+                                                 interpreter,
+                                                 strm,
+                                                 show_frame_info,
+                                                 num_frames_with_source > first_frame - frame_idx,
+                                                 source_lines_before,
+                                                 source_lines_after) == false)
+                break;
+
+            ++num_frames_displayed;
+        }
+    }
+    else
+    {
+        for (frame_idx = first_frame + num_frames - 1; frame_idx >= first_frame; --frame_idx)
+        {
+            frame_sp = thread->GetStackFrameAtIndex (frame_idx);
+            if (frame_sp == NULL)
+                break;
+
+            if (DisplayFrameForExecutionContext (thread,
+                                                 frame_sp.get(),
+                                                 interpreter,
+                                                 strm,
+                                                 show_frame_info,
+                                                 num_frames_with_source > first_frame - frame_idx,
+                                                 source_lines_before,
+                                                 source_lines_after) == false)
+                break;
+
+            ++num_frames_displayed;
+        }
+    }
+    strm.IndentLess();
+    return num_frames_displayed;
+}
+
+bool
+lldb_private::DisplayFrameForExecutionContext
+(
+    Thread *thread,
+    StackFrame *frame,
+    CommandInterpreter *interpreter,
+    Stream& strm,
+    bool show_frame_info,
+    bool show_source,
+    uint32_t source_lines_before,
+    uint32_t source_lines_after
+)
+{
+    // thread and frame must be filled in prior to calling this function
+    if (thread && frame)
+    {
+        if (show_frame_info)
+        {
+            strm.Indent();
+            frame->Dump (&strm, true);
+            strm.EOL();
+        }
+
+        SymbolContext sc (frame->GetSymbolContext(eSymbolContextCompUnit | eSymbolContextLineEntry));
+
+        if (show_source && sc.comp_unit && sc.line_entry.IsValid())
+        {
+            interpreter->GetSourceManager().DisplaySourceLinesWithLineNumbers (
+                    sc.line_entry.file,
+                    sc.line_entry.line,
+                    3,
+                    3,
+                    "->",
+                    &strm);
+
+        }
+        return true;
+    }
+    return false;
+}
+
+
+//-------------------------------------------------------------------------
+// CommandObjectThreadBacktrace
+//-------------------------------------------------------------------------
+
+class CommandObjectThreadBacktrace : public CommandObject
+{
+public:
+
+    CommandObjectThreadBacktrace () :
+        CommandObject ("thread backtrace",
+                       "Shows the stack for one or more threads.",
+                       "thread backtrace [<thread-idx>] ...",
+                       eFlagProcessMustBeLaunched | eFlagProcessMustBePaused),
+        m_ascending (true)
+    {
+    }
+
+    ~CommandObjectThreadBacktrace()
+    {
+    }
+
+
+    bool
+    Execute
+    (
+        Args& command,
+        CommandContext *context,
+        CommandInterpreter *interpreter,
+        CommandReturnObject &result
+    )
+    {
+        if (command.GetArgumentCount() == 0)
+        {
+            ExecutionContext exe_ctx(context->GetExecutionContext());
+            if (exe_ctx.thread)
+            {
+                bool show_frame_info = true;
+                uint32_t num_frames_with_source = 0; // Don't show any frasmes with source when backtracing
+                if (DisplayFramesForExecutionContext (exe_ctx.thread,
+                                                      interpreter,
+                                                      result.GetOutputStream(),
+                                                      m_ascending,
+                                                      0,
+                                                      UINT32_MAX,
+                                                      show_frame_info,
+                                                      num_frames_with_source,
+                                                      3,
+                                                      3))
+                {
+                    result.SetStatus (eReturnStatusSuccessFinishResult);
+                }
+            }
+            else
+            {
+                result.AppendError ("invalid thread");
+                result.SetStatus (eReturnStatusFailed);
+            }
+        }
+        else
+        {
+            result.AppendError ("backtrace doesn't take arguments (for now)");
+            result.SetStatus (eReturnStatusFailed);
+        }
+        return result.Succeeded();
+    }
+protected:
+    bool m_ascending;
+};
+
+
+typedef enum StepScope
+{
+    eStepScopeSource,
+    eStepScopeInstruction
+};
+
+class CommandObjectThreadStepWithTypeAndScope : public CommandObject
+{
+public:
+
+    class CommandOptions : public Options
+    {
+    public:
+
+        CommandOptions () :
+            Options()
+        {
+            // Keep default values of all options in one place: ResetOptionValues ()
+            ResetOptionValues ();
+        }
+
+        virtual
+        ~CommandOptions ()
+        {
+        }
+
+        virtual Error
+        SetOptionValue (int option_idx, const char *option_arg)
+        {
+            Error error;
+            char short_option = (char) m_getopt_table[option_idx].val;
+
+            switch (short_option)
+            {
+                case 'a':
+                {
+                    bool success;
+                    m_avoid_no_debug =  Args::StringToBoolean (option_arg, true, &success);
+                    if (!success)
+                        error.SetErrorStringWithFormat("Invalid boolean value for option '%c'.\n", short_option);
+                }
+                break;
+                case 'm':
+                {
+                    bool found_one = false;
+                    OptionEnumValueElement *enum_values = g_option_table[option_idx].enum_values; 
+                    m_run_mode = (lldb::RunMode) Args::StringToOptionEnum(option_arg, enum_values, eOnlyDuringStepping, &found_one);
+                    if (!found_one)
+                        error.SetErrorStringWithFormat("Invalid enumeration value for option '%c'.\n", short_option);
+                }
+                break;
+                default:
+                    error.SetErrorStringWithFormat("Invalid short option character '%c'.\n", short_option);
+                    break;
+
+            }
+            return error;
+        }
+
+        void
+        ResetOptionValues ()
+        {
+            Options::ResetOptionValues();
+            m_avoid_no_debug = true;
+            m_run_mode = eOnlyDuringStepping;
+        }
+
+        const lldb::OptionDefinition*
+        GetDefinitions ()
+        {
+            return g_option_table;
+        }
+
+        // Options table: Required for subclasses of Options.
+
+        static lldb::OptionDefinition g_option_table[];
+
+        // Instance variables to hold the values for command options.
+        bool m_avoid_no_debug;
+        RunMode m_run_mode;
+    };
+
+    CommandObjectThreadStepWithTypeAndScope (const char *name,
+                         const char *help,
+                         const char *syntax,
+                         uint32_t flags,
+                         StepType step_type,
+                         StepScope step_scope) :
+        CommandObject (name, help, syntax, flags),
+        m_step_type (step_type),
+        m_step_scope (step_scope),
+        m_options ()
+    {
+    }
+
+    virtual
+    ~CommandObjectThreadStepWithTypeAndScope ()
+    {
+    }
+
+    virtual
+    Options *
+    GetOptions ()
+    {
+        return &m_options;
+    }
+
+    virtual bool
+    Execute (Args& command,
+             CommandContext *context,
+             CommandInterpreter *interpreter,
+             CommandReturnObject &result)
+    {
+        Process *process = context->GetExecutionContext().process;
+        bool synchronous_execution = interpreter->GetSynchronous();
+
+        if (process == NULL)
+        {
+            result.AppendError ("need a valid process to step");
+            result.SetStatus (eReturnStatusFailed);
+
+        }
+        else
+        {
+            const uint32_t num_threads = process->GetThreadList().GetSize();
+            Thread *thread = NULL;
+
+            if (command.GetArgumentCount() == 0)
+            {
+                thread = process->GetThreadList().GetCurrentThread().get();
+                if (thread == NULL)
+                {
+                    result.AppendError ("no current thread in process");
+                    result.SetStatus (eReturnStatusFailed);
+                    return false;
+                }
+            }
+            else
+            {
+                const char *thread_idx_cstr = command.GetArgumentAtIndex(0);
+                uint32_t step_thread_idx = Args::StringToUInt32 (thread_idx_cstr, LLDB_INVALID_INDEX32);
+                if (step_thread_idx == LLDB_INVALID_INDEX32)
+                {
+                    result.AppendErrorWithFormat ("Invalid thread index '%s'.\n", thread_idx_cstr);
+                    result.SetStatus (eReturnStatusFailed);
+                    return false;
+                }
+                thread = process->GetThreadList().FindThreadByIndexID(step_thread_idx).get();
+                if (thread == NULL)
+                {
+                    result.AppendErrorWithFormat ("Thread index %u is out of range (valid values are 0 - %u).\n", 
+                                                  step_thread_idx, 0, num_threads);
+                    result.SetStatus (eReturnStatusFailed);
+                    return false;
+                }
+            }
+
+            const bool abort_other_plans = false;
+            const lldb::RunMode stop_other_threads = m_options.m_run_mode;
+            
+            // This is a bit unfortunate, but not all the commands in this command object support
+            // only while stepping, so I use the bool for them.
+            bool bool_stop_other_threads;
+            if (m_options.m_run_mode == eAllThreads)
+                bool_stop_other_threads = false;
+            else
+                bool_stop_other_threads = true;
+
+            if (m_step_type == eStepTypeInto)
+            {
+                StackFrame *frame = thread->GetStackFrameAtIndex(0).get();
+                ThreadPlan *new_plan;
+
+                if (frame->HasDebugInformation ())
+                {
+                    new_plan = thread->QueueThreadPlanForStepRange (abort_other_plans, m_step_type, 
+                                                                    frame->GetSymbolContext(eSymbolContextEverything).line_entry.range, 
+                                                                    frame->GetSymbolContext(eSymbolContextEverything), 
+                                                                    stop_other_threads);
+                    if (new_plan)
+                    {
+                        ThreadPlanStepInRange *real_plan = dynamic_cast<ThreadPlanStepInRange *> (new_plan);
+                        if (real_plan)
+                        {
+                            if (m_options.m_avoid_no_debug)
+                            {
+                                real_plan->GetFlags().Set (ThreadPlanShouldStopHere::eAvoidNoDebug);
+                            }
+                            else
+                            {
+                                real_plan->GetFlags().Clear (ThreadPlanShouldStopHere::eAvoidNoDebug);
+                            }
+                        }
+                    }
+                }
+                else
+                    new_plan = thread->QueueThreadPlanForStepSingleInstruction (false, abort_other_plans, bool_stop_other_threads);
+
+                process->GetThreadList().SetCurrentThreadByID (thread->GetID());
+                process->Resume ();
+            }
+            else if (m_step_type == eStepTypeOver)
+            {
+                StackFrame *frame = thread->GetStackFrameAtIndex(0).get();
+                ThreadPlan *new_plan;
+
+                if (frame->HasDebugInformation())
+                    new_plan = thread->QueueThreadPlanForStepRange (abort_other_plans, 
+                                                                    m_step_type, 
+                                                                    frame->GetSymbolContext(eSymbolContextEverything).line_entry.range, 
+                                                                    frame->GetSymbolContext(eSymbolContextEverything), 
+                                                                    stop_other_threads);
+                else
+                    new_plan = thread->QueueThreadPlanForStepSingleInstruction (true, 
+                                                                                abort_other_plans, 
+                                                                                bool_stop_other_threads);
+
+                // FIXME: This will keep the step plan on the thread stack when we hit a breakpoint while stepping over.
+                // Maybe there should be a parameter to control this.
+                new_plan->SetOkayToDiscard(false);
+
+                process->GetThreadList().SetCurrentThreadByID (thread->GetID());
+                process->Resume ();
+            }
+            else if (m_step_type == eStepTypeTrace)
+            {
+                thread->QueueThreadPlanForStepSingleInstruction (false, abort_other_plans, bool_stop_other_threads);
+                process->GetThreadList().SetCurrentThreadByID (thread->GetID());
+                process->Resume ();
+            }
+            else if (m_step_type == eStepTypeTraceOver)
+            {
+                thread->QueueThreadPlanForStepSingleInstruction (true, abort_other_plans, bool_stop_other_threads);
+                process->GetThreadList().SetCurrentThreadByID (thread->GetID());
+                process->Resume ();
+            }
+            else if (m_step_type == eStepTypeOut)
+            {
+                ThreadPlan *new_plan;
+
+                new_plan = thread->QueueThreadPlanForStepOut (abort_other_plans, NULL, false, bool_stop_other_threads, eVoteYes, eVoteNoOpinion);
+                // FIXME: This will keep the step plan on the thread stack when we hit a breakpoint while stepping over.
+                // Maybe there should be a parameter to control this.
+                new_plan->SetOkayToDiscard(false);
+
+                process->GetThreadList().SetCurrentThreadByID (thread->GetID());
+                process->Resume ();
+            }
+            else
+            {
+                result.AppendError ("step type is not supported");
+                result.SetStatus (eReturnStatusFailed);
+            }
+            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);
+                //  }
+                process->GetThreadList().SetCurrentThreadByID (thread->GetID());
+                result.SetDidChangeProcessState (true);
+                result.AppendMessageWithFormat ("Process %i %s\n", process->GetID(), StateAsCString (state));
+                result.SetStatus (eReturnStatusSuccessFinishNoResult);
+            }
+        }
+        return result.Succeeded();
+    }
+
+protected:
+    StepType m_step_type;
+    StepScope m_step_scope;
+    CommandOptions m_options;
+};
+
+static lldb::OptionEnumValueElement
+g_tri_running_mode[] =
+{
+{ eOnlyThisThread,     "thisThread",    "Run only this thread"},
+{ eAllThreads,         "allThreads",    "Run all threads"},
+{ eOnlyDuringStepping, "whileStepping", "Run only this thread while stepping"},
+{ 0, NULL, NULL }
+};
+
+static lldb::OptionEnumValueElement
+g_duo_running_mode[] =
+{
+{ eOnlyThisThread,     "thisThread",    "Run only this thread"},
+{ eAllThreads,         "allThreads",    "Run all threads"},
+{ 0, NULL, NULL }
+};
+
+lldb::OptionDefinition
+CommandObjectThreadStepWithTypeAndScope::CommandOptions::g_option_table[] =
+{
+{ 0, true, "avoid_no_debug", 'a', required_argument,       NULL, 0, "<avoid_no_debug>",        "Should step-in step over functions with no debug information"},
+{ 0, true, "run_mode", 'm', required_argument,       g_tri_running_mode, 0, "<run_mode>",        "Determine how to run other threads while stepping this one"},
+{ 0, false, NULL, 0, 0, NULL, 0, NULL, NULL }
+};
+
+
+//-------------------------------------------------------------------------
+// CommandObjectThreadContinue
+//-------------------------------------------------------------------------
+
+class CommandObjectThreadContinue : public CommandObject
+{
+public:
+
+    CommandObjectThreadContinue () :
+        CommandObject ("thread continue",
+                       "Continues execution of one or more threads in an active process.",
+                       "thread continue <thread-index> [<thread-index> ...]",
+                       eFlagProcessMustBeLaunched | eFlagProcessMustBePaused)
+    {
+    }
+
+
+    virtual
+    ~CommandObjectThreadContinue ()
+    {
+    }
+
+    virtual bool
+    Execute (Args& command,
+             CommandContext *context,
+             CommandInterpreter *interpreter,
+             CommandReturnObject &result)
+    {
+        bool synchronous_execution = interpreter->GetSynchronous ();
+
+        if (!context->GetTarget())
+        {
+            result.AppendError ("invalid target, set executable file using 'file' command");
+            result.SetStatus (eReturnStatusFailed);
+            return false;
+        }
+
+        Process *process = context->GetExecutionContext().process;
+        if (process == NULL)
+        {
+            result.AppendError ("no process exists. Cannot continue");
+            result.SetStatus (eReturnStatusFailed);
+            return false;
+        }
+
+        StateType state = process->GetState();
+        if ((state == eStateCrashed) || (state == eStateStopped) || (state == eStateSuspended))
+        {
+            const uint32_t num_threads = process->GetThreadList().GetSize();
+            uint32_t idx;
+            const size_t argc = command.GetArgumentCount();
+            if (argc > 0)
+            {
+                std::vector<uint32_t> resume_thread_indexes;
+                for (uint32_t i=0; i<argc; ++i)
+                {
+                    idx = Args::StringToUInt32 (command.GetArgumentAtIndex(0), LLDB_INVALID_INDEX32);
+                    if (idx < num_threads)
+                        resume_thread_indexes.push_back(idx);
+                    else
+                        result.AppendWarningWithFormat("Thread index %u out of range.\n", idx);
+                }
+
+                if (resume_thread_indexes.empty())
+                {
+                    result.AppendError ("no valid thread indexes were specified");
+                    result.SetStatus (eReturnStatusFailed);
+                    return false;
+                }
+                else
+                {
+                    result.AppendMessage ("Resuming thread ");
+                    for (idx=0; idx<num_threads; ++idx)
+                    {
+                        Thread *thread = process->GetThreadList().GetThreadAtIndex(idx).get();
+                        if (find(resume_thread_indexes.begin(), resume_thread_indexes.end(), idx) != resume_thread_indexes.end())
+                        {
+                            result.AppendMessageWithFormat ("%u ", idx);
+                            thread->SetResumeState (eStateRunning);
+                        }
+                        else
+                        {
+                            thread->SetResumeState (eStateSuspended);
+                        }
+                    }
+                    result.AppendMessageWithFormat ("in process %i\n", process->GetID());
+                }
+            }
+            else
+            {
+                Thread *current_thread = process->GetThreadList().GetCurrentThread().get();
+                if (current_thread == NULL)
+                {
+                    result.AppendError ("the process doesn't have a current thread");
+                    result.SetStatus (eReturnStatusFailed);
+                    return false;
+                }
+                // Set the actions that the threads should each take when resuming
+                for (idx=0; idx<num_threads; ++idx)
+                {
+                    Thread *thread = process->GetThreadList().GetThreadAtIndex(idx).get();
+                    if (thread == current_thread)
+                    {
+                        result.AppendMessageWithFormat ("Resuming thread 0x%4.4x in process %i\n", thread->GetID(), process->GetID());
+                        thread->SetResumeState (eStateRunning);
+                    }
+                    else
+                    {
+                        thread->SetResumeState (eStateSuspended);
+                    }
+                }
+            }
+
+            Error error (process->Resume());
+            if (error.Success())
+            {
+                result.AppendMessageWithFormat ("Resuming process %i\n", process->GetID());
+                if (synchronous_execution)
+                {
+                    StateType state = process->WaitForProcessToStop (NULL);
+
+                    result.SetDidChangeProcessState (true);
+                    result.AppendMessageWithFormat ("Process %i %s\n", process->GetID(), StateAsCString (state));
+                    result.SetStatus (eReturnStatusSuccessFinishNoResult);
+                }
+                else
+                {
+                    result.SetStatus (eReturnStatusSuccessContinuingNoResult);
+                }
+            }
+            else
+            {
+                result.AppendErrorWithFormat("Failed to resume process: %s\n", error.AsCString());
+                result.SetStatus (eReturnStatusFailed);
+            }
+        }
+        else
+        {
+            result.AppendErrorWithFormat ("Process cannot be continued from its current state (%s).\n",
+                                          StateAsCString(state));
+            result.SetStatus (eReturnStatusFailed);
+        }
+
+        return result.Succeeded();
+    }
+
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectThreadUntil
+//-------------------------------------------------------------------------
+
+class CommandObjectThreadUntil : public CommandObject
+{
+public:
+
+    class CommandOptions : public Options
+    {
+    public:
+        uint32_t m_thread_idx;
+        uint32_t m_frame_idx;
+
+        CommandOptions () :
+            Options(),
+            m_thread_idx(LLDB_INVALID_THREAD_ID),
+            m_frame_idx(LLDB_INVALID_FRAME_ID)
+        {
+            // Keep default values of all options in one place: ResetOptionValues ()
+            ResetOptionValues ();
+        }
+
+        virtual
+        ~CommandOptions ()
+        {
+        }
+
+        virtual Error
+        SetOptionValue (int option_idx, const char *option_arg)
+        {
+            Error error;
+            char short_option = (char) m_getopt_table[option_idx].val;
+
+            switch (short_option)
+            {
+                case 't':
+                {
+                    uint32_t m_thread_idx = Args::StringToUInt32 (option_arg, LLDB_INVALID_INDEX32);
+                    if (m_thread_idx == LLDB_INVALID_INDEX32)
+                    {
+                        error.SetErrorStringWithFormat ("Invalid thread index '%s'.\n", option_arg);
+                    }
+                }
+                break;
+                case 'f':
+                {
+                    m_frame_idx = Args::StringToUInt32 (option_arg, LLDB_INVALID_FRAME_ID);
+                    if (m_frame_idx == LLDB_INVALID_FRAME_ID)
+                    {
+                        error.SetErrorStringWithFormat ("Invalid frame index '%s'.\n", option_arg);
+                    }
+                }
+                break;
+                case 'm':
+                {
+                    bool found_one = false;
+                    OptionEnumValueElement *enum_values = g_option_table[option_idx].enum_values; 
+                    lldb::RunMode run_mode = (lldb::RunMode) Args::StringToOptionEnum(option_arg, enum_values, eOnlyDuringStepping, &found_one);
+
+                    if (!found_one)
+                        error.SetErrorStringWithFormat("Invalid enumeration value for option '%c'.\n", short_option);
+                    else if (run_mode == eAllThreads)
+                        m_stop_others = false;
+                    else
+                        m_stop_others = true;
+        
+                }
+                break;
+                default:
+                    error.SetErrorStringWithFormat("Invalid short option character '%c'.\n", short_option);
+                    break;
+
+            }
+            return error;
+        }
+
+        void
+        ResetOptionValues ()
+        {
+            Options::ResetOptionValues();
+            m_thread_idx = LLDB_INVALID_THREAD_ID;
+            m_frame_idx = 0;
+            m_stop_others = false;
+        }
+
+        const lldb::OptionDefinition*
+        GetDefinitions ()
+        {
+            return g_option_table;
+        }
+
+        uint32_t m_step_thread_idx;
+        bool m_stop_others;
+
+        // Options table: Required for subclasses of Options.
+
+        static lldb::OptionDefinition g_option_table[];
+
+        // Instance variables to hold the values for command options.
+    };
+
+    CommandObjectThreadUntil () :
+        CommandObject ("thread until",
+                       "Runs the current or specified thread until it reaches a given line number or leaves the current function.",
+                       "thread until [<cmd-options>] <line-number>",
+                       eFlagProcessMustBeLaunched | eFlagProcessMustBePaused),
+        m_options ()
+    {
+    }
+
+
+    virtual
+    ~CommandObjectThreadUntil ()
+    {
+    }
+
+    virtual
+    Options *
+    GetOptions ()
+    {
+        return &m_options;
+    }
+
+    virtual bool
+    Execute (Args& command,
+             CommandContext *context,
+             CommandInterpreter *interpreter,
+             CommandReturnObject &result)
+    {
+        bool synchronous_execution = interpreter->GetSynchronous ();
+
+        if (!context->GetTarget())
+        {
+            result.AppendError ("invalid target, set executable file using 'file' command");
+            result.SetStatus (eReturnStatusFailed);
+            return false;
+        }
+
+        Process *process = context->GetExecutionContext().process;
+        if (process == NULL)
+        {
+            result.AppendError ("need a valid process to step");
+            result.SetStatus (eReturnStatusFailed);
+
+        }
+        else
+        {
+            Thread *thread = NULL;
+            uint32_t line_number;
+
+            if (command.GetArgumentCount() != 1)
+            {
+                result.AppendErrorWithFormat ("No line number provided:\n%s", GetSyntax());
+                result.SetStatus (eReturnStatusFailed);
+                return false;
+            }
+
+            line_number = Args::StringToUInt32 (command.GetArgumentAtIndex(0), UINT32_MAX);
+            if (line_number == UINT32_MAX)
+            {
+                result.AppendErrorWithFormat ("Invalid line number: '%s'.\n", command.GetArgumentAtIndex(0));
+                result.SetStatus (eReturnStatusFailed);
+                return false;
+            }
+
+            if (m_options.m_thread_idx == LLDB_INVALID_THREAD_ID)
+            {
+                thread = process->GetThreadList().GetCurrentThread().get();
+            }
+            else
+            {
+                thread = process->GetThreadList().GetThreadAtIndex(m_options.m_thread_idx).get();
+            }
+
+            if (thread == NULL)
+            {
+                const uint32_t num_threads = process->GetThreadList().GetSize();
+                result.AppendErrorWithFormat ("Thread index %u is out of range (valid values are 0 - %u).\n", m_options.m_thread_idx, 0, num_threads);
+                result.SetStatus (eReturnStatusFailed);
+                return false;
+            }
+
+            const bool abort_other_plans = true;
+
+            StackFrame *frame = thread->GetStackFrameAtIndex(m_options.m_frame_idx).get();
+            if (frame == NULL)
+            {
+
+                result.AppendErrorWithFormat ("Frame index %u is out of range for thread %u.\n", m_options.m_frame_idx, m_options.m_thread_idx);
+                result.SetStatus (eReturnStatusFailed);
+                return false;
+            }
+
+            ThreadPlan *new_plan;
+
+            if (frame->HasDebugInformation ())
+            {
+                // Finally we got here...  Translate the given line number to a bunch of addresses:
+                SymbolContext sc(frame->GetSymbolContext (eSymbolContextCompUnit));
+                LineTable *line_table = NULL;
+                if (sc.comp_unit)
+                    line_table = sc.comp_unit->GetLineTable();
+
+                if (line_table == NULL)
+                {
+                    result.AppendErrorWithFormat ("Failed to resolve the line table for frame %u of thread index %u.\n",
+                                                 m_options.m_frame_idx, m_options.m_thread_idx);
+                    result.SetStatus (eReturnStatusFailed);
+                    return false;
+                }
+
+                LineEntry function_start;
+                uint32_t index_ptr = 0, end_ptr;
+                std::vector<addr_t> address_list;
+
+                // Find the beginning & end index of the
+                AddressRange fun_addr_range = sc.function->GetAddressRange();
+                Address fun_start_addr = fun_addr_range.GetBaseAddress();
+                line_table->FindLineEntryByAddress (fun_start_addr, function_start, &index_ptr);
+
+                Address fun_end_addr(fun_start_addr.GetSection(), fun_start_addr.GetOffset() + fun_addr_range.GetByteSize());
+                line_table->FindLineEntryByAddress (fun_end_addr, function_start, &end_ptr);
+
+                while (index_ptr <= end_ptr)
+                {
+                    LineEntry line_entry;
+                    index_ptr = sc.comp_unit->FindLineEntry(index_ptr, line_number, sc.comp_unit, &line_entry);
+                    if (index_ptr == UINT32_MAX)
+                        break;
+
+                    addr_t address = line_entry.range.GetBaseAddress().GetLoadAddress(process);
+                    if (address != LLDB_INVALID_ADDRESS)
+                        address_list.push_back (address);
+                    index_ptr++;
+                }
+
+                new_plan = thread->QueueThreadPlanForStepUntil (abort_other_plans, address_list.data(), address_list.size(), m_options.m_stop_others);
+                new_plan->SetOkayToDiscard(false);
+            }
+            else
+            {
+                result.AppendErrorWithFormat ("Frame index %u of thread %u has no debug information.\n", m_options.m_frame_idx, m_options.m_thread_idx);
+                result.SetStatus (eReturnStatusFailed);
+                return false;
+
+            }
+
+            process->GetThreadList().SetCurrentThreadByID (m_options.m_thread_idx);
+            Error error (process->Resume ());
+            if (error.Success())
+            {
+                result.AppendMessageWithFormat ("Resuming process %i\n", process->GetID());
+                if (synchronous_execution)
+                {
+                    StateType state = process->WaitForProcessToStop (NULL);
+
+                    result.SetDidChangeProcessState (true);
+                    result.AppendMessageWithFormat ("Process %i %s\n", process->GetID(), StateAsCString (state));
+                    result.SetStatus (eReturnStatusSuccessFinishNoResult);
+                }
+                else
+                {
+                    result.SetStatus (eReturnStatusSuccessContinuingNoResult);
+                }
+            }
+            else
+            {
+                result.AppendErrorWithFormat("Failed to resume process: %s.\n", error.AsCString());
+                result.SetStatus (eReturnStatusFailed);
+            }
+
+        }
+        return result.Succeeded();
+    }
+protected:
+    CommandOptions m_options;
+
+};
+
+lldb::OptionDefinition
+CommandObjectThreadUntil::CommandOptions::g_option_table[] =
+{
+{ 0, true, "frame", 'f', required_argument,       NULL, 0, "<frame>",        "Frame index for until operation - defaults to 0"},
+{ 0, true, "thread", 't', required_argument,       NULL, 0, "<thread>",      "Thread index for the thread for until operation"},
+{ 0, true, "run_mode", 'm', required_argument,       g_duo_running_mode, 0, "<run_mode>",        "Determine how to run other threads while stepping this one"},
+{ 0, false, NULL, 0, 0, NULL, 0, NULL, NULL }
+};
+
+
+//-------------------------------------------------------------------------
+// CommandObjectThreadSelect
+//-------------------------------------------------------------------------
+
+class CommandObjectThreadSelect : public CommandObject
+{
+public:
+
+    CommandObjectThreadSelect () :
+        CommandObject ("thread select",
+                         "Selects a threads as the currently active thread.",
+                         "thread select <thread-index>",
+                         eFlagProcessMustBeLaunched | eFlagProcessMustBePaused)
+    {
+    }
+
+
+    virtual
+    ~CommandObjectThreadSelect ()
+    {
+    }
+
+    virtual bool
+    Execute (Args& command,
+             CommandContext *context,
+             CommandInterpreter *interpreter,
+             CommandReturnObject &result)
+    {
+        Process *process = context->GetExecutionContext().process;
+        if (process == NULL)
+        {
+            result.AppendError ("no process");
+            result.SetStatus (eReturnStatusFailed);
+            return false;
+        }
+        else if (command.GetArgumentCount() != 1)
+        {
+            result.AppendErrorWithFormat("'%s' takes exactly one thread index argument:\nUsage: \n", m_cmd_name.c_str(), m_cmd_syntax.c_str());
+            result.SetStatus (eReturnStatusFailed);
+            return false;
+        }
+
+        uint32_t index_id = Args::StringToUInt32(command.GetArgumentAtIndex(0), 0, 0);
+
+        Thread *new_thread = process->GetThreadList().FindThreadByIndexID(index_id).get();
+        if (new_thread == NULL)
+        {
+            result.AppendErrorWithFormat ("Invalid thread #%s.\n", command.GetArgumentAtIndex(0));
+            result.SetStatus (eReturnStatusFailed);
+            return false;
+        }
+
+        process->GetThreadList().SetCurrentThreadByID(new_thread->GetID());
+        
+        DisplayThreadInfo (interpreter,
+                           result.GetOutputStream(),
+                           new_thread,
+                           false,
+                           true);
+
+        return result.Succeeded();
+    }
+
+};
+
+
+//-------------------------------------------------------------------------
+// CommandObjectThreadList
+//-------------------------------------------------------------------------
+
+CommandObjectThreadList::CommandObjectThreadList ():
+    CommandObject ("thread list",
+                     "Shows a summary of all current threads in a process.",
+                     "thread list",
+                     eFlagProcessMustBeLaunched | eFlagProcessMustBePaused)
+{
+}
+
+CommandObjectThreadList::~CommandObjectThreadList()
+{
+}
+
+bool
+CommandObjectThreadList::Execute
+(
+    Args& command,
+    CommandContext *context,
+    CommandInterpreter *interpreter,
+    CommandReturnObject &result
+)
+{
+    StreamString &strm = result.GetOutputStream();
+    result.SetStatus (eReturnStatusSuccessFinishNoResult);
+    ExecutionContext exe_ctx(context->GetExecutionContext());
+    if (exe_ctx.process)
+    {
+        const StateType state = exe_ctx.process->GetState();
+
+        if (StateIsStoppedState(state))
+        {
+            if (state == eStateExited)
+            {
+                int exit_status = exe_ctx.process->GetExitStatus();
+                const char *exit_description = exe_ctx.process->GetExitDescription();
+                strm.Printf ("Process %d exited with status = %i (0x%8.8x) %s\n",
+                                      exe_ctx.process->GetID(),
+                                      exit_status,
+                                      exit_status,
+                                      exit_description ? exit_description : "");
+            }
+            else
+            {
+                strm.Printf ("Process %d state is %s\n", exe_ctx.process->GetID(), StateAsCString (state));
+                if (exe_ctx.thread == NULL)
+                    exe_ctx.thread = exe_ctx.process->GetThreadList().GetThreadAtIndex(0).get();
+                if (exe_ctx.thread != NULL)
+                {
+                    DisplayThreadsInfo (interpreter, &exe_ctx, result, false, false);
+                }
+                else
+                {
+                    result.AppendError ("no valid thread found in current process");
+                    result.SetStatus (eReturnStatusFailed);
+                }
+            }
+        }
+        else
+        {
+            result.AppendError ("process is currently running");
+            result.SetStatus (eReturnStatusFailed);
+        }
+    }
+    else
+    {
+        result.AppendError ("no current location or status available");
+        result.SetStatus (eReturnStatusFailed);
+    }
+    return result.Succeeded();
+}
+
+//-------------------------------------------------------------------------
+// CommandObjectMultiwordThread
+//-------------------------------------------------------------------------
+
+CommandObjectMultiwordThread::CommandObjectMultiwordThread (CommandInterpreter *interpreter) :
+    CommandObjectMultiword ("thread",
+                            "A set of commands for operating on one or more thread within a running process.",
+                            "thread <subcommand> [<subcommand-options>]")
+{
+    LoadSubCommand (CommandObjectSP (new CommandObjectThreadBacktrace ()), "backtrace", interpreter);
+    LoadSubCommand (CommandObjectSP (new CommandObjectThreadContinue ()), "continue", interpreter);
+    LoadSubCommand (CommandObjectSP (new CommandObjectThreadList ()), "list", interpreter);
+    LoadSubCommand (CommandObjectSP (new CommandObjectThreadSelect ()), "select", interpreter);
+    LoadSubCommand (CommandObjectSP (new CommandObjectThreadUntil ()), "until", interpreter);
+    LoadSubCommand (CommandObjectSP (new CommandObjectThreadStepWithTypeAndScope ("thread step-in",
+                                                                                  "Source level single step in in specified thread (current thread, if none specified).",
+                                                                                  "thread step-in [<thread-id>]",
+                                                                                  eFlagProcessMustBeLaunched | eFlagProcessMustBePaused,
+                                                                                  eStepTypeInto,
+                                                                                  eStepScopeSource)),
+                    "step-in", interpreter);
+
+    LoadSubCommand (CommandObjectSP (new CommandObjectThreadStepWithTypeAndScope ("thread step-out",
+                                                                                      "Source level single step out in specified thread (current thread, if none specified).",
+                                                                                      "thread step-out [<thread-id>]",
+                                                                                      eFlagProcessMustBeLaunched | eFlagProcessMustBePaused,
+                                                                                      eStepTypeOut,
+                                                                                      eStepScopeSource)),
+                    "step-out", interpreter);
+
+    LoadSubCommand (CommandObjectSP (new CommandObjectThreadStepWithTypeAndScope ("thread step-over",
+                                                                                      "Source level single step over in specified thread (current thread, if none specified).",
+                                                                                      "thread step-over [<thread-id>]",
+                                                                                      eFlagProcessMustBeLaunched | eFlagProcessMustBePaused,
+                                                                                      eStepTypeOver,
+                                                                                      eStepScopeSource)),
+                    "step-over", interpreter);
+
+    LoadSubCommand (CommandObjectSP (new CommandObjectThreadStepWithTypeAndScope ("thread step-inst",
+                                                                                      "Single step one instruction in specified thread (current thread, if none specified).",
+                                                                                      "thread step-inst [<thread-id>]",
+                                                                                      eFlagProcessMustBeLaunched | eFlagProcessMustBePaused,
+                                                                                      eStepTypeTrace,
+                                                                                      eStepScopeInstruction)),
+                    "step-inst", interpreter);
+    LoadSubCommand (CommandObjectSP (new CommandObjectThreadStepWithTypeAndScope ("thread step-inst-over",
+                                                                                      "Single step one instruction in specified thread (current thread, if none specified), stepping over calls.",
+                                                                                      "thread step-inst-over [<thread-id>]",
+                                                                                      eFlagProcessMustBeLaunched | eFlagProcessMustBePaused,
+                                                                                      eStepTypeTraceOver,
+                                                                                      eStepScopeInstruction)),
+                    "step-inst-over", interpreter);
+}
+
+CommandObjectMultiwordThread::~CommandObjectMultiwordThread ()
+{
+}
+
+