Skip to content
This repository has been archived by the owner on Apr 5, 2024. It is now read-only.

Commit

Permalink
Improve attaching to unity processes.
Browse files Browse the repository at this point in the history
Updated regex to support PS4, Xbox One, and Switch.
Added additional log outputs for locating issues in future releases.
  • Loading branch information
miniwolf committed Aug 14, 2018
1 parent 43bf68a commit 20daa3b
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 74 deletions.
2 changes: 1 addition & 1 deletion MonoDebug
Submodule MonoDebug updated 1 files
+2 −1 src/Protocol.cs
2 changes: 1 addition & 1 deletion MonoDevelop.Debugger.Soft.Unity
4 changes: 3 additions & 1 deletion UnityDebug/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,17 +68,19 @@ static void Main(string[] argv)
{
RunSession(Console.OpenStandardInput(), Console.OpenStandardOutput());
}
catch(Exception e)
catch(Exception e)
{
Log.Write ("Exception: " + e);
}
}

static void RunSession(Stream inputStream, Stream outputStream)
{
Log.Write("Running session");
DebugSession debugSession = new UnityDebugSession();
DebuggerLoggingService.CustomLogger = new CustomLogger();
debugSession.Start(inputStream, outputStream).Wait();
Log.Write("Session Terminated");
}

static string GetUnityProcesses()
Expand Down
92 changes: 47 additions & 45 deletions UnityDebug/UnityAttach.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,49 +6,51 @@

namespace UnityDebug
{
public static class UnityAttach
{
static readonly Dictionary<string, string> targetNameToProcessName = new Dictionary<string,string>
{
{ "unity editor", "Unity Editor" },
{ "osx player", "OSXPlayer" },
{ "windows player", "WindowsPlayer" },
{ "linux player", "LinuxPlayer" },
{ "ios player", "iPhonePlayer" },
{ "android player", "AndroidPlayer" }
};


public static IEnumerable<UnityProcessInfo> GetAttachableProcesses(string targetName)
{
var match = Regex.Match(targetName, "\\(([0-9]+)\\)");
var processId = -1;
if (match.Success)
{
processId = Convert.ToInt32(match.Groups[1].Value);
targetName = targetName.Substring(0, targetName.IndexOf("(") - 1);
}
string processName;

UnityProcessDiscovery.GetProcessOptions options = UnityProcessDiscovery.GetProcessOptions.All;

if (!targetNameToProcessName.TryGetValue (targetName.ToLower (), out processName)) {
processName = targetName;
} else {
if (processName == "Unity Editor")
options = UnityProcessDiscovery.GetProcessOptions.Editor;
else
options = UnityProcessDiscovery.GetProcessOptions.Players;
}

var processes = UnityProcessDiscovery.GetAttachableProcesses (options);

processes.ForEach (p => Log.Write ("Found Unity process: " + p.Name + " (" + p.Id + ")"));

return processId == -1
? processes.Where (p => p.Name.Contains(processName))
: processes.Where(p => p.Name.Contains(processName) && p.Id == processId);
}
}
public static class UnityAttach
{
static readonly Dictionary<string, string> targetNameToProcessName = new Dictionary<string, string>
{
{ "unity editor", "Unity Editor" },
{ "osx player", "OSXPlayer" },
{ "windows player", "WindowsPlayer" },
{ "linux player", "LinuxPlayer" },
{ "ios player", "iPhonePlayer" },
{ "android player", "AndroidPlayer" },
{ "ps4 player", "PS4Player" },
{ "xbox one player", "XboxOnePlayer" },
{ "switch player", "SwitchPlayer" },
};

public static IEnumerable<UnityProcessInfo> GetAttachableProcesses(string targetName)
{
var match = Regex.Match(targetName, "\\(([0-9]+)\\)");
var processId = -1;
if (match.Success)
{
processId = Convert.ToInt32(match.Groups[1].Value);
targetName = targetName.Substring(0, targetName.IndexOf("(") - 1);
}

UnityProcessDiscovery.GetProcessOptions options = UnityProcessDiscovery.GetProcessOptions.All;

if (!targetNameToProcessName.TryGetValue(targetName.ToLower(), out var processName))
{
processName = targetName;
}
else
{
options = processName == "Unity Editor"
? UnityProcessDiscovery.GetProcessOptions.Editor
: UnityProcessDiscovery.GetProcessOptions.Players;
}

var processes = UnityProcessDiscovery.GetAttachableProcesses(options);

processes.ForEach(p => Log.Write("Found Unity process: " + p.Name + " (" + p.Id + ")"));

return processId == -1
? processes.Where(p => p.Name.Contains(processName))
: processes.Where(p => p.Name.Contains(processName) && p.Id == processId);
}
}
}

77 changes: 51 additions & 26 deletions UnityDebug/UnityDebugSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ internal class UnityDebugSession : DebugSession

