Refactor commands
authorIgor Kulaychuk <i.kulaychuk@samsung.com>
Thu, 13 Jul 2017 02:04:33 +0000 (05:04 +0300)
committerIgor Kulaychuk <i.kulaychuk@samsung.com>
Mon, 13 Nov 2017 19:22:40 +0000 (22:22 +0300)
src/debug/debugger/CMakeLists.txt
src/debug/debugger/commands.cpp [new file with mode: 0644]
src/debug/debugger/main.cpp

index 33808f0..8c4d641 100644 (file)
@@ -9,7 +9,8 @@ set(coreclrdbg_SRC
     varobj.cpp
     typeprinter.cpp
     valuewalk.cpp
-    valueprint.cpp)
+    valueprint.cpp
+    commands.cpp)
 
 if(CLR_CMAKE_PLATFORM_ARCH_AMD64)
     add_definitions(-D_TARGET_AMD64_=1)
diff --git a/src/debug/debugger/commands.cpp b/src/debug/debugger/commands.cpp
new file mode 100644 (file)
index 0000000..5b2d64e
--- /dev/null
@@ -0,0 +1,350 @@
+#include "common.h"
+
+#include <string>
+#include <vector>
+#include <sstream>
+#include <unordered_map>
+#include <functional>
+
+// Varobj
+HRESULT ListVariables(ICorDebugFrame *pFrame, std::string &output);
+HRESULT CreateVar(ICorDebugThread *pThread, ICorDebugFrame *pFrame, const std::string &varobjName, const std::string &expression, std::string &output);
+HRESULT ListChildren(const std::string &name, int print_values, ICorDebugThread *pThread, ICorDebugFrame *pFrame, std::string &output);
+HRESULT DeleteVar(const std::string &varobjName);
+
+// Modules
+HRESULT GetStepRangeFromCurrentIP(ICorDebugThread *pThread, COR_DEBUG_STEP_RANGE *range);
+
+// Breakpoints
+HRESULT DeleteBreakpoint(ULONG32 id);
+HRESULT CreateBreakpointInProcess(ICorDebugProcess *pProcess, std::string filename, int linenum, ULONG32 &id);
+HRESULT PrintBreakpoint(ULONG32 id, std::string &output);
+
+void _out_printf(const char *fmt, ...)
+    __attribute__((format (printf, 1, 2)));
+
+#define out_printf(fmt, ...) _out_printf(fmt, ##__VA_ARGS__)
+
+typedef std::function<HRESULT(
+    ICorDebugProcess *pProcess,
+    const std::vector<std::string> &args,
+    std::string &output)> CommandCallback;
+
+HRESULT PrintThreadsState(ICorDebugController *controller, std::string &output);
+HRESULT PrintFrames(ICorDebugThread *pThread, std::string &output, int lowFrame = 0, int highFrame = INT_MAX);
+
+// Breakpoints
+HRESULT CreateBreakpointInProcess(ICorDebugProcess *pProcess, std::string filename, int linenum, ULONG32 &id);
+HRESULT PrintBreakpoint(ULONG32 id, std::string &output);
+
+// Debug events
+int GetLastStoppedThreadId();
+void WaitProcessExited();
+HRESULT DisableAllBreakpointsAndSteppers(ICorDebugProcess *pProcess);
+
+bool ParseBreakpoint(const std::vector<std::string> &args, std::string &filename, unsigned int &linenum)
+{
+    if (args.empty())
+        return false;
+
+    std::size_t i = args.at(0).rfind(':');
+
+    if (i == std::string::npos)
+        return false;
+
+    filename = args.at(0).substr(0, i);
+    std::string slinenum = args.at(0).substr(i + 1);
+
+    try
+    {
+        linenum = std::stoul(slinenum);
+        return true;
+    }
+    catch(std::invalid_argument e)
+    {
+        return false;
+    }
+    catch (std::out_of_range  e)
+    {
+        return false;
+    }
+}
+
+HRESULT BreakInsertCommand(
+    ICorDebugProcess *pProcess,
+    const std::vector<std::string> &args,
+    std::string &output)
+{
+    std::string filename;
+    unsigned int linenum;
+    ULONG32 id;
+    if (ParseBreakpoint(args, filename, linenum)
+        && SUCCEEDED(CreateBreakpointInProcess(pProcess, filename, linenum, id)))
+    {
+        PrintBreakpoint(id, output);
+        return S_OK;
+    }
+
+    output = "Unknown breakpoint location format";
+    return E_FAIL;
+}
+
+enum StepType {
+    STEP_IN = 0,
+    STEP_OVER,
+    STEP_OUT
+};
+
+HRESULT RunStep(ICorDebugThread *pThread, StepType stepType)
+{
+    HRESULT Status;
+
+    ToRelease<ICorDebugStepper> pStepper;
+    IfFailRet(pThread->CreateStepper(&pStepper));
+
+    CorDebugIntercept mask = (CorDebugIntercept)(INTERCEPT_ALL & ~(INTERCEPT_SECURITY | INTERCEPT_CLASS_INIT));
+    IfFailRet(pStepper->SetInterceptMask(mask));
+
+    if (stepType == STEP_OUT)
+    {
+        IfFailRet(pStepper->StepOut());
+        return S_OK;
+    }
+
+    BOOL bStepIn = stepType == STEP_IN;
+
+    COR_DEBUG_STEP_RANGE range;
+    if (SUCCEEDED(GetStepRangeFromCurrentIP(pThread, &range)))
+    {
+        IfFailRet(pStepper->StepRange(bStepIn, &range, 1));
+    } else {
+        IfFailRet(pStepper->Step(bStepIn));
+    }
+
+    return S_OK;
+}
+
+static CommandCallback StepCommand(StepType stepType)
+{
+    return [&](ICorDebugProcess *pProcess,
+               const std::vector<std::string> &,
+               std::string &)->HRESULT
+        {
+            HRESULT Status;
+            ToRelease<ICorDebugThread> pThread;
+            DWORD threadId = GetLastStoppedThreadId();
+            IfFailRet(pProcess->GetThread(threadId, &pThread));
+            IfFailRet(RunStep(pThread, stepType));
+            IfFailRet(pProcess->Continue(0));
+            return S_OK;
+        };
+}
+
+static HRESULT ThreadInfoCommand(ICorDebugProcess *pProcess, const std::vector<std::string> &, std::string &output)
+{
+    return PrintThreadsState(pProcess, output);
+}
+
+static bool g_exit = false;
+
+static std::unordered_map<std::string, CommandCallback> commands {
+    { "thread-info", ThreadInfoCommand },
+    { "exec-continue", [](ICorDebugProcess *pProcess, const std::vector<std::string> &, std::string &){ return pProcess->Continue(0); } },
+    { "exec-interrupt", [](ICorDebugProcess *pProcess, const std::vector<std::string> &, std::string &){ return pProcess->Stop(0); } },
+    { "break-insert", BreakInsertCommand },
+    { "break-delete", [](ICorDebugProcess *, const std::vector<std::string> &args, std::string &) -> HRESULT {
+        for (const std::string &idStr : args)
+        {
+            ULONG32 id = std::stoul(idStr);
+            DeleteBreakpoint(id);
+        }
+        return S_OK;
+    } },
+    { "exec-step", StepCommand(STEP_IN) },
+    { "exec-next", StepCommand(STEP_OVER) },
+    { "exec-finish", StepCommand(STEP_OUT) },
+    { "stack-list-frames", [](ICorDebugProcess *pProcess, const std::vector<std::string> &args, std::string &output) -> HRESULT {
+        // TODO: Add parsing frame lowFrame, highFrame and --thread
+        HRESULT Status;
+        ToRelease<ICorDebugThread> pThread;
+        DWORD threadId = GetLastStoppedThreadId();
+        IfFailRet(pProcess->GetThread(threadId, &pThread));
+        int lowFrame = 0;
+        int highFrame = INT_MAX;
+        IfFailRet(PrintFrames(pThread, output, lowFrame, highFrame));
+        return S_OK;
+    }},
+    { "stack-list-variables", [](ICorDebugProcess *pProcess, const std::vector<std::string> &args, std::string &output) -> HRESULT {
+        // TODO: Add parsing arguments --thread, --frame
+        HRESULT Status;
+        ToRelease<ICorDebugThread> pThread;
+        DWORD threadId = GetLastStoppedThreadId();
+        IfFailRet(pProcess->GetThread(threadId, &pThread));
+
+        ToRelease<ICorDebugFrame> pFrame;
+        IfFailRet(pThread->GetActiveFrame(&pFrame));
+
+        IfFailRet(ListVariables(pFrame, output));
+
+        return S_OK;
+    }},
+    { "var-create", [](ICorDebugProcess *pProcess, const std::vector<std::string> &args, std::string &output) -> HRESULT {
+        HRESULT Status;
+
+        if (args.size() < 2)
+        {
+            output = "Command requires at least 2 arguments";
+            return E_FAIL;
+        }
+
+        // TODO: Add parsing arguments --thread, --frame
+        ToRelease<ICorDebugThread> pThread;
+        DWORD threadId = GetLastStoppedThreadId();
+        IfFailRet(pProcess->GetThread(threadId, &pThread));
+
+        ToRelease<ICorDebugFrame> pFrame;
+        IfFailRet(pThread->GetActiveFrame(&pFrame));
+
+        return CreateVar(pThread, pFrame, args.at(0), args.at(1), output);
+    }},
+    { "var-list-children", [](ICorDebugProcess *pProcess, const std::vector<std::string> &args, std::string &output) -> HRESULT {
+        HRESULT Status;
+
+        int print_values = 0;
+        int var_index = 0;
+        if (!args.empty())
+        {
+            if (args.at(0) == "1" || args.at(0) == "--all-values")
+            {
+                print_values = 1;
+                var_index++;
+            }
+            else if (args.at(0) == "2" || args.at(0) == "--simple-values")
+            {
+                print_values = 2;
+                var_index++;
+            }
+        }
+
+        if (args.size() < (var_index + 1))
+        {
+            output = "Command requires an argument";
+            return E_FAIL;
+        }
+
+        // TODO: Add parsing arguments --thread, --frame
+        ToRelease<ICorDebugThread> pThread;
+        DWORD threadId = GetLastStoppedThreadId();
+        IfFailRet(pProcess->GetThread(threadId, &pThread));
+
+        ToRelease<ICorDebugFrame> pFrame;
+        IfFailRet(pThread->GetActiveFrame(&pFrame));
+        return ListChildren(args.at(var_index), print_values, pThread, pFrame, output);
+    }},
+    { "var-delete", [](ICorDebugProcess *, const std::vector<std::string> &args, std::string &output) -> HRESULT {
+        if (args.size() < 1)
+        {
+            output = "Command requires at least 1 argument";
+            return E_FAIL;
+        }
+        return DeleteVar(args.at(0));
+    }},
+    { "gdb-exit", [](ICorDebugProcess *pProcess, const std::vector<std::string> &args, std::string &output) -> HRESULT {
+        HRESULT Status;
+        g_exit = true;
+        IfFailRet(pProcess->Stop(0));
+
+        DisableAllBreakpointsAndSteppers(pProcess);
+
+        Status = pProcess->Terminate(0);
+
+        WaitProcessExited();
+        //pProcess.Release();
+        return Status;
+    }}
+};
+
+static bool ParseLine(const std::string &str,
+                      std::string &token,
+                      std::string &cmd,
+                      std::vector<std::string> &args)
+{
+    token.clear();
+    cmd.clear();
+    args.clear();
+
+    std::stringstream ss(str);
+
+    std::vector<std::string> result;
+    std::string buf;
+
+    if (!(ss >> cmd))
+        return false;
+
+    std::size_t i = cmd.find_first_not_of("0123456789");
+    if (i == std::string::npos)
+        return false;
+
+    if (cmd.at(i) != '-')
+        return false;
+
+    token = cmd.substr(0, i);
+    cmd = cmd.substr(i + 1);
+
+    while (ss >> buf)
+        args.push_back(buf);
+
+    return true;
+}
+
+void CommandLoop(ICorDebugProcess *pProcess)
+{
+    static char inputBuffer[1024];
+    std::string token;
+
+    while (!g_exit)
+    {
+        token.clear();
+
+        out_printf("(gdb)\n");
+        if (!fgets(inputBuffer, _countof(inputBuffer), stdin))
+            break;
+
+        std::vector<std::string> args;
+        std::string command;
+        if (!ParseLine(inputBuffer, token, command, args))
+        {
+            out_printf("%s^error,msg=\"Failed to parse input\"\n", token.c_str());
+            continue;
+        }
+
+        auto command_it = commands.find(command);
+
+        if (command_it == commands.end())
+        {
+            out_printf("%s^error,msg=\"Unknown command: %s\"\n", token.c_str(), command.c_str());
+            continue;
+        }
+
+        std::string output;
+        HRESULT hr = command_it->second(pProcess, args, output);
+        if (g_exit)
+            break;
+        if (SUCCEEDED(hr))
+        {
+            const char *sep = output.empty() ? "" : ",";
+            out_printf("%s^done%s%s\n", token.c_str(), sep, output.c_str());
+        }
+        else
+        {
+            const char *sep = output.empty() ? "" : " ";
+            out_printf("%s^error,msg=\"Error: 0x%08x%s%s\"\n", token.c_str(), hr, sep, output.c_str());
+        }
+    }
+    if (SUCCEEDED(pProcess->Stop(0)))
+    {
+        DisableAllBreakpointsAndSteppers(pProcess);
+        pProcess->Detach();
+    }
+    out_printf("%s^exit\n", token.c_str());
+}
index 153a1a5..dc36258 100644 (file)
@@ -37,7 +37,7 @@ static void NotifyProcessExited()
     g_processCV.notify_one();
 }
 
