Fix VSCode protocol output event.
authorMikhail Kurinnoi <m.kurinnoi@samsung.com>
Tue, 9 Jan 2024 12:02:15 +0000 (15:02 +0300)
committerGleb Balykov/Advanced System SW Lab /SRR/Staff Engineer/Samsung Electronics <g.balykov@samsung.com>
Tue, 23 Jan 2024 19:15:38 +0000 (22:15 +0300)
Related to https://github.com/Samsung/netcoredbg/issues/157

src/debugger/managedcallback.cpp
src/interfaces/iprotocol.h
src/protocols/cliprotocol.cpp
src/protocols/cliprotocol.h
src/protocols/miprotocol.cpp
src/protocols/miprotocol.h
src/protocols/vscodeprotocol.cpp
src/protocols/vscodeprotocol.h

index c48d3dc6009ae0e203de3b1ab094c355afeba255..e957bfe73efac1e41d45766c32851028c3348da6 100644 (file)
@@ -363,7 +363,9 @@ HRESULT STDMETHODCALLTYPE ManagedCallback::LogMessage(ICorDebugAppDomain *pAppDo
         src = "Debugger.Log";
     }
 
-    m_debugger.pProtocol->EmitOutputEvent(OutputConsole, to_utf8(pMessage), src);
+    DWORD threadId = 0;
+    pThread->GetID(&threadId);
+    m_debugger.pProtocol->EmitOutputEvent(OutputStdOut, to_utf8(pMessage), src, threadId);
     return m_sharedCallbacksQueue->ContinueAppDomain(pAppDomain);
 }
 
index 112c5b011b4b125b0e620823d257fbdbb8e30c4b..4c92705ea99f1bcba8f2b154eb896212267d74e4 100644 (file)
@@ -40,7 +40,7 @@ public:
     virtual void EmitInteropDebuggingErrorEvent(const int error_n) {}
     virtual void EmitThreadEvent(const ThreadEvent &event) = 0;
     virtual void EmitModuleEvent(const ModuleEvent &event) = 0;
-    virtual void EmitOutputEvent(OutputCategory category, string_view output, string_view source = "") = 0;
+    virtual void EmitOutputEvent(OutputCategory category, string_view output, string_view source = "", DWORD threadId = 0) = 0;
     virtual void EmitBreakpointEvent(const BreakpointEvent &event) = 0;
     virtual void Cleanup() = 0;
     virtual void SetLaunchCommand(const std::string &fileExec, const std::vector<std::string> &args) = 0;
index b6e4aa0abfce624217534ce5cb1e17d2b3e80b33..5ca0a8ec36b4b412310c4c0471381f53929c93a4 100644 (file)
@@ -968,7 +968,7 @@ void CLIProtocol::EmitModuleEvent(const ModuleEvent &event)
 
 // This function implements Debugger interface and called from ManagedDebugger, 
 // (from IORedirect class) as callback function, in separate thread.
-void CLIProtocol::EmitOutputEvent(OutputCategory category, string_view output, string_view source)
+void CLIProtocol::EmitOutputEvent(OutputCategory category, string_view output, string_view source, DWORD threadId)
 {
     LogFuncEntry();
 
index 0434d7a8401d2dbb863b5423a3ce3bfb9042c8e5..77f812ce6e9d6dd21e6dc8b560ce3cea0cac0041 100644 (file)
@@ -94,7 +94,7 @@ public:
     void EmitInteropDebuggingErrorEvent(const int error_n) override;
     void EmitThreadEvent(const ThreadEvent &event) override;
     void EmitModuleEvent(const ModuleEvent &event) override;
-    void EmitOutputEvent(OutputCategory category, string_view output, string_view source = "") override;
+    void EmitOutputEvent(OutputCategory category, string_view output, string_view source = "", DWORD threadId = 0) override;
     void EmitBreakpointEvent(const BreakpointEvent &event) override;
     void Cleanup() override;
     void CommandLoop() override;
index 8a2ac2084c5d29563f2deb8036c1f170c480ba02..2c689c08205cd4eea234058dd665ae7d828d9c72 100644 (file)
@@ -509,7 +509,7 @@ void MIProtocol::EmitModuleEvent(const ModuleEvent &event)
     }
 }
 