public UnityDebugSession()
{
Log.Write("Constructing UnityDebugSession");
m_ResumeEvent = new AutoResetEvent(false);
m_Breakpoints = new SourceBreakpoint[0];
m_VariableHandles = new Handles<ObjectValue[]>();
Expand Down Expand Up @@ -176,6 +177,8 @@ public UnityDebugSession()
m_Session.OutputWriter = (isStdErr, text) => {
SendOutput(isStdErr ? "stderr" : "stdout", text);
};

Log.Write("Done constructing UnityDebugSession");
}

public StackFrame Frame { get; set; }
Expand Down Expand Up @@ -224,15 +227,18 @@ public override void Launch(Response response, dynamic args)

public override void Attach(Response response, dynamic args)
{
Log.Write($"UnityDebug: Attach: {response} ; {args}");
string name = GetString (args, "name");

SetExceptionBreakpoints(args.__exceptionOptions);

Log.Write($"UnityDebug: Searching for Unity process '{name}'");
SendOutput("stdout", "UnityDebug: Searching for Unity process '" + name + "'");

var processes = UnityAttach.GetAttachableProcesses(name).ToArray ();

if (processes.Length == 0) {
Log.Write($"Could not find target name '{name}'.");
SendErrorResponse (response, 8001, "Could not find target name '{_name}'. Is it running?", new { _name = name});
return;
}
Expand Down Expand Up @@ -266,24 +272,31 @@ public override void Attach(Response response, dynamic args)

Connect(attachInfo.Address, attachInfo.Port);

Log.Write($"UnityDebug: Attached to Unity process '{process.Name}' ({process.Id})");
SendOutput("stdout", "UnityDebug: Attached to Unity process '" + process.Name + "' (" + process.Id + ")\n");
SendResponse(response);
}

void TooManyInstances(Response response, string name, UnityProcessInfo[] processes)
{
Log.Write($"Multiple targets with name '{name}' running. Unable to connect.");
SendErrorResponse(response, 8002, "Multiple targets with name '{_name}' running. Unable to connect.\n" +
"Use \"Unity Attach Debugger\" from the command palette (View > Command Palette...) to specify which process to attach to.", new { _name = name });

Log.Write($"UnityDebug: Multiple targets with name '{name}' running. Unable to connect.)");
SendOutput("stdout", "UnityDebug: Multiple targets with name '" + name + "' running. Unable to connect.\n" +
"Use \"Unity Attach Debugger\" from the command palette (View > Command Palette...) to specify which process to attach to.");

foreach (var p in processes)
{
Log.Write($"UnityDebug: Found Unity process '{p.Name}' ({p.Id})");
SendOutput("stdout", "UnityDebug: Found Unity process '" + p.Name + "' (" + p.Id + ")\n");
}
}

