Extract class for handling GDB MI protocol
authorIgor Kulaychuk <i.kulaychuk@samsung.com>
Fri, 12 Jan 2018 16:23:00 +0000 (19:23 +0300)
committerIgor Kulaychuk <i.kulaychuk@samsung.com>
Fri, 12 Jan 2018 16:23:00 +0000 (19:23 +0300)
src/debug/netcoredbg/breakpoints.cpp
src/debug/netcoredbg/breakpoints.h
src/debug/netcoredbg/commands.cpp
src/debug/netcoredbg/debugger.h
src/debug/netcoredbg/main.cpp

index ff7f492..21f4c83 100644 (file)
@@ -241,7 +241,7 @@ static HRESULT ResolveBreakpoint(ManagedBreakpoint &bp)
     return S_OK;
 }
 
-void TryResolveBreakpointsForModule(ICorDebugModule *pModule)
+void Debugger::TryResolveBreakpointsForModule(ICorDebugModule *pModule)
 {
     std::lock_guard<std::mutex> lock(g_breakMutex);
 
@@ -256,7 +256,7 @@ void TryResolveBreakpointsForModule(ICorDebugModule *pModule)
         {
             Breakpoint breakpoint;
             b.ToBreakpoint(breakpoint);
-            Debugger::EmitBreakpointEvent(BreakpointEvent(BreakpointChanged, breakpoint));
+            m_protocol->EmitBreakpointEvent(BreakpointEvent(BreakpointChanged, breakpoint));
         }
     }
 }
index 226f54e..c2446ca 100644 (file)
@@ -9,4 +9,3 @@ HRESULT GetCurrentBreakpoint(ICorDebugThread *pThread, Breakpoint &breakpoint);
 
 void DeleteAllBreakpoints();
 HRESULT HitBreakpoint(ICorDebugThread *pThread, Breakpoint &breakpoint);
-void TryResolveBreakpointsForModule(ICorDebugModule *pModule);
index 258f8a9..785261e 100644 (file)
@@ -136,7 +136,7 @@ static HRESULT PrintBreakpoint(const Breakpoint &b, std::string &output)
     if (b.verified)
     {
         ss << "bkpt={number=\"" << b.id << "\",type=\"breakpoint\",disp=\"keep\",enabled=\"y\","
-            "func=\"\",fullname=\"" << Debugger::EscapeMIValue(b.source.path) << "\",line=\"" << b.line << "\"}";
+            "func=\"\",fullname=\"" << MIProtocol::EscapeMIValue(b.source.path) << "\",line=\"" << b.line << "\"}";
         Status = S_OK;
     }
     else
@@ -149,7 +149,7 @@ static HRESULT PrintBreakpoint(const Breakpoint &b, std::string &output)
     return Status;
 }
 