-void MIProtocol::EmitOutputEvent(OutputCategory category, string_view output, string_view source)
+void MIProtocol::EmitOutputEvent(OutputCategory category, string_view output, string_view source, DWORD threadId)
 {
     LogFuncEntry();
 
index f168872a08f90a06752eb6d148bf02474a2718f5..7621bbb1b74b60dc4f2db6567e80026fb99725b3 100644 (file)
@@ -38,7 +38,7 @@ public:
     void EmitContinuedEvent(ThreadId threadId) override;
     void EmitThreadEvent(const ThreadEvent &event) override;
     void EmitModuleEvent(const ModuleEvent &event) override;
-    void EmitOutputEvent(OutputCategory category, string_view output, string_view source = "") override;
+    void EmitOutputEvent(OutputCategory category, string_view output, string_view source = "", DWORD threadId = 0) override;
     void EmitBreakpointEvent(const BreakpointEvent &event) override;
     void Cleanup() override;
     void CommandLoop() override;
index 5e6d6d9abae067bf395237ce947389ccb5631893..3e136852a0ca15dd6195b919ef07ca78207af51c 100644 (file)
@@ -305,15 +305,18 @@ namespace
 
     // This function serializes "OutputEvent" to specified output stream and used for two
     // purposes: to compute output size, and to perform the output directly.
-    template <typename T1, typename T2>
-    void serialize_output(std::ostream& stream, uint64_t counter, string_view name, T1& text, T2& source)
+    template <typename T1>
+    void serialize_output(std::ostream& stream, uint64_t counter, string_view name, T1& text, Source& source)
     {
         stream << "{\"seq\":" << counter 
             << ", \"event\":\"output\",\"type\":\"event\",\"body\":{\"category\":\"" << name
             << "\",\"output\":\"" << text << "\"";
 
-        if (source.size() > 0)
-            stream << ",\"source\":\"" << source << "\"";
+        if (!source.IsNull())
+        {
+            // "source":{"name":"Program.cs","path":"/path/Program.cs"}
+            stream << ",\"source\":{\"name\":\"" << source.name << "\",\"path\":\"" << source.path << "\"}";
+        }
 
         stream <<  "}}";
 
@@ -321,7 +324,7 @@ namespace
     };
 }
 
-void VSCodeProtocol::EmitOutputEvent(OutputCategory category, string_view output, string_view source)
+void VSCodeProtocol::EmitOutputEvent(OutputCategory category, string_view output, string_view, DWORD threadId)
 {
     LogFuncEntry();
 
@@ -332,20 +335,35 @@ void VSCodeProtocol::EmitOutputEvent(OutputCategory category, string_view output
     const string_view& name = categories[category];
 
     EscapedString<JSON_escape_rules> escaped_text(output);
-    EscapedString<JSON_escape_rules> escaped_source(source);
 
     std::lock_guard<std::mutex> lock(m_outMutex);
 
+    Source source;
+    int totalFrames = 0;
+    std::vector<StackFrame> stackFrames;
+    if (threadId && SUCCEEDED(m_sharedDebugger->GetStackTrace(ThreadId(threadId), FrameLevel(0), 0, stackFrames, totalFrames)))
+    {
+        // Find first frame with source file data (code with PDB/user code).
+        for (const StackFrame& stackFrame : stackFrames)
+        {
+            if (!stackFrame.source.IsNull())
+            {
+                source = stackFrame.source;
+                break;
+            }
+        }
+    }
+
     // compute size of headers without text (text could be huge, no reason parse it for size, that we already know)
     CountingStream count;
-    serialize_output(count, m_seqCounter, name, "", escaped_source);
+    serialize_output(count, m_seqCounter, name, "", source);
 
     // compute total size of headers + text
     auto const total_size = count.size() + escaped_text.size();
 
     // perform output
     cout << CONTENT_LENGTH << total_size << TWO_CRLF;
-    serialize_output(cout, m_seqCounter, name, escaped_text, escaped_source);
+    serialize_output(cout, m_seqCounter, name, escaped_text, source);
 
     ++m_seqCounter;
 }
index f710151c3532fb2350b053a4e78b9814b305fae9..8fa95661a74bbf0e8c892b22eb37298953d9a80b 100644 (file)
@@ -74,7 +74,7 @@ public:
     void EmitContinuedEvent(ThreadId threadId) override;
     void EmitThreadEvent(const ThreadEvent &event) override;
     void EmitModuleEvent(const ModuleEvent &event) override;
-    void EmitOutputEvent(OutputCategory category, string_view output, string_view source = "") override;
+    void EmitOutputEvent(OutputCategory category, string_view output, string_view source = "", DWORD threadId = 0) override;
     void EmitBreakpointEvent(const BreakpointEvent &event) override;
     void Cleanup() override;
     void CommandLoop() override;