Skip to content

Commit

Permalink
Work on debugger and fix assembly name in templates.
Browse files Browse the repository at this point in the history
  • Loading branch information
charlesbetros committed Apr 17, 2017
1 parent 0fef242 commit aaee21a
Show file tree
Hide file tree
Showing 19 changed files with 514 additions and 52 deletions.
2 changes: 1 addition & 1 deletion source/Cosmos.Build.MSBuild/Cosmos.targets
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
<UsingTask TaskName="Cosmos.Build.MSBuild.Ld" AssemblyFile="$(CosmosBuildTaskAssemblyFile)"/>
<UsingTask TaskName="Cosmos.Build.MSBuild.ReadNAsmMapToDebugInfo" AssemblyFile="$(CosmosBuildTaskAssemblyFile)"/>

<Target Name="CosmosCompile" AfterTargets="Build">
<Target Name="CoreCompile">
<Error Text="File %(Compile.Identity) is set to compile, but .Cosmos projects don't compile any source themselves!" Condition="$(Compile) != ''"/>
<CreateProperty Value="true" Condition="$(BinFormat) == 'elf'">
<Output PropertyName="IsELF" TaskParameter="Value"/>
Expand Down
9 changes: 9 additions & 0 deletions source/Cosmos.VS.DebugEngine/CmdIDList.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace Cosmos.VS.DebugEngine
{
public static class CmdIDList
{
public const int DebugLaunchCmdID = 0x0100;
public const int DebugExecCmdID = 0x0101;
public const int DebugLogCmdID = 0x0102;
}
}
62 changes: 62 additions & 0 deletions source/Cosmos.VS.DebugEngine/Commands/BaseDebugCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
using System;
using System.Runtime.InteropServices;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.OLE.Interop;
using Microsoft.VisualStudio.Shell;
using IServiceProvider = System.IServiceProvider;

namespace Cosmos.VS.DebugEngine.Commands
{
public abstract class BaseDebugCommand
{
protected IServiceProvider serviceProvider;

protected BaseDebugCommand(IServiceProvider serviceProvider)
{
this.serviceProvider = serviceProvider;
}

public virtual int Execute(uint nCmdExecOpt, IntPtr pvaIn, IntPtr pvaOut)
{
throw new NotImplementedException();
}

protected static int EnsureString(IntPtr pvaIn, out string arguments)
{
arguments = null;
if (pvaIn == IntPtr.Zero)
{
// No arguments.
return VSConstants.E_INVALIDARG;
}

object vaInObject = Marshal.GetObjectForNativeVariant(pvaIn);
if (vaInObject == null || vaInObject.GetType() != typeof(string))
{
return VSConstants.E_INVALIDARG;
}

arguments = vaInObject as string;
return VSConstants.S_OK;
}

protected static bool IsQueryParameterList(System.IntPtr pvaIn, System.IntPtr pvaOut, uint nCmdexecopt)
{
ushort lo = (ushort)(nCmdexecopt & (uint)0xffff);
ushort hi = (ushort)(nCmdexecopt >> 16);
if (lo == (ushort)OLECMDEXECOPT.OLECMDEXECOPT_SHOWHELP)
{
if (hi == VsMenus.VSCmdOptQueryParameterList)
{
if (pvaOut != IntPtr.Zero)
{
return true;
}
}
}

return false;
}

}
}
70 changes: 70 additions & 0 deletions source/Cosmos.VS.DebugEngine/Commands/DebugCommandHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
using System;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.OLE.Interop;
using IServiceProvider = System.IServiceProvider;

