// Get the debugger arguments and commands to run initially
List<string> initialCommands = new List<string>();
- string arguments = null;
+ var arguments = new StringBuilder();
switch (debugger)
{
case NativeDebugger.Cdb:
- initialCommands.Add(".sympath %DEBUG_ROOT%");
- initialCommands.Add(".extpath " + Path.GetDirectoryName(config.SOSPath()));
+ string helperExtension = config.CDBHelperExtension();
+ if (string.IsNullOrWhiteSpace(helperExtension) || !File.Exists(helperExtension))
+ {
+ throw new Exception($"CDB helper script path not set or does not exist: {helperExtension}");
+ }
+ arguments.AppendFormat(@"-c "".load {0}""", helperExtension);
+
if (loadDump)
{
- arguments = "-z %DUMP_NAME%";
+ arguments.Append(" -z %DUMP_NAME%");
}
else
{
- arguments = "-Gsins " + debuggeeCommandLine;
+ arguments.AppendFormat(" -Gsins {0}", debuggeeCommandLine);
// disable stopping on integer divide-by-zero and integer overflow exceptions
initialCommands.Add("sxd dz");
initialCommands.Add("sxd iov");
}
+ initialCommands.Add(".sympath %DEBUG_ROOT%");
+ initialCommands.Add(".extpath " + Path.GetDirectoryName(config.SOSPath()));
+
// Add the path to runtime so cdb/sos can find mscordbi.
string runtimeSymbolsPath = config.RuntimeSymbolsPath;
if (runtimeSymbolsPath != null)
{
throw new Exception("LLDB helper script path not set or does not exist: " + lldbHelperScript);
}
- arguments = string.Format(@"--no-lldbinit -o ""settings set interpreter.prompt-on-quit false"" -o ""command script import {0}"" -o ""version""", lldbHelperScript);
+ arguments.AppendFormat(@"--no-lldbinit -o ""settings set interpreter.prompt-on-quit false"" -o ""command script import {0}"" -o ""version""", lldbHelperScript);
// Load the dump or launch the debuggee process
if (loadDump)
{
throw new Exception("GDB not meant for loading core dumps");
}
- arguments = "--args " + debuggeeCommandLine;
+ arguments.AppendFormat("--args {0}", debuggeeCommandLine);
// .NET Core 1.1 or less don't catch stack overflow and abort so need to catch SIGSEGV
if (config.StackOverflowSIGSEGV)
}
// Create the native debugger process running
- ProcessRunner processRunner = new ProcessRunner(debuggerPath, ReplaceVariables(variables, arguments)).
+ ProcessRunner processRunner = new ProcessRunner(debuggerPath, ReplaceVariables(variables, arguments.ToString())).
WithLog(scriptLogger).
WithTimeout(TimeSpan.FromMinutes(10));
{
case NativeDebugger.Cdb:
commands.Add($".load {sosPath}");
- commands.Add(".lines; .reload");
+ commands.Add(".lines");
+ commands.Add(".reload");
if (sosHostRuntime != null)
{
commands.Add($"!SetHostRuntime {sosHostRuntime}");
public async Task ContinueExecution()
{
string command = null;
+ bool addPrefix = true;
switch (Debugger)
{
case NativeDebugger.Cdb:
command = "g";
+ // Don't add the !runcommand prefix because it gets printed when cdb stops
+ // again because the helper extension used .pcmd to set a stop command.
+ addPrefix = false;
break;
case NativeDebugger.Lldb:
command = "process continue";
command = "continue";
break;
}
- if (!await RunCommand(command))
+ if (!await RunCommand(command, addPrefix))
{
throw new Exception($"'{command}' FAILED");
}
}
}
- public async Task<bool> RunCommand(string command)
+ public async Task<bool> RunCommand(string command, bool addPrefix = true)
{
if (string.IsNullOrWhiteSpace(command))
{
throw new Exception("Debugger command empty or null");
}
- return await HandleCommand(command);
+ return await HandleCommand(command, addPrefix);
}
public async Task QuitDebugger()
return null;
}
- private async Task<bool> HandleCommand(string input)
+ private async Task<bool> HandleCommand(string input, bool addPrefix)
{
if (!await _scriptLogger.WaitForCommandPrompt())
{
input = input.Substring(0, firstPOUT) + poutMatchResult + input.Substring(secondPOUT + poutTag.Length);
}
}
- _processRunner.StandardInputWriteLine(_scriptLogger.ProcessCommand(ReplaceVariables(input)));
+ string command = ReplaceVariables(input);
+ if (addPrefix)
+ {
+ command = _scriptLogger.ProcessCommand(command);
+ }
+ _processRunner.StandardInputWriteLine(command);
ScriptLogger.CommandResult result = await _scriptLogger.WaitForCommandOutput();
_lastCommandOutput = result.CommandOutput;
public string ProcessCommand(string command)
{
- if (_debugger == NativeDebugger.Lldb)
+ switch (_debugger)
{
- command = string.Format("runcommand {0}", command);
+ case NativeDebugger.Cdb:
+ command = string.Format("!runcommand {0}", command);
+ break;
+
+ case NativeDebugger.Lldb:
+ command = string.Format("runcommand {0}", command);
+ break;
}
return command;
}
switch (_debugger)
{
case NativeDebugger.Cdb:
- // Some commands like DumpStack have ===> or -> in the output that looks
- // like the cdb prompt. Using a regex here to better match the cdb prompt
- // is way to slow.
- if (lastCommandOutput.EndsWith("=> ") || lastCommandOutput.EndsWith("-> "))
- {
- return;
- }
- commandEnd = lastCommandOutput.EndsWith("> ");
- break;
case NativeDebugger.Lldb:
commandError = lastCommandOutput.EndsWith("<END_COMMAND_ERROR>");
commandEnd = commandError || lastCommandOutput.EndsWith("<END_COMMAND_OUTPUT>");
return TestConfiguration.MakeCanonicalExePath(config.GetValue("CDBPath"));
}
+ public static string CDBHelperExtension(this TestConfiguration config)
+ {
+ return TestConfiguration.MakeCanonicalPath(config.GetValue("CDBHelperExtension"));
+ }
+
public static string LLDBHelperScript(this TestConfiguration config)
{
return TestConfiguration.MakeCanonicalPath(config.GetValue("LLDBHelperScript"));
--- /dev/null
+//--------------------------------------------------------------------
+//
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//
+// Description: contains an entry points required by WinDbg
+//
+//--------------------------------------------------------------------
+
+// Including SDKDDKVer.h defines the highest available Windows platform.
+
+// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
+// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
+
+#include <sdkddkver.h>
+
+// Windows Header Files
+#include <windows.h>
+#include <stdio.h>
+
+//
+// Define KDEXT_64BIT to make all wdbgexts APIs recognize 64 bit addresses
+// It is recommended for extensions to use 64 bit headers from wdbgexts so
+// the extensions could support 64 bit targets.
+//
+#define KDEXT_64BIT
+#include <dbgeng.h>
+
+#include <tchar.h>
+#include <strsafe.h>
+#include <dbghelp.h>
+
+#define DBGEXT_DEF extern "C" __declspec(dllexport) HRESULT __cdecl
+
+PDEBUG_CLIENT g_DebugClient = NULL;
+PDEBUG_CONTROL4 g_DebugControl = NULL;
+
+EXTERN_C __declspec(dllexport) void __cdecl DebugExtensionUninitialize(void);
+extern void __cdecl dprintf(PCSTR Format, ...);
+
+// DbgEng requires all extensions to implement this function.
+EXTERN_C __declspec(dllexport) HRESULT __cdecl
+DebugExtensionInitialize(
+ PULONG version,
+ PULONG flags)
+{
+ HRESULT hr;
+
+ *version = DEBUG_EXTENSION_VERSION(1, 0);
+ *flags = 0;
+
+ g_DebugClient = NULL;
+ g_DebugControl = NULL;
+
+ hr = DebugCreate(__uuidof(IDebugClient), (void **)&g_DebugClient);
+ if (FAILED(hr)) {
+ goto exit;
+ }
+ hr = g_DebugClient->QueryInterface(__uuidof(IDebugControl4), (void **)&g_DebugControl);
+ if (FAILED(hr)) {
+ goto exit;
+ }
+ hr = g_DebugControl->Execute(DEBUG_OUTCTL_IGNORE, ".pcmd -s \".echo <END_COMMAND_OUTPUT>\"", 0);
+ if (FAILED(hr)) {
+ goto exit;
+ }
+ dprintf("<END_COMMAND_OUTPUT>\n");
+exit:
+ if (FAILED(hr)) {
+ dprintf("<END_COMMAND_ERROR>\n");
+ DebugExtensionUninitialize();
+ }
+ return hr;
+}
+
+// WinDbg requires all extensions to implement this function.
+EXTERN_C __declspec(dllexport) void __cdecl
+DebugExtensionUninitialize(void)
+{
+ if (g_DebugControl != NULL) {
+ g_DebugControl->Release();
+ g_DebugControl = NULL;
+ }
+ if (g_DebugClient != NULL) {
+ g_DebugClient->Release();
+ g_DebugClient = NULL;
+ }
+}
+
+DBGEXT_DEF runcommand(__in PDEBUG_CLIENT4 client, __in PCSTR args)
+{
+ HRESULT hr = g_DebugControl->Execute(DEBUG_OUTCTL_ALL_CLIENTS, args, 0);
+ if (hr == S_OK) {
+ dprintf("<END_COMMAND_OUTPUT>\n");
+ }
+ else {
+ dprintf("<END_COMMAND_ERROR>\n");
+ }
+ return hr;
+}
+
+void __cdecl
+dprintf(PCSTR Format, ...)
+{
+ va_list Args;
+
+ va_start(Args, Format);
+ g_DebugControl->OutputVaList(DEBUG_OUTPUT_ERROR, Format, Args);
+ va_end(Args);
+}