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);
}
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;
// 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();
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;
}
}
-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();
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;
// 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 << "}}";
};
}
-void VSCodeProtocol::EmitOutputEvent(OutputCategory category, string_view output, string_view source)
+void VSCodeProtocol::EmitOutputEvent(OutputCategory category, string_view output, string_view, DWORD threadId)
{
LogFuncEntry();
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;
}
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;