namespace Cosmos.VS.DebugEngine.Commands
{
public delegate int DebugCommandExecute(uint nCmdExecOpt, IntPtr pvaIn, IntPtr pvaOut);

public class DebugCommandHandler
{
public DebugCommandHandler(IServiceProvider serviceProvider)
{
var launchCommand = new DebugLaunchCommand(serviceProvider);
OnDebugLaunch += launchCommand.Execute;

var logCommand = new DebugLogCommand(serviceProvider);
OnDebugLog += logCommand.Execute;

var execCommand = new DebugExecCommand(serviceProvider);
OnDebugExec += execCommand.Execute;
}

public event DebugCommandExecute OnDebugLaunch;
public event DebugCommandExecute OnDebugExec;
public event DebugCommandExecute OnDebugLog;

public int Execute(uint nCmdID, uint nCmdExecOpt, IntPtr pvaIn, IntPtr pvaOut)
{
switch (nCmdID)
{
case CmdIDList.DebugLaunchCmdID:
if (OnDebugLaunch != null)
{
return OnDebugLaunch(nCmdExecOpt, pvaIn, pvaOut);
}
break;
case CmdIDList.DebugExecCmdID:
if (OnDebugExec != null)
{
return OnDebugExec(nCmdExecOpt, pvaIn, pvaOut);
}
break;
case CmdIDList.DebugLogCmdID:
if (OnDebugLog != null)
{
return OnDebugLog(nCmdExecOpt, pvaIn, pvaOut);
}
break;
}
global::System.Diagnostics.Debug.Fail("Unknown command id");
return VSConstants.E_NOTIMPL;
}

public int Query(uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText)
{
switch (prgCmds[0].cmdID)
{
case CmdIDList.DebugLaunchCmdID:
case CmdIDList.DebugExecCmdID:
case CmdIDList.DebugLogCmdID:
prgCmds[0].cmdf |= (uint)(OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_ENABLED | OLECMDF.OLECMDF_INVISIBLE);
return VSConstants.S_OK;
}

global::System.Diagnostics.Debug.Fail("Unknown command id");
return VSConstants.E_NOTIMPL;
}
}
}
88 changes: 88 additions & 0 deletions source/Cosmos.VS.DebugEngine/Commands/DebugExecCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
using System;
using System.Globalization;
using System.Runtime.InteropServices;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.Shell.Interop;

namespace Cosmos.VS.DebugEngine.Commands
{
public class DebugExecCommand : BaseDebugCommand
{
public DebugExecCommand(IServiceProvider serviceProvider)
: base(serviceProvider)
{
}

public override int Execute(uint nCmdExecOpt, IntPtr pvaIn, IntPtr pvaOut)
{
int hr;

if (IsQueryParameterList(pvaIn, pvaOut, nCmdExecOpt))
{
Marshal.GetNativeVariantForObject("$", pvaOut);
return VSConstants.S_OK;
}

string arguments;
hr = EnsureString(pvaIn, out arguments);
if (hr != VSConstants.S_OK)
return hr;

if (string.IsNullOrWhiteSpace(arguments))
throw new ArgumentException("Expected an MI command to execute (ex: Debug.MIDebugExec info sharedlibrary)");

DebugExec(arguments);

return VSConstants.S_OK;
}

private void DebugExec(string command)
{
var commandWindow = (IVsCommandWindow)serviceProvider.GetService(typeof(SVsCommandWindow));
bool atBreak = false;
var debugger = serviceProvider.GetService(typeof(SVsShellDebugger)) as IVsDebugger;
if (debugger != null)
{
DBGMODE[] mode = new DBGMODE[1];
if (debugger.GetMode(mode) == VSConstants.S_OK)
{
atBreak = mode[0] == DBGMODE.DBGMODE_Break;
}
}

string results = null;

try
{
if (atBreak)
{
commandWindow.ExecuteCommand(String.Format(CultureInfo.InvariantCulture, "Debug.EvaluateStatement -exec {0}", command));
}
else
{
//results = await MIDebugCommandDispatcher.ExecuteCommand(command);
}
}
catch (Exception e)
{
if (e.InnerException != null)
{
e = e.InnerException;
}

commandWindow.Print($"Error: {e.Message}\r\n");
}

if (results != null && results.Length > 0)
{
// Make sure that we are printing whole lines
if (!results.EndsWith("\n") && !results.EndsWith("\r\n"))
{
results = results + "\n";
}

commandWindow.Print(results);
}
}
}
}
115 changes: 115 additions & 0 deletions source/Cosmos.VS.DebugEngine/Commands/DebugLaunchCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
using System;
using System.Globalization;
using System.IO;
using System.Runtime.InteropServices;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.Shell.Interop;

