From 1f1514ce3f4fe7a4c32418d17ebc7323dac027c4 Mon Sep 17 00:00:00 2001 From: Igor Kulaychuk Date: Thu, 11 Jan 2018 22:51:06 +0300 Subject: [PATCH] Refactor breakpoint printing --- src/debug/netcoredbg/breakpoints.cpp | 94 ++++++++++++++-------------- src/debug/netcoredbg/breakpoints.h | 8 +-- src/debug/netcoredbg/commands.cpp | 79 +++++++++++++++++++++-- src/debug/netcoredbg/debugger.h | 12 +++- src/debug/netcoredbg/main.cpp | 30 ++++----- src/debug/netcoredbg/protocol.h | 50 ++++++++++++++- 6 files changed, 198 insertions(+), 75 deletions(-) diff --git a/src/debug/netcoredbg/breakpoints.cpp b/src/debug/netcoredbg/breakpoints.cpp index 8865d29..e7d8eb5 100644 --- a/src/debug/netcoredbg/breakpoints.cpp +++ b/src/debug/netcoredbg/breakpoints.cpp @@ -46,6 +46,15 @@ struct ManagedBreakpoint { breakpoint->Activate(0); } + void ToBreakpoint(Breakpoint &breakpoint) + { + breakpoint.id = this->id; + breakpoint.verified = this->IsResolved(); + breakpoint.source = Source(this->fullname); + breakpoint.line = this->linenum; + breakpoint.hitCount = this->times; + } + ManagedBreakpoint(ManagedBreakpoint &&that) = default; ManagedBreakpoint(const ManagedBreakpoint &that) = delete; @@ -53,38 +62,40 @@ struct ManagedBreakpoint { static std::map g_breaks; -static HRESULT PrintBreakpoint(const ManagedBreakpoint &b, std::string &output) +HRESULT GetCurrentBreakpoint(ICorDebugThread *pThread, Breakpoint &breakpoint) { HRESULT Status; - std::stringstream ss; + ULONG32 ilOffset; + Modules::SequencePoint sp; + mdMethodDef methodToken; - if (b.IsResolved()) - { - ss << "bkpt={number=\"" << b.id << "\",type=\"breakpoint\",disp=\"keep\",enabled=\"y\"," - "func=\"\",fullname=\"" << Debugger::EscapeMIValue(b.fullname) << "\",line=\"" << b.linenum << "\"}"; - Status = S_OK; - } - else - { - ss << "bkpt={number=\"" << b.id << "\",type=\"breakpoint\",disp=\"keep\",enabled=\"y\"," - "warning=\"No executable code of the debugger's target code type is associated with this line.\"}"; - Status = S_FALSE; - } - output = ss.str(); - return Status; -} + ToRelease pFrame; + IfFailRet(pThread->GetActiveFrame(&pFrame)); + if (pFrame == nullptr) + return E_FAIL; + IfFailRet(pFrame->GetFunctionToken(&methodToken)); + + IfFailRet(Modules::GetFrameLocation(pFrame, ilOffset, sp)); -HRESULT PrintBreakpoint(ULONG32 id, std::string &output) -{ std::lock_guard lock(g_breakMutex); - auto it = g_breaks.find(id); + for (auto &it : g_breaks) + { + ManagedBreakpoint &b = it.second; - if (it == g_breaks.end()) - return E_FAIL; + if (b.fullname == sp.document && + b.ilOffset == ilOffset && + b.methodToken == methodToken && + b.linenum == sp.startLine && + b.enabled) + { + b.ToBreakpoint(breakpoint); + return S_OK; + } + } - return PrintBreakpoint(it->second, output); + return E_FAIL; } HRESULT HitBreakpoint(ICorDebugThread *pThread, ULONG32 &id, ULONG32 ×) @@ -124,19 +135,19 @@ HRESULT HitBreakpoint(ICorDebugThread *pThread, ULONG32 &id, ULONG32 ×) return E_FAIL; } -static ULONG32 InsertBreakpoint(ManagedBreakpoint &bp) +static void InsertBreakpoint(ManagedBreakpoint &bp, Breakpoint &breakpoint) { std::lock_guard lock(g_breakMutex); ULONG32 id = g_breakIndex++; bp.id = id; g_breaks.insert(std::make_pair(id, std::move(bp))); - return id; + bp.ToBreakpoint(breakpoint); } -ULONG32 InsertExceptionBreakpoint(const std::string &name) +void InsertExceptionBreakpoint(const std::string &name, Breakpoint &breakpoint) { ManagedBreakpoint bp; - return InsertBreakpoint(bp); + InsertBreakpoint(bp, breakpoint); } HRESULT DeleteBreakpoint(ULONG32 id) @@ -243,36 +254,23 @@ void TryResolveBreakpointsForModule(ICorDebugModule *pModule) if (SUCCEEDED(ResolveBreakpointInModule(pModule, b))) { - std::string output; - PrintBreakpoint(b, output); - Debugger::Printf("=breakpoint-modified,%s\n", output.c_str()); + Breakpoint breakpoint; + b.ToBreakpoint(breakpoint); + Debugger::EmitBreakpointEvent(BreakpointEvent(BreakpointChanged, breakpoint)); } } } -static HRESULT CreateBreakpointInProcess(ManagedBreakpoint &bp, ULONG32 &id) -{ - if (SUCCEEDED(ResolveBreakpoint(bp))) - { - id = InsertBreakpoint(bp); - return S_OK; - } - return S_FALSE; -} - -HRESULT InsertBreakpointInProcess(ICorDebugProcess *pProcess, std::string filename, int linenum, ULONG32 &id) +HRESULT InsertBreakpointInProcess(ICorDebugProcess *pProcess, std::string filename, int linenum, Breakpoint &breakpoint) { ManagedBreakpoint bp; bp.fullname = filename; bp.linenum = linenum; - HRESULT Status = pProcess ? CreateBreakpointInProcess(bp, id) : S_FALSE; + if (pProcess) + ResolveBreakpoint(bp); - if (Status == S_FALSE) - { - // Add pending breakpoint - id = InsertBreakpoint(bp); - } + InsertBreakpoint(bp, breakpoint); - return Status; + return S_OK; } diff --git a/src/debug/netcoredbg/breakpoints.h b/src/debug/netcoredbg/breakpoints.h index 2a891db..e3e09fb 100644 --- a/src/debug/netcoredbg/breakpoints.h +++ b/src/debug/netcoredbg/breakpoints.h @@ -3,11 +3,9 @@ // See the LICENSE file in the project root for more information. HRESULT DeleteBreakpoint(ULONG32 id); -HRESULT InsertBreakpointInProcess(ICorDebugProcess *pProcess, std::string filename, int linenum, ULONG32 &id); -HRESULT PrintBreakpoint(ULONG32 id, std::string &output); -ULONG32 InsertExceptionBreakpoint(const std::string &name); -HRESULT CreateBreakpointInProcess(ICorDebugProcess *pProcess, std::string filename, int linenum, ULONG32 &id); -HRESULT PrintBreakpoint(ULONG32 id, std::string &output); +HRESULT InsertBreakpointInProcess(ICorDebugProcess *pProcess, std::string filename, int linenum, Breakpoint &breakpoint); +void InsertExceptionBreakpoint(const std::string &name, Breakpoint &breakpoint); +HRESULT GetCurrentBreakpoint(ICorDebugThread *pThread, Breakpoint &breakpoint); void DeleteAllBreakpoints(); HRESULT HitBreakpoint(ICorDebugThread *pThread, ULONG32 &id, ULONG32 ×); diff --git a/src/debug/netcoredbg/commands.cpp b/src/debug/netcoredbg/commands.cpp index fdac9d6..61209f5 100644 --- a/src/debug/netcoredbg/commands.cpp +++ b/src/debug/netcoredbg/commands.cpp @@ -126,6 +126,45 @@ bool ParseBreakpoint(const std::vector &args_orig, std::string &fil return ok && linenum > 0; } + +static HRESULT PrintBreakpoint(const Breakpoint &b, std::string &output) +{ + HRESULT Status; + + std::stringstream ss; + + if (b.verified) + { + ss << "bkpt={number=\"" << b.id << "\",type=\"breakpoint\",disp=\"keep\",enabled=\"y\"," + "func=\"\",fullname=\"" << Debugger::EscapeMIValue(b.source.path) << "\",line=\"" << b.line << "\"}"; + Status = S_OK; + } + else + { + ss << "bkpt={number=\"" << b.id << "\",type=\"breakpoint\",disp=\"keep\",enabled=\"y\"," + "warning=\"No executable code of the debugger's target code type is associated with this line.\"}"; + Status = S_FALSE; + } + output = ss.str(); + return Status; +} + +HRESULT Debugger::EmitBreakpointEvent(BreakpointEvent event) +{ + switch(event.reason) + { + case StopBreakpoint: + { + std::string output; + PrintBreakpoint(event.breakpoint, output); + Debugger::Printf("=breakpoint-modified,%s\n", output.c_str()); + return S_OK; + } + default: + return S_OK; + } +} + static HRESULT BreakInsertCommand( ICorDebugProcess *pProcess, const std::vector &args, @@ -134,10 +173,11 @@ static HRESULT BreakInsertCommand( std::string filename; unsigned int linenum; ULONG32 id; + Breakpoint breakpoint; if (ParseBreakpoint(args, filename, linenum) - && SUCCEEDED(InsertBreakpointInProcess(pProcess, filename, linenum, id))) + && SUCCEEDED(InsertBreakpointInProcess(pProcess, filename, linenum, breakpoint))) { - PrintBreakpoint(id, output); + PrintBreakpoint(breakpoint, output); return S_OK; } @@ -306,6 +346,36 @@ static HRESULT ThreadInfoCommand(ICorDebugProcess *pProcess, const std::vector pThread; + + switch(event.reason) + { + case StopBreakpoint: + { + IfFailRet(m_pProcess->GetThread(event.threadId, &pThread)); + + StackFrame stackFrame; + ToRelease pFrame; + if (SUCCEEDED(pThread->GetActiveFrame(&pFrame)) && pFrame != nullptr) + GetFrameLocation(pFrame, stackFrame); + + Breakpoint b; + IfFailRet(GetCurrentBreakpoint(pThread, b)); + + std::string output; + PrintFrameLocation(stackFrame, output); + Debugger::Printf("*stopped,reason=\"breakpoint-hit\",thread-id=\"%i\",stopped-threads=\"all\",bkptno=\"%u\",times=\"%u\",frame={%s}\n", + event.threadId, (unsigned int)b.id, (unsigned int)b.hitCount, output.c_str()); + return S_OK; + } + default: + return S_OK; + } +} + HRESULT Debugger::HandleCommand(std::string command, const std::vector &args, std::string &output) @@ -518,10 +588,11 @@ HRESULT Debugger::HandleCommand(std::string command, ss << "bkpt=["; for (; i < args.size(); i++) { - ULONG32 id = InsertExceptionBreakpoint(args.at(i)); + Breakpoint b; + InsertExceptionBreakpoint(args.at(i), b); ss << sep; sep = ","; - ss << "{number=\"" << id << "\"}"; + ss << "{number=\"" << b.id << "\"}"; } ss << "]"; output = ss.str(); diff --git a/src/debug/netcoredbg/debugger.h b/src/debug/netcoredbg/debugger.h index e617667..1ba3250 100644 --- a/src/debug/netcoredbg/debugger.h +++ b/src/debug/netcoredbg/debugger.h @@ -53,12 +53,18 @@ class Debugger static HRESULT StepCommand(ICorDebugProcess *pProcess, const std::vector &args, std::string &output, StepType stepType); + + HRESULT EmitStoppedEvent(StoppedEvent event); + + public: + static HRESULT EmitBreakpointEvent(BreakpointEvent event); + static bool IsJustMyCode() { return m_justMyCode; } static void SetJustMyCode(bool enable) { m_justMyCode = enable; } - Debugger(ManagedCallback *cb) : - m_managedCallback(cb), + Debugger() : + m_managedCallback(nullptr), m_pDebug(nullptr), m_pProcess(nullptr), m_exit(false), @@ -69,6 +75,8 @@ public: ~Debugger(); + void SetManagedCallback(ManagedCallback *managedCallback); + static void Printf(const char *fmt, ...) __attribute__((format (printf, 1, 2))); static void Message(const char *fmt, ...) __attribute__((format (printf, 1, 2))); static std::string EscapeMIValue(const std::string &str); diff --git a/src/debug/netcoredbg/main.cpp b/src/debug/netcoredbg/main.cpp index b7a5d3e..f88ad29 100644 --- a/src/debug/netcoredbg/main.cpp +++ b/src/debug/netcoredbg/main.cpp @@ -300,7 +300,9 @@ static HRESULT GetExceptionInfo(ICorDebugThread *pThread, class ManagedCallback : public ICorDebugManagedCallback, ICorDebugManagedCallback2 { + friend class Debugger; ULONG m_refCount; + Debugger *m_debugger; public: void HandleEvent(ICorDebugController *controller, const char *eventName) @@ -309,7 +311,7 @@ public: controller->Continue(0); } - ManagedCallback() : m_refCount(1) {} + ManagedCallback() : m_refCount(1), m_debugger(nullptr) {} virtual ~ManagedCallback() {} // IUnknown @@ -368,24 +370,15 @@ public: return S_OK; } - ULONG32 id = 0; - ULONG32 times = 0; - HitBreakpoint(pThread, id, times); - - StackFrame stackFrame; - ToRelease pFrame; - if (SUCCEEDED(pThread->GetActiveFrame(&pFrame)) && pFrame != nullptr) - GetFrameLocation(pFrame, stackFrame); - DWORD threadId = 0; pThread->GetID(&threadId); - std::string output; - PrintFrameLocation(stackFrame, output); - Debugger::Printf("*stopped,reason=\"breakpoint-hit\",thread-id=\"%i\",stopped-threads=\"all\",bkptno=\"%u\",times=\"%u\",frame={%s}\n", - (int)threadId, (unsigned int)id, (unsigned int)times, output.c_str()); + ULONG32 id = 0; + ULONG32 times = 0; + HitBreakpoint(pThread, id, times); SetLastStoppedThread(pThread); + m_debugger->EmitStoppedEvent(StoppedEvent(StopBreakpoint, threadId)); return S_OK; } @@ -712,6 +705,12 @@ public: bool Debugger::m_justMyCode = true; +void Debugger::SetManagedCallback(ManagedCallback *managedCallback) +{ + m_managedCallback = managedCallback; + m_managedCallback->m_debugger = this; +} + Debugger::~Debugger() { m_managedCallback->Release(); @@ -1052,7 +1051,8 @@ int main(int argc, char *argv[]) } } - Debugger debugger(new ManagedCallback()); + Debugger debugger; + debugger.SetManagedCallback(new ManagedCallback()); if (pidDebuggee != 0) { diff --git a/src/debug/netcoredbg/protocol.h b/src/debug/netcoredbg/protocol.h index 90b76e6..e2339bc 100644 --- a/src/debug/netcoredbg/protocol.h +++ b/src/debug/netcoredbg/protocol.h @@ -42,10 +42,58 @@ struct StackFrame int endColumn; std::string moduleId; - ClrAddr clrAddr; + ClrAddr clrAddr; // exposed for MI protocol StackFrame() : id(0), line(0), column(0), endLine(0), endColumn(0) {} StackFrame(uint64_t id, std::string name) : id(id), name(name) {} }; + +enum StopReason +{ + StopStep, + StopBreakpoint, + StopException, + StopPause, + StopEntry +}; + +struct StoppedEvent +{ + StopReason reason; + std::string description; + int threadId; + std::string text; + bool allThreadsStopped; + + StoppedEvent(StopReason reason, int threadId = 0) : reason(reason), threadId(threadId), allThreadsStopped(true) {} +}; + +struct Breakpoint +{ + uint32_t id; + bool verified; + std::string message; + Source source; + int line; + + uint32_t hitCount; // exposed for MI protocol + + Breakpoint() : id(0), verified(false), line(0), hitCount(0) {} +}; + +enum BreakpointReason +{ + BreakpointChanged, + BreakpointNew, + BreakpointRemoved +}; + +struct BreakpointEvent +{ + BreakpointReason reason; + Breakpoint breakpoint; + + BreakpointEvent(BreakpointReason reason, Breakpoint breakpoint) : reason(reason), breakpoint(breakpoint) {} +}; -- 2.34.1