From: Igor Kulaychuk Date: Fri, 12 Jan 2018 16:23:00 +0000 (+0300) Subject: Extract class for handling GDB MI protocol X-Git-Tag: submit/tizen/20180620.071641~63 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=f0443ef1f60cfb3fddb6af1696292569fefe790f;p=sdk%2Ftools%2Fnetcoredbg.git Extract class for handling GDB MI protocol --- diff --git a/src/debug/netcoredbg/breakpoints.cpp b/src/debug/netcoredbg/breakpoints.cpp index ff7f492..21f4c83 100644 --- a/src/debug/netcoredbg/breakpoints.cpp +++ b/src/debug/netcoredbg/breakpoints.cpp @@ -241,7 +241,7 @@ static HRESULT ResolveBreakpoint(ManagedBreakpoint &bp) return S_OK; } -void TryResolveBreakpointsForModule(ICorDebugModule *pModule) +void Debugger::TryResolveBreakpointsForModule(ICorDebugModule *pModule) { std::lock_guard 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)); } } } diff --git a/src/debug/netcoredbg/breakpoints.h b/src/debug/netcoredbg/breakpoints.h index 226f54e..c2446ca 100644 --- a/src/debug/netcoredbg/breakpoints.h +++ b/src/debug/netcoredbg/breakpoints.h @@ -9,4 +9,3 @@ HRESULT GetCurrentBreakpoint(ICorDebugThread *pThread, Breakpoint &breakpoint); void DeleteAllBreakpoints(); HRESULT HitBreakpoint(ICorDebugThread *pThread, Breakpoint &breakpoint); -void TryResolveBreakpointsForModule(ICorDebugModule *pModule); diff --git a/src/debug/netcoredbg/commands.cpp b/src/debug/netcoredbg/commands.cpp index 258f8a9..785261e 100644 --- a/src/debug/netcoredbg/commands.cpp +++ b/src/debug/netcoredbg/commands.cpp @@ -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 &args, - std::string &output, StepType stepType) +HRESULT Debugger::StepCommand(int threadId, + StepType stepType) { HRESULT Status; ToRelease 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 &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 &args, - std::string &output) +HRESULT MIProtocol::HandleCommand(std::string command, + const std::vector &args, + std::string &output) { static std::unordered_map 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 &args, std::string &output) -> HRESULT { + return StepCommand(args, output, Debugger::STEP_IN); + }}, + { "exec-next", [this](ICorDebugProcess *, const std::vector &args, std::string &output) -> HRESULT { + return StepCommand(args, output, Debugger::STEP_OVER); + }}, + { "exec-finish", [this](ICorDebugProcess *, const std::vector &args, std::string &output) -> HRESULT { + return StepCommand(args, output, Debugger::STEP_OUT); + }}, { "exec-abort", [this](ICorDebugProcess *, const std::vector &, std::string &output) -> HRESULT { - this->TerminateProcess(); + m_debugger->TerminateProcess(); return S_OK; }}, { "target-attach", [this](ICorDebugProcess *, const std::vector &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 &output) -> HRESULT { - this->DetachFromProcess(); + m_debugger->DetachFromProcess(); return S_OK; }}, { "stack-list-frames", [](ICorDebugProcess *pProcess, const std::vector &args_orig, std::string &output) -> HRESULT { @@ -571,7 +585,7 @@ HRESULT Debugger::HandleCommand(std::string command, { "gdb-exit", [this](ICorDebugProcess *, const std::vector &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 &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 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()); } diff --git a/src/debug/netcoredbg/debugger.h b/src/debug/netcoredbg/debugger.h index 766b09c..2759a8f 100644 --- a/src/debug/netcoredbg/debugger.h +++ b/src/debug/netcoredbg/debugger.h @@ -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 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 &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 &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 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 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 &args, + std::string &output); + + HRESULT StepCommand(const std::vector &args, + std::string &output, + Debugger::StepType stepType); }; HRESULT DisableAllSteppers(ICorDebugProcess *pProcess); diff --git a/src/debug/netcoredbg/main.cpp b/src/debug/netcoredbg/main.cpp index 28a3491..5bdecac 100644 --- a/src/debug/netcoredbg/main.cpp +++ b/src/debug/netcoredbg/main.cpp @@ -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 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 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 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; }