Refactor breakpoint printing
authorIgor Kulaychuk <i.kulaychuk@samsung.com>
Thu, 11 Jan 2018 19:51:06 +0000 (22:51 +0300)
committerIgor Kulaychuk <i.kulaychuk@samsung.com>
Thu, 11 Jan 2018 19:51:06 +0000 (22:51 +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
src/debug/netcoredbg/protocol.h

index 8865d295d2eafc9f364d16885db005d6db42de06..e7d8eb551ba86b21b7401efeb31132817b093ee7 100644 (file)
@@ -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<ULONG32, ManagedBreakpoint> 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<ICorDebugFrame> 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<std::mutex> 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 &times)
@@ -124,19 +135,19 @@ HRESULT HitBreakpoint(ICorDebugThread *pThread, ULONG32 &id, ULONG32 &times)
     return E_FAIL;
 }
 
-static ULONG32 InsertBreakpoint(ManagedBreakpoint &bp)
+static void InsertBreakpoint(ManagedBreakpoint &bp, Breakpoint &breakpoint)
 {
     std::lock_guard<std::mutex> 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;
 }
index 2a891dbf2c3cd86b5436f4e33bac7f9a9ce4bb4e..e3e09fbdb6b0c89be6fc8a07511b224b42031959 100644 (file)
@@ -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 &times);
index fdac9d6730aa95c026b6dc2a582b0519a54ffcb8..61209f59eab3ca0469c58822af07050711a14cd3 100644 (file)
@@ -126,6 +126,45 @@ bool ParseBreakpoint(const std::vector<std::string> &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<std::string> &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<s
     return S_OK;
 }
 
+HRESULT Debugger::EmitStoppedEvent(StoppedEvent event)
+{
+    HRESULT Status;
+    ToRelease<ICorDebugThread> pThread;
+
+    switch(event.reason)
+    {
+        case StopBreakpoint:
+        {
+            IfFailRet(m_pProcess->GetThread(event.threadId, &pThread));
+
+            StackFrame stackFrame;
+            ToRelease<ICorDebugFrame> 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<std::string> &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();
index e617667648182e78db7e0903677cad322d95a4a7..1ba3250345337352055c1101873a01f93fbab1d8 100644 (file)
@@ -53,12 +53,18 @@ class Debugger
     static HRESULT StepCommand(ICorDebugProcess *pProcess,
                                const std::vector<std::string> &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);
index b7a5d3ed4f79da50e089383b8618553edff0df5e..f88ad29ad83112a36742401fbdf16b3d33c6a2e5 100644 (file)
@@ -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<ICorDebugFrame> 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)
     {
index 90b76e62c9c4e516937c571e30ff88ff2d893741..e2339bc932e18c4ae08aff9030cf2d15bfdaa283 100644 (file)
@@ -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) {}
+};