namespace Cosmos.VS.DebugEngine.Commands
{
public class DebugLaunchCommand : BaseDebugCommand
{
private const string DebugLaunchCommandSyntax = "E,Executable:!(d) O,OptionsFile:!(d)";

private enum DebugLaunchCommandSwitchEnum
{
Executable,
OptionsFile
}

public DebugLaunchCommand(IServiceProvider serviceProvider)
: base(serviceProvider)
{
}

public override int Execute(uint nCmdExecOpt, IntPtr pvaIn, IntPtr pvaOut)
{
int hr;

if (IsQueryParameterList(pvaIn, pvaOut, nCmdExecOpt))
{
Marshal.GetNativeVariantForObject("$ /switchdefs:\"" + DebugLaunchCommandSyntax + "\"", pvaOut);
return VSConstants.S_OK;
}

string arguments;
hr = EnsureString(pvaIn, out arguments);
if (hr != VSConstants.S_OK)
return hr;

IVsParseCommandLine parseCommandLine = (IVsParseCommandLine)serviceProvider.GetService(typeof(SVsParseCommandLine));
hr = parseCommandLine.ParseCommandTail(arguments, iMaxParams: -1);
if (ErrorHandler.Failed(hr))
return hr;

hr = parseCommandLine.HasParams();
if (ErrorHandler.Failed(hr))
return hr;
if (hr == VSConstants.S_OK || parseCommandLine.HasSwitches() != VSConstants.S_OK)
{
string message = string.Concat("Unexpected syntax for MIDebugLaunch command. Expected:\n",
"Debug.MIDebugLaunch /Executable:<path_or_logical_name> /OptionsFile:<path>");
throw new ApplicationException(message);
}

hr = parseCommandLine.EvaluateSwitches(DebugLaunchCommandSyntax);
if (ErrorHandler.Failed(hr))
return hr;

string executable;
if (parseCommandLine.GetSwitchValue((int)DebugLaunchCommandSwitchEnum.Executable, out executable) != VSConstants.S_OK ||
string.IsNullOrWhiteSpace(executable))
{
throw new ArgumentException("Executable must be specified");
}

bool checkExecutableExists = false;
string options = string.Empty;

string optionsFilePath;
if (parseCommandLine.GetSwitchValue((int)DebugLaunchCommandSwitchEnum.OptionsFile, out optionsFilePath) == 0)
{
// When using the options file, we want to allow the executable to be just a logical name, but if
// one enters a real path, we should make sure it isn't mistyped. If the path contains a slash, we assume it
// is meant to be a real path so enforce that it exists
checkExecutableExists = (executable.IndexOf('\\') >= 0);

if (string.IsNullOrWhiteSpace(optionsFilePath))
throw new ArgumentException("Value expected for '/OptionsFile' option");

if (!File.Exists(optionsFilePath))
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "Options file '{0}' does not exist", optionsFilePath));

options = File.ReadAllText(optionsFilePath);
}

if (checkExecutableExists)
{
if (!File.Exists(executable))
{
throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "Executable '{0}' does not exist", executable));
}

executable = Path.GetFullPath(executable);
}

LaunchDebugTarget(executable, options);

return 0;
}

private void LaunchDebugTarget(string filePath, string options)
{
IVsDebugger4 debugger = (IVsDebugger4)serviceProvider.GetService(typeof(IVsDebugger));
VsDebugTargetInfo4[] debugTargets = new VsDebugTargetInfo4[1];
debugTargets[0].dlo = (uint)DEBUG_LAUNCH_OPERATION.DLO_CreateProcess;
debugTargets[0].bstrExe = filePath;
debugTargets[0].bstrOptions = options;
debugTargets[0].guidLaunchDebugEngine = Guids.DebugEngineGuid;
VsDebugTargetProcessInfo[] processInfo = new VsDebugTargetProcessInfo[debugTargets.Length];

debugger.LaunchDebugTargets4(1, debugTargets, processInfo);
}

}
}
Loading

0 comments on commit aaee21a

Please sign in to comment.