void Connect(IPAddress address, int port)
{
Log.Write($"UnityDebug: Connect to: {address}:{port}");
lock (m_Lock) {

var args0 = new SoftDebuggerConnectArgs(string.Empty, address, port) {
Expand All @@ -300,6 +313,7 @@ void Connect(IPAddress address, int port)
//---- private ------------------------------------------
void SetExceptionBreakpoints(dynamic exceptionOptions)
{
Log.Write($"UnityDebug: SetExceptionBreakpoints: {exceptionOptions}");
if (exceptionOptions == null)
{
return;
Expand Down Expand Up @@ -338,6 +352,8 @@ void SetExceptionBreakpoints(dynamic exceptionOptions)

public override void Disconnect(Response response, dynamic args)
{
Log.Write($"UnityDebug: Disconnect: {args}");
Log.Write($"UnityDebug: Disconnect: {response}");
if (unityDebugConnector != null) {
unityDebugConnector.OnDisconnect ();
unityDebugConnector = null;
Expand All @@ -361,12 +377,14 @@ public override void Disconnect(Response response, dynamic args)

public override void SetFunctionBreakpoints(Response response, dynamic arguments)
{
Log.Write($"UnityDebug: SetFunctionBreakpoints: {response} ; {arguments}");
var breakpoints = new List<ResponseBreakpoint>();
SendResponse(response, new SetFunctionBreakpointsResponse(breakpoints));
}

public override void Continue(Response response, dynamic args)
public override void Continue(Response response, dynamic arguments)
{
Log.Write($"UnityDebug: Continue: {response} ; {arguments}");
WaitForSuspend();
SendResponse(response, new ContinueResponseBody());
lock (m_Lock) {
Expand All @@ -377,16 +395,9 @@ public override void Continue(Response response, dynamic args)
}
}

void WaitForSuspend()
{
if (!m_DebuggeeExecuting) return;

m_ResumeEvent.WaitOne();
m_DebuggeeExecuting = false;
}

public override void Next(Response response, dynamic args)
public override void Next(Response response, dynamic arguments)
{
Log.Write($"UnityDebug: Next: {response} ; {arguments}");
WaitForSuspend();
SendResponse(response);
lock (m_Lock) {
Expand All @@ -397,8 +408,9 @@ public override void Next(Response response, dynamic args)
}
}

public override void StepIn(Response response, dynamic args)
public override void StepIn(Response response, dynamic arguments)
{
Log.Write($"UnityDebug: StepIn: {response} ; {arguments}");
WaitForSuspend();
SendResponse(response);
lock (m_Lock) {
Expand All @@ -409,8 +421,9 @@ public override void StepIn(Response response, dynamic args)
}
}

public override void StepOut(Response response, dynamic args)
public override void StepOut(Response response, dynamic arguments)
{
Log.Write($"UnityDebug: StepIn: {response} ; {arguments}");
WaitForSuspend();
SendResponse(response);
lock (m_Lock) {
Expand All @@ -421,8 +434,9 @@ public override void StepOut(Response response, dynamic args)
}
}

public override void Pause(Response response, dynamic args)
public override void Pause(Response response, dynamic arguments)
{
Log.Write($"UnityDebug: StepIn: {response} ; {arguments}");
SendResponse(response);
PauseDebugger();
}
Expand All @@ -435,15 +449,15 @@ void PauseDebugger()
}
}

protected override void SetVariable(Response response, object args)
protected override void SetVariable(Response response, object arguments)
{
var reference = GetInt(args, "variablesReference", -1);
var reference = GetInt(arguments, "variablesReference", -1);
if (reference == -1) {
SendErrorResponse(response, 3009, "variables: property 'variablesReference' is missing", null, false, true);
return;
}

var value = GetString(args, "value");
var value = GetString(arguments, "value");
if (m_VariableHandles.TryGet(reference, out var children)) {
if (children != null && children.Length > 0) {
if (children.Length > MAX_CHILDREN) {
Expand All @@ -455,7 +469,7 @@ protected override void SetVariable(Response response, object args)
continue;
v.WaitHandle.WaitOne();
var variable = CreateVariable(v);
if (variable.name == GetString(args, "name"))
if (variable.name == GetString(arguments, "name"))
{
v.Value = value;
SendResponse(response, new SetVariablesResponseBody(value, variable.type, variable.variablesReference));
Expand All @@ -465,17 +479,19 @@ protected override void SetVariable(Response response, object args)
}
}

public override void SetExceptionBreakpoints(Response response, dynamic args)
public override void SetExceptionBreakpoints(Response response, dynamic arguments)
{
SetExceptionBreakpoints(args.exceptionOptions);
Log.Write($"UnityDebug: StepIn: {response} ; {arguments}");
SetExceptionBreakpoints(arguments.exceptionOptions);
SendResponse(response);
}

public override void SetBreakpoints(Response response, dynamic args)
public override void SetBreakpoints(Response response, dynamic arguments)
{
Log.Write($"UnityDebug: SetBreakpoints: {response} ; {arguments}");
string path = null;
if (args.source != null) {
var p = (string)args.source.path;
if (arguments.source != null) {
var p = (string)arguments.source.path;
if (p != null && p.Trim().Length > 0) {
path = p;
}
Expand All @@ -491,7 +507,7 @@ public override void SetBreakpoints(Response response, dynamic args)
return;
}

SourceBreakpoint[] newBreakpoints = getBreakpoints(args, "breakpoints");
SourceBreakpoint[] newBreakpoints = getBreakpoints(arguments, "breakpoints");
var lines = newBreakpoints.Select(bp => bp.line);
var breakpointsToRemove = m_Breakpoints.Where(bp => !lines.Contains(bp.line)).ToArray();
foreach (Breakpoint breakpoint in m_Session.Breakpoints.GetBreakpoints())
Expand Down Expand Up @@ -524,10 +540,11 @@ public override void SetBreakpoints(Response response, dynamic args)
SendResponse(response, new SetBreakpointsResponseBody(responseBreakpoints));
}

public override void StackTrace(Response response, dynamic args)
public override void StackTrace(Response response, dynamic arguments)
{
int maxLevels = GetInt(args, "levels", 10);
int threadReference = GetInt(args, "threadId", 0);
Log.Write($"UnityDebug: StackTrace: {response} ; {arguments}");
int maxLevels = GetInt(arguments, "levels", 10);
int threadReference = GetInt(arguments, "threadId", 0);

WaitForSuspend();

Expand Down Expand Up @@ -849,5 +866,13 @@ void DebuggerKill()
}
}
}

void WaitForSuspend()
{
if (!m_DebuggeeExecuting) return;

m_ResumeEvent.WaitOne();
m_DebuggeeExecuting = false;
}
}
}

0 comments on commit 20daa3b

Please sign in to comment.