-static void WaitProcessExited()
+void WaitProcessExited()
 {
     std::unique_lock<std::mutex> lock(g_processMutex);
     if (g_process)
@@ -106,10 +106,7 @@ void _out_printf(const char *fmt, ...)
 // Breakpoints
 void DeleteAllBreakpoints();
 HRESULT FindCurrentBreakpointId(ICorDebugThread *pThread, ULONG32 &id);
-HRESULT DeleteBreakpoint(ULONG32 id);
-HRESULT CreateBreakpointInProcess(ICorDebugProcess *pProcess, std::string filename, int linenum, ULONG32 &id);
 HRESULT TryResolveBreakpointsForModule(ICorDebugModule *pModule);
-HRESULT PrintBreakpoint(ULONG32 id, std::string &output);
 
 // Modules
 void SetCoreCLRPath(const std::string &coreclrPath);
@@ -130,12 +127,6 @@ HRESULT GetFrameLocation(ICorDebugFrame *pFrame,
 // Valuewalk
 void NotifyEvalComplete();
 
-// Varobj
-HRESULT ListVariables(ICorDebugFrame *pFrame, std::string &output);
-HRESULT CreateVar(ICorDebugThread *pThread, ICorDebugFrame *pFrame, const std::string &varobjName, const std::string &expression, std::string &output);
-HRESULT ListChildren(const std::string &name, int print_values, ICorDebugThread *pThread, ICorDebugFrame *pFrame, std::string &output);
-HRESULT DeleteVar(const std::string &varobjName);
-
 
 HRESULT PrintThread(ICorDebugThread *pThread, std::string &output)
 {
@@ -257,41 +248,6 @@ HRESULT DisableAllBreakpointsAndSteppers(ICorDebugProcess *pProcess)
     return S_OK;
 }
 
-enum StepType {
-    STEP_IN = 0,
-    STEP_OVER,
-    STEP_OUT
-};
-
-HRESULT RunStep(ICorDebugThread *pThread, StepType stepType)
-{
-    HRESULT Status;
-
-    ToRelease<ICorDebugStepper> pStepper;
-    IfFailRet(pThread->CreateStepper(&pStepper));
-
-    CorDebugIntercept mask = (CorDebugIntercept)(INTERCEPT_ALL & ~(INTERCEPT_SECURITY | INTERCEPT_CLASS_INIT));
-    IfFailRet(pStepper->SetInterceptMask(mask));
-
-    if (stepType == STEP_OUT)
-    {
-        IfFailRet(pStepper->StepOut());
-        return S_OK;
-    }
-
-    BOOL bStepIn = stepType == STEP_IN;
-
-    COR_DEBUG_STEP_RANGE range;
-    if (SUCCEEDED(GetStepRangeFromCurrentIP(pThread, &range)))
-    {
-        IfFailRet(pStepper->StepRange(bStepIn, &range, 1));
-    } else {
-        IfFailRet(pStepper->Step(bStepIn));
-    }
-
-    return S_OK;
-}
-
 enum FrameType
 {
     FrameNative,
@@ -840,63 +796,7 @@ public:
             /* [in] */ ICorDebugMDA *pMDA) {return S_OK; }
 };
 
-bool ParseBreakpoint(const std::vector<std::string> &args, std::string &filename, unsigned int &linenum)
-{
-    if (args.empty())
-        return false;
-
-    std::size_t i = args.at(0).rfind(':');
-
-    if (i == std::string::npos)
-        return false;
-
-    filename = args.at(0).substr(0, i);
-    std::string slinenum = args.at(0).substr(i + 1);
-
-    try
-    {
-        linenum = std::stoul(slinenum);
-        return true;
-    }
-    catch(std::invalid_argument e)
-    {
-        return false;
-    }
-    catch (std::out_of_range  e)
-    {
-        return false;
-    }
-}
-
-bool ParseLine(const std::string &str, std::string &token, std::string &cmd, std::vector<std::string> &args)
-{
-    token.clear();
-    cmd.clear();
-    args.clear();
-
-    std::stringstream ss(str);
-
-    std::vector<std::string> result;
-    std::string buf;
-
-    if (!(ss >> cmd))
-        return false;
-
-    std::size_t i = cmd.find_first_not_of("0123456789");
-    if (i == std::string::npos)
-        return false;
-
-    if (cmd.at(i) != '-')
-        return false;
-
-    token = cmd.substr(0, i);
-    cmd = cmd.substr(i + 1);
-
-    while (ss >> buf)
-        args.push_back(buf);
-
-    return true;
-}
+void CommandLoop(ICorDebugProcess *pProcess);
 
 void print_help()
 {
@@ -1037,300 +937,10 @@ int main(int argc, char *argv[])
         g_process = pProcess;
     }
 
-    static char inputBuffer[1024];
-    std::string token;
-
-    for (;;) {
-        token.clear();
-
-        out_printf("(gdb)\n");
-        if (!fgets(inputBuffer, _countof(inputBuffer), stdin))
-            break;
-
-        std::vector<std::string> args;
-        std::string command;
-        if (!ParseLine(inputBuffer, token, command, args))
-        {
-            out_printf("%s^error,msg=\"Failed to parse input line\"\n", token.c_str());
-            continue;
-        }
-
-        if (command == "thread-info")
-        {
-            std::string output;
-            HRESULT hr = PrintThreadsState(pProcess, output);
-            if (SUCCEEDED(hr))
-            {
-                out_printf("%s^done,%s\n", token.c_str(), output.c_str());
-            }
-            else
-            {
-                out_printf("%s^error,msg=\"HRESULT=%x\"\n", token.c_str(), hr);
-            }
-        }
-        else if (command == "exec-continue")
-        {
-            HRESULT hr = pProcess->Continue(0);
-            if (SUCCEEDED(hr))
-            {
-                out_printf("%s^done\n", token.c_str());
-            }
-            else
-            {
-                out_printf("%s^error,msg=\"HRESULT=%x\"\n", token.c_str(), hr);
-            }
-        }
-        else if (command == "exec-interrupt")
-        {
-            HRESULT hr = pProcess->Stop(0);
-            if (SUCCEEDED(hr))
-            {
-                out_printf("%s^done\n", token.c_str());
-            }
-            else
-            {
-                out_printf("%s^error,msg=\"HRESULT=%x\"\n", token.c_str(), hr);
-            }
-        }
-        else if (command == "break-insert")
-        {
-            std::string filename;
-            unsigned int linenum;
-            ULONG32 id;
-            if (ParseBreakpoint(args, filename, linenum)
-                && SUCCEEDED(CreateBreakpointInProcess(pProcess, filename, linenum, id)))
-            {
-                std::string output;
-                PrintBreakpoint(id, output);
-                out_printf("%s^done,%s\n", token.c_str(), output.c_str());
-            }
-            else
-            {
-                out_printf("%s^error,msg=\"Unknown breakpoint location format\"\n", token.c_str());
-            }
-        }
-        else if (command == "break-delete")
-        {
-            try
-            {
-                for (std::string &idStr : args)
-                {
-                    ULONG32 id = std::stoul(idStr);
-                    DeleteBreakpoint(id);
-                }
-                out_printf("%s^done\n", token.c_str());
-            }
-            catch(std::invalid_argument e)
-            {
-                out_printf("%s^error,msg=\"Invalid argument\"\n", token.c_str());
-            }
-            catch (std::out_of_range  e)
-            {
-                out_printf("%s^error,msg=\"Out of range\"\n", token.c_str());
-            }
-        }
-        else if (command == "exec-next" || command == "exec-step" || command == "exec-finish")
-        {
-            StepType stepType;
-            if (command == "exec-next")
-                stepType = STEP_OVER;
-            else if (command == "exec-step")
-                stepType = STEP_IN;
-            else if (command == "exec-finish")
-                stepType = STEP_OUT;
-
-            ToRelease<ICorDebugThread> pThread;
-            DWORD threadId = GetLastStoppedThreadId();
-            HRESULT hr = pProcess->GetThread(threadId, &pThread);
-            if (SUCCEEDED(hr))
-            {
-                hr = RunStep(pThread, stepType);
-            }
-
-            if (FAILED(hr))
-            {
-                out_printf("%s^error,msg=\"Cannot create stepper: %x\"\n", token.c_str(), hr);
-            }
-            else
-            {
-                hr = pProcess->Continue(0);
-                if (SUCCEEDED(hr))
-                {
-                    out_printf("%s^done\n", token.c_str());
-                }
-                else
-                {
-                    out_printf("%s^error,msg=\"HRESULT=%x\"\n", token.c_str(), hr);
-                }
-            }
-        }
-        else if (command == "stack-list-frames")
-        {
-            // TODO: Add parsing frame lowFrame, highFrame and --thread
-            std::string output;
-            ToRelease<ICorDebugThread> pThread;
-            DWORD threadId = GetLastStoppedThreadId();
-            HRESULT hr = pProcess->GetThread(threadId, &pThread);
-            int lowFrame = 0;
-            int highFrame = INT_MAX;
-            if (SUCCEEDED(hr))
-            {
-                hr = PrintFrames(pThread, output, lowFrame, highFrame);
-            }
-            if (SUCCEEDED(hr))
-            {
-                out_printf("%s^done,%s\n", token.c_str(), output.c_str());
-            }
-            else
-            {
-                out_printf("%s^error,msg=\"HRESULT=%x\"\n", token.c_str(), hr);
-            }
-        }
-        else if (command == "stack-list-variables")
-        {
-            // TODO: Add parsing arguments --thread, --frame
-            std::string output;
-            ToRelease<ICorDebugThread> pThread;
-            DWORD threadId = GetLastStoppedThreadId();
-            HRESULT hr = pProcess->GetThread(threadId, &pThread);
-            if (SUCCEEDED(hr))
-            {
-                ToRelease<ICorDebugFrame> pFrame;
-                hr = pThread->GetActiveFrame(&pFrame);
-                if (SUCCEEDED(hr))
-                    hr = ListVariables(pFrame, output);
-            }
-            if (SUCCEEDED(hr))
-            {
-                out_printf("%s^done,%s\n", token.c_str(), output.c_str());
-            }
-            else
-            {
-                out_printf("%s^error,msg=\"HRESULT=%x\"\n", token.c_str(), hr);
-            }
-        }
-        else if (command == "var-create")
-        {
-            if (args.size() < 2)
-            {
-                out_printf("%s^error,msg=\"%s requires at least 2 arguments\"\n", token.c_str(), command.c_str());
-            } else {
-                // TODO: Add parsing arguments --thread, --frame
-                std::string output;
-                ToRelease<ICorDebugThread> pThread;
-                DWORD threadId = GetLastStoppedThreadId();
-                HRESULT hr = pProcess->GetThread(threadId, &pThread);
-                if (SUCCEEDED(hr))
-                {
-                    ToRelease<ICorDebugFrame> pFrame;
-                    hr = pThread->GetActiveFrame(&pFrame);
-                    if (SUCCEEDED(hr))
-                        hr = CreateVar(pThread, pFrame, args.at(0), args.at(1), output);
-                }
-                if (SUCCEEDED(hr))
-                {
-                    out_printf("%s^done,%s\n", token.c_str(), output.c_str());
-                }
-                else
-                {
-                    out_printf("%s^error,msg=\"HRESULT=%x\"\n", token.c_str(), hr);
-                }
-            }
-        }
-        else if (command == "var-list-children")
-        {
-            int print_values = 0;
-            int var_index = 0;
-            if (!args.empty())
-            {
-                if (args.at(0) == "1" || args.at(0) == "--all-values")
-                {
-                    print_values = 1;
-                    var_index++;
-                }
-                else if (args.at(0) == "2" || args.at(0) == "--simple-values")
-                {
-                    print_values = 2;
-                    var_index++;
-                }
-            }
-
-            if (args.size() < (var_index + 1))
-            {
-                out_printf("%s^error,msg=\"%s requires an argument\"\n", token.c_str(), command.c_str());
-            } else {
-                // TODO: Add parsing arguments --thread, --frame
-                std::string output;
-                ToRelease<ICorDebugThread> pThread;
-                DWORD threadId = GetLastStoppedThreadId();
-                HRESULT hr = pProcess->GetThread(threadId, &pThread);
-                if (SUCCEEDED(hr))
-                {
-                    ToRelease<ICorDebugFrame> pFrame;
-                    hr = pThread->GetActiveFrame(&pFrame);
-                    if (SUCCEEDED(hr))
-                        hr = ListChildren(args.at(var_index), print_values, pThread, pFrame, output);
-                }
-                if (SUCCEEDED(hr))
-                {
-                    out_printf("%s^done,%s\n", token.c_str(), output.c_str());
-                }
-                else
-                {
-                    out_printf("%s^error,msg=\"HRESULT=%x\"\n", token.c_str(), hr);
-                }
-            }
-        }
-        else if (command == "var-delete")
-        {
-            if (args.size() < 1)
-            {
-                out_printf("%s^error,msg=\"%s requires at least 1 argument\"\n", token.c_str(), command.c_str());
-            } else {
-                if (SUCCEEDED(DeleteVar(args.at(0))))
-                {
-                    out_printf("%s^done\n", token.c_str());
-                }
-                else
-                {
-                    out_printf("%s^error,msg=\"Varible %s does not exits\"\n", token.c_str(), args.at(0).c_str());
-                }
-            }
-        }
-        else if (command == "gdb-exit")
-        {
-            hr = pProcess->Stop(0);
-            if (SUCCEEDED(hr))
-            {
-                DisableAllBreakpointsAndSteppers(pProcess);
-
-                hr = pProcess->Terminate(0);
-
-                WaitProcessExited();
-
-                pProcess.Release();
-            }
-            break;
-        }
-        else
-        {
-            out_printf("%s^error,msg=\"Unknown command: %s\"\n", token.c_str(), command.c_str());
-        }
-    }
-
-    if (pProcess)
-    {
-        if (SUCCEEDED(pProcess->Stop(0)))
-        {
-            DisableAllBreakpointsAndSteppers(pProcess);
-            hr = pProcess->Detach();
-        }
-    }
+    CommandLoop(pProcess);
 
     pCorDebug->Terminate();
 
-    out_printf("%s^exit\n", token.c_str());
-
     // TODO: Cleanup libcoreclr.so instance
 
     return EXIT_SUCCESS;