-void Debugger::EmitBreakpointEvent(BreakpointEvent event)
+void MIProtocol::EmitBreakpointEvent(BreakpointEvent event)
 {
     switch(event.reason)
     {
@@ -157,7 +157,7 @@ void Debugger::EmitBreakpointEvent(BreakpointEvent event)
         {
             std::string output;
             PrintBreakpoint(event.breakpoint, output);
-            Debugger::Printf("=breakpoint-modified,%s\n", output.c_str());
+            MIProtocol::Printf("=breakpoint-modified,%s\n", output.c_str());
             return;
         }
         default:
@@ -228,17 +228,25 @@ HRESULT Debugger::SetupStep(ICorDebugThread *pThread, Debugger::StepType stepTyp
     return S_OK;
 }
 
-HRESULT Debugger::StepCommand(ICorDebugProcess *pProcess,
-                              const std::vector<std::string> &args,
-                              std::string &output, StepType stepType)
+HRESULT Debugger::StepCommand(int threadId,
+                              StepType stepType)
 {
     HRESULT Status;
     ToRelease<ICorDebugThread> pThread;
-    DWORD threadId = GetIntArg(args, "--thread", GetLastStoppedThreadId());
-    IfFailRet(pProcess->GetThread(threadId, &pThread));
-    DisableAllSteppers(pProcess);
+    IfFailRet(m_pProcess->GetThread(threadId, &pThread));
+    DisableAllSteppers(m_pProcess);
     IfFailRet(SetupStep(pThread, stepType));
-    IfFailRet(pProcess->Continue(0));
+    IfFailRet(m_pProcess->Continue(0));
+    return S_OK;
+}
+
+HRESULT MIProtocol::StepCommand(const std::vector<std::string> &args,
+                                std::string &output,
+                                Debugger::StepType stepType)
+{
+    HRESULT Status;
+    DWORD threadId = GetIntArg(args, "--thread", GetLastStoppedThreadId());
+    m_debugger->StepCommand(threadId, stepType);
     output = "^running";
     return S_OK;
 }
@@ -258,8 +266,8 @@ HRESULT PrintFrameLocation(const StackFrame &stackFrame, std::string &output)
 
     if (!stackFrame.source.IsNull())
     {
-        ss << "file=\"" << Debugger::EscapeMIValue(stackFrame.source.name) << "\","
-           << "fullname=\"" << Debugger::EscapeMIValue(stackFrame.source.path) << "\","
+        ss << "file=\"" << MIProtocol::EscapeMIValue(stackFrame.source.name) << "\","
+           << "fullname=\"" << MIProtocol::EscapeMIValue(stackFrame.source.path) << "\","
            << "line=\"" << stackFrame.line << "\","
            << "col=\"" << stackFrame.column << "\","
            << "end-line=\"" << stackFrame.endLine << "\","
@@ -336,7 +344,7 @@ static HRESULT ThreadInfoCommand(ICorDebugProcess *pProcess, const std::vector<s
     for (const Thread& thread : threads)
     {
         ss << "{id=\"" << thread.id
-           << "\",name=\"" << Debugger::EscapeMIValue(thread.name) << "\",state=\""
+           << "\",name=\"" << MIProtocol::EscapeMIValue(thread.name) << "\",state=\""
            << (thread.running ? "running" : "stopped") << "\"}" << sep;
         sep = ",";
     }
@@ -346,7 +354,7 @@ static HRESULT ThreadInfoCommand(ICorDebugProcess *pProcess, const std::vector<s
     return S_OK;
 }
 
-void Debugger::EmitStoppedEvent(StoppedEvent event)
+void MIProtocol::EmitStoppedEvent(StoppedEvent event)
 {
     HRESULT Status;
 
@@ -357,13 +365,13 @@ void Debugger::EmitStoppedEvent(StoppedEvent event)
     {
         case StopBreakpoint:
         {
-            Debugger::Printf("*stopped,reason=\"breakpoint-hit\",thread-id=\"%i\",stopped-threads=\"all\",bkptno=\"%u\",times=\"%u\",frame={%s}\n",
+            MIProtocol::Printf("*stopped,reason=\"breakpoint-hit\",thread-id=\"%i\",stopped-threads=\"all\",bkptno=\"%u\",times=\"%u\",frame={%s}\n",
                 event.threadId, (unsigned int)event.breakpoint.id, (unsigned int)event.breakpoint.hitCount, frameLocation.c_str());
             return;
         }
         case StopStep:
         {
-            Debugger::Printf("*stopped,reason=\"end-stepping-range\",thread-id=\"%i\",stopped-threads=\"all\",frame={%s}\n",
+            MIProtocol::Printf("*stopped,reason=\"end-stepping-range\",thread-id=\"%i\",stopped-threads=\"all\",frame={%s}\n",
                 event.threadId, frameLocation.c_str());
             return;
         }
@@ -371,9 +379,9 @@ void Debugger::EmitStoppedEvent(StoppedEvent event)
         {
             std::string category = "clr";
             std::string stage = "unhandled";
-            Debugger::Printf("*stopped,reason=\"exception-received\",exception-name=\"%s\",exception=\"%s\",exception-stage=\"%s\",exception-category=\"%s\",thread-id=\"%i\",stopped-threads=\"all\",frame={%s}\n",
+            MIProtocol::Printf("*stopped,reason=\"exception-received\",exception-name=\"%s\",exception=\"%s\",exception-stage=\"%s\",exception-category=\"%s\",thread-id=\"%i\",stopped-threads=\"all\",frame={%s}\n",
                 event.text.c_str(),
-                Debugger::EscapeMIValue(event.description).c_str(),
+                MIProtocol::EscapeMIValue(event.description).c_str(),
                 stage.c_str(),
                 category.c_str(),
                 event.threadId,
@@ -384,12 +392,12 @@ void Debugger::EmitStoppedEvent(StoppedEvent event)
     }
 }
 
-void Debugger::EmitExitedEvent(ExitedEvent event)
+void MIProtocol::EmitExitedEvent(ExitedEvent event)
 {
-    Debugger::Printf("*stopped,reason=\"exited\",exit-code=\"%i\"\n", event.exitCode);
+    MIProtocol::Printf("*stopped,reason=\"exited\",exit-code=\"%i\"\n", event.exitCode);
 }
 
-void Debugger::EmitThreadEvent(ThreadEvent event)
+void MIProtocol::EmitThreadEvent(ThreadEvent event)
 {
     const char *reasonText = "";
     switch(event.reason)
@@ -401,23 +409,23 @@ void Debugger::EmitThreadEvent(ThreadEvent event)
             reasonText = "thread-exited";
             break;
     }
-    Debugger::Printf("=%s,id=\"%i\"\n", reasonText, event.threadId);
+    MIProtocol::Printf("=%s,id=\"%i\"\n", reasonText, event.threadId);
 }
 
-void Debugger::EmitOutputEvent(OutputEvent event)
+void MIProtocol::EmitOutputEvent(OutputEvent event)
 {
     if (event.source.empty())
-        Debugger::Printf("=message,text=\"%s\",send-to=\"output-window\"\"\n",
-            Debugger::EscapeMIValue(event.output).c_str());
+        MIProtocol::Printf("=message,text=\"%s\",send-to=\"output-window\"\"\n",
+            MIProtocol::EscapeMIValue(event.output).c_str());
     else
-        Debugger::Printf("=message,text=\"%s\",send-to=\"output-window\",source=\"%s\"\n",
-            Debugger::EscapeMIValue(event.output).c_str(),
-            Debugger::EscapeMIValue(event.source).c_str());
+        MIProtocol::Printf("=message,text=\"%s\",send-to=\"output-window\",source=\"%s\"\n",
+            MIProtocol::EscapeMIValue(event.output).c_str(),
+            MIProtocol::EscapeMIValue(event.source).c_str());
 }
 
-HRESULT Debugger::HandleCommand(std::string command,
-                                const std::vector<std::string> &args,
-                                std::string &output)
+HRESULT MIProtocol::HandleCommand(std::string command,
+                                  const std::vector<std::string> &args,
+                                  std::string &output)
 {
     static std::unordered_map<std::string, CommandCallback> commands {
     { "thread-info", ThreadInfoCommand },
@@ -442,11 +450,17 @@ HRESULT Debugger::HandleCommand(std::string command,
         }
         return S_OK;
     } },
-    { "exec-step", std::bind(StepCommand, _1, _2, _3, STEP_IN) },
-    { "exec-next", std::bind(StepCommand, _1, _2, _3, STEP_OVER) },
-    { "exec-finish", std::bind(StepCommand, _1, _2, _3, STEP_OUT) },
+    { "exec-step", [this](ICorDebugProcess *, const std::vector<std::string> &args, std::string &output) -> HRESULT {
+        return StepCommand(args, output, Debugger::STEP_IN);
+    }},
+    { "exec-next", [this](ICorDebugProcess *, const std::vector<std::string> &args, std::string &output) -> HRESULT {
+        return StepCommand(args, output, Debugger::STEP_OVER);
+    }},
+    { "exec-finish", [this](ICorDebugProcess *, const std::vector<std::string> &args, std::string &output) -> HRESULT {
+        return StepCommand(args, output, Debugger::STEP_OUT);
+    }},
     { "exec-abort", [this](ICorDebugProcess *, const std::vector<std::string> &, std::string &output) -> HRESULT {
-        this->TerminateProcess();
+        m_debugger->TerminateProcess();
         return S_OK;
     }},
     { "target-attach", [this](ICorDebugProcess *, const std::vector<std::string> &args, std::string &output) -> HRESULT {
@@ -459,12 +473,12 @@ HRESULT Debugger::HandleCommand(std::string command,
         bool ok;
         int pid = ParseInt(args.at(0), ok);
         if (!ok) return E_INVALIDARG;
-        IfFailRet(this->AttachToProcess(pid));
+        IfFailRet(m_debugger->AttachToProcess(pid));
         // TODO: print succeessful result
         return S_OK;
     }},
     { "target-detach", [this](ICorDebugProcess *, const std::vector<std::string> &, std::string &output) -> HRESULT {
-        this->DetachFromProcess();
+        m_debugger->DetachFromProcess();
         return S_OK;
     }},
     { "stack-list-frames", [](ICorDebugProcess *pProcess, const std::vector<std::string> &args_orig, std::string &output) -> HRESULT {
@@ -571,7 +585,7 @@ HRESULT Debugger::HandleCommand(std::string command,
     { "gdb-exit", [this](ICorDebugProcess *, const std::vector<std::string> &args, std::string &output) -> HRESULT {
         this->m_exit = true;
 
-        this->TerminateProcess();
+        m_debugger->TerminateProcess();
 
         return S_OK;
     }},
@@ -586,7 +600,7 @@ HRESULT Debugger::HandleCommand(std::string command,
         return S_OK;
     }},
     { "exec-run", [this](ICorDebugProcess *, const std::vector<std::string> &args, std::string &output) -> HRESULT {
-        HRESULT Status = RunProcess();
+        HRESULT Status = m_debugger->RunProcess(m_fileExec, m_execArgs);
         if (SUCCEEDED(Status))
             output = "^running";
         return Status;
@@ -652,7 +666,7 @@ HRESULT Debugger::HandleCommand(std::string command,
         return E_FAIL;
     }
 
-    return command_it->second(m_pProcess, args, output);
+    return command_it->second(m_debugger->GetProcess(), args, output);
 }
 
 static std::vector<std::string> TokenizeString(const std::string &str, const char *delimiters = " \t\n\r")
@@ -732,7 +746,7 @@ static bool ParseLine(const std::string &str,
     return true;
 }
 
-void Debugger::CommandLoop()
+void MIProtocol::CommandLoop()
 {
     static char inputBuffer[1024];
     std::string token;
@@ -779,7 +793,7 @@ void Debugger::CommandLoop()
     }
 
     if (!m_exit)
-        TerminateProcess();
+        m_debugger->TerminateProcess();
 
     Printf("%s^exit\n", token.c_str());
 }
index 766b09c..2759a8f 100644 (file)
@@ -6,20 +6,25 @@
 
 
 class ManagedCallback;
+class Protocol;
 
 class Debugger
 {
+public:
+    enum StepType {
+        STEP_IN = 0,
+        STEP_OVER,
+        STEP_OUT
+    };
+
+private:
     friend class ManagedCallback;
+    Protocol *m_protocol;
     ManagedCallback *m_managedCallback;
     ICorDebug *m_pDebug;
     ICorDebugProcess *m_pProcess;
-    bool m_exit;
 
     static bool m_justMyCode;
-    static std::mutex m_outMutex;
-
-    std::string m_fileExec;
-    std::vector<std::string> m_execArgs;
 
     std::mutex m_startupMutex;
     std::condition_variable m_startupCV;
@@ -32,36 +37,14 @@ class Debugger
 
     HRESULT CheckNoProcess();
 
-    HRESULT HandleCommand(std::string command,
-                          const std::vector<std::string> &args,
-                          std::string &output);
-
     static VOID StartupCallback(IUnknown *pCordb, PVOID parameter, HRESULT hr);
     HRESULT Startup(IUnknown *punk, int pid);
 
-    HRESULT RunProcess();
-
     void Cleanup();
 
-    enum StepType {
-        STEP_IN = 0,
-        STEP_OVER,
-        STEP_OUT
-    };
-
     static HRESULT SetupStep(ICorDebugThread *pThread, StepType stepType);
-    static HRESULT StepCommand(ICorDebugProcess *pProcess,
-                               const std::vector<std::string> &args,
-                               std::string &output, StepType stepType);
-
-    static void EmitStoppedEvent(StoppedEvent event);
-    static void EmitExitedEvent(ExitedEvent event);
-    static void EmitThreadEvent(ThreadEvent event);
-    static void EmitOutputEvent(OutputEvent event);
 
 public:
-    static void EmitBreakpointEvent(BreakpointEvent event);
-
     static bool IsJustMyCode() { return m_justMyCode; }
     static void SetJustMyCode(bool enable) { m_justMyCode = enable; }
 
@@ -69,7 +52,6 @@ public:
         m_managedCallback(nullptr),
         m_pDebug(nullptr),
         m_pProcess(nullptr),
-        m_exit(false),
         m_startupReady(false),
         m_startupResult(S_OK),
         m_unregisterToken(nullptr),
@@ -77,17 +59,63 @@ public:
 
     ~Debugger();
 
-    void SetManagedCallback(ManagedCallback *managedCallback);
+    void TryResolveBreakpointsForModule(ICorDebugModule *pModule);
 
-    static void Printf(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
+    void SetProtocol(Protocol *protocol) { m_protocol = protocol; }
+    void SetManagedCallback(ManagedCallback *managedCallback);
 
-    static std::string EscapeMIValue(const std::string &str);
+    HRESULT RunProcess(std::string fileExec, std::vector<std::string> execArgs);
 
     HRESULT AttachToProcess(int pid);
     HRESULT DetachFromProcess();
     HRESULT TerminateProcess();
 
-    void CommandLoop();
+    ICorDebugProcess *GetProcess() { return m_pProcess; }
+
+    HRESULT StepCommand(int threadId, StepType stepType);
+};
+
+class Protocol
+{
+public:
+    virtual void EmitStoppedEvent(StoppedEvent event) = 0;
+    virtual void EmitExitedEvent(ExitedEvent event) = 0;
+    virtual void EmitThreadEvent(ThreadEvent event) = 0;
+    virtual void EmitOutputEvent(OutputEvent event) = 0;
+    virtual void EmitBreakpointEvent(BreakpointEvent event) = 0;
+    virtual void CommandLoop() = 0;
+};
+
+class MIProtocol : public Protocol
+{
+    static std::mutex m_outMutex;
+    bool m_exit;
+    Debugger *m_debugger;
+
+    std::string m_fileExec;
+    std::vector<std::string> m_execArgs;
+public:
+    void SetDebugger(Debugger *debugger) { m_debugger = debugger; m_debugger->SetProtocol(this); }
+    static std::string EscapeMIValue(const std::string &str);
+
+    MIProtocol() : m_exit(false) {}
+    void EmitStoppedEvent(StoppedEvent event) override;
+    void EmitExitedEvent(ExitedEvent event) override;
+    void EmitThreadEvent(ThreadEvent event) override;
+    void EmitOutputEvent(OutputEvent event) override;
+    void EmitBreakpointEvent(BreakpointEvent event) override;
+    void CommandLoop() override;
+
+    static void Printf(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
+
+private:
+    HRESULT HandleCommand(std::string command,
+                          const std::vector<std::string> &args,
+                          std::string &output);
+
+    HRESULT StepCommand(const std::vector<std::string> &args,
+                        std::string &output,
+                        Debugger::StepType stepType);
 };
 
 HRESULT DisableAllSteppers(ICorDebugProcess *pProcess);
index 28a3491..5bdecac 100644 (file)
@@ -98,9 +98,9 @@ BOOL SafeReadMemory (TADDR offset, PVOID lpBuffer, ULONG cb,
     return bRet;
 }
 
-std::mutex Debugger::m_outMutex;
+std::mutex MIProtocol::m_outMutex;
 
-void Debugger::Printf(const char *fmt, ...)
+void MIProtocol::Printf(const char *fmt, ...)
 {
     std::lock_guard<std::mutex> lock(m_outMutex);
     va_list arg;
@@ -113,7 +113,7 @@ void Debugger::Printf(const char *fmt, ...)
 }
 
 // TODO: Merge with EscapeString
-std::string Debugger::EscapeMIValue(const std::string &str)
+std::string MIProtocol::EscapeMIValue(const std::string &str)
 {
     std::string s(str);
 
@@ -276,7 +276,7 @@ public:
         void HandleEvent(ICorDebugController *controller, const std::string &eventName)
         {
             std::string text = "Event received: '" + eventName + "'\n";
-            m_debugger->EmitOutputEvent(OutputEvent(OutputConsole, text));
+            m_debugger->m_protocol->EmitOutputEvent(OutputEvent(OutputConsole, text));
             controller->Continue(0);
         }
 
@@ -350,7 +350,7 @@ public:
                 GetFrameLocation(pFrame, threadId, 0, event.frame);
 
             SetLastStoppedThread(pThread);
-            m_debugger->EmitStoppedEvent(event);
+            m_debugger->m_protocol->EmitStoppedEvent(event);
 
             return S_OK;
         }
@@ -383,7 +383,7 @@ public:
                 event.frame = stackFrame;
 
                 SetLastStoppedThread(pThread);
-                m_debugger->EmitStoppedEvent(event);
+                m_debugger->m_protocol->EmitStoppedEvent(event);
             }
             return S_OK;
         }
@@ -422,7 +422,7 @@ public:
                     event.text = excType;
                     event.description = message.empty() ? details : message;
                     event.frame = stackFrame;
-                    m_debugger->EmitStoppedEvent(event);
+                    m_debugger->m_protocol->EmitStoppedEvent(event);
                 };
 
                 if (FAILED(pThread->GetCurrentException(&pExceptionValue)) || FAILED(ObjectToString(pThread, pExceptionValue, emitFunc)))
@@ -435,7 +435,7 @@ public:
                 std::string text = "Exception thrown: '" + excType + "' in " + excModule + "\n";
                 OutputEvent event(OutputConsole, text);
                 event.source = "target-exception";
-                m_debugger->EmitOutputEvent(event);
+                m_debugger->m_protocol->EmitOutputEvent(event);
                 pAppDomain->Continue(0);
             }
 
@@ -473,7 +473,7 @@ public:
             /* [in] */ ICorDebugProcess *pProcess)
         {
             NotifyEvalComplete(nullptr, nullptr);
-            m_debugger->EmitExitedEvent(ExitedEvent(0));
+            m_debugger->m_protocol->EmitExitedEvent(ExitedEvent(0));
             NotifyProcessExited();
             return S_OK;
         }
@@ -484,7 +484,7 @@ public:
         {
             DWORD threadId = 0;
             thread->GetID(&threadId);
-            m_debugger->EmitThreadEvent(ThreadEvent(ThreadStarted, threadId));
+            m_debugger->m_protocol->EmitThreadEvent(ThreadEvent(ThreadStarted, threadId));
             pAppDomain->Continue(0);
             return S_OK;
         }
@@ -496,7 +496,7 @@ public:
             NotifyEvalComplete(thread, nullptr);
             DWORD threadId = 0;
             thread->GetID(&threadId);
-            m_debugger->EmitThreadEvent(ThreadEvent(ThreadExited, threadId));
+            m_debugger->m_protocol->EmitThreadEvent(ThreadEvent(ThreadExited, threadId));
             pAppDomain->Continue(0);
             return S_OK;
         }
@@ -515,15 +515,15 @@ public:
 
             std::stringstream ss;
             ss << "id=\"{" << id << "}\","
-                << "target-name=\"" << Debugger::EscapeMIValue(name) << "\","
-                << "host-name=\"" << Debugger::EscapeMIValue(name) << "\","
+                << "target-name=\"" << MIProtocol::EscapeMIValue(name) << "\","
+                << "host-name=\"" << MIProtocol::EscapeMIValue(name) << "\","
                 << "symbols-loaded=\"" << symbolsLoaded << "\","
                 << "base-address=\"0x" << std::hex << baseAddress << "\","
                 << "size=\"" << std::dec << size << "\"";
-            Debugger::Printf("=library-loaded,%s\n", ss.str().c_str());
+            MIProtocol::Printf("=library-loaded,%s\n", ss.str().c_str());
 
             if (symbolsLoaded)
-                TryResolveBreakpointsForModule(pModule);
+                m_debugger->TryResolveBreakpointsForModule(pModule);
 
             pAppDomain->Continue(0);
             return S_OK;
@@ -828,7 +828,7 @@ HRESULT Debugger::Startup(IUnknown *punk, int pid)
     return S_OK;
 }
 
-HRESULT Debugger::RunProcess()
+HRESULT Debugger::RunProcess(std::string fileExec, std::vector<std::string> execArgs)
 {
     static const auto startupCallbackWaitTimeout = std::chrono::milliseconds(5000);
     HRESULT Status;
@@ -836,10 +836,10 @@ HRESULT Debugger::RunProcess()
     IfFailRet(CheckNoProcess());
 
     std::stringstream ss;
-    ss << "\"" << m_fileExec << "\"";
-    for (std::string &arg : m_execArgs)
+    ss << "\"" << fileExec << "\"";
+    for (std::string &arg : execArgs)
     {
-        ss << " \"" << EscapeMIValue(arg) << "\"";
+        ss << " \"" << MIProtocol::EscapeMIValue(arg) << "\"";
     }
     std::string cmdString = ss.str();
     std::unique_ptr<WCHAR[]> cmd(new WCHAR[cmdString.size() + 1]);
@@ -1029,6 +1029,9 @@ int main(int argc, char *argv[])
     Debugger debugger;
     debugger.SetManagedCallback(new ManagedCallback());
 
+    MIProtocol protocol;
+    protocol.SetDebugger(&debugger);
+
     if (pidDebuggee != 0)
     {
         HRESULT Status = debugger.AttachToProcess(pidDebuggee);
@@ -1039,7 +1042,7 @@ int main(int argc, char *argv[])
         }
     }
 
-    debugger.CommandLoop();
+    protocol.CommandLoop();
 
     return EXIT_SUCCESS;
 }