Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MIEngine: Introduce --thread and --frame options #1401

Merged
merged 2 commits into from
Jul 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 38 additions & 24 deletions src/MICore/CommandFactories/MICommandFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ public abstract class MICommandFactory

public abstract string Name { get; }

internal int MajorVersion { get; set; }

public static MICommandFactory GetInstance(MIMode mode, Debugger debugger)
{
MICommandFactory commandFactory;
Expand Down Expand Up @@ -119,16 +121,18 @@ public virtual async Task<Results> ThreadInfo(uint? threadid = null)

public async Task<Results> StackInfoDepth(int threadId, int maxDepth = 1000, ResultClass resultClass = ResultClass.done)
{
string command = string.Format(CultureInfo.InvariantCulture, @"-stack-info-depth {0}", maxDepth);
Results results = await ThreadCmdAsync(command, resultClass, threadId);
string command = "-stack-info-depth";
string args = string.Format(CultureInfo.InvariantCulture, $@"{maxDepth}");
Results results = await ThreadCmdAsync(command, args, resultClass, threadId);

return results;
}

public async Task<TupleValue[]> StackListFrames(int threadId, uint lowFrameLevel, uint highFrameLevel = 1000)
{
string command = string.Format(CultureInfo.InvariantCulture, @"-stack-list-frames {0} {1}", lowFrameLevel, highFrameLevel);
Results results = await ThreadCmdAsync(command, ResultClass.done, threadId);
string command = "-stack-list-frames";
string args = string.Format(CultureInfo.InvariantCulture, $@"{lowFrameLevel} {highFrameLevel}");
Results results = await ThreadCmdAsync(command, args, ResultClass.done, threadId);

ListValue list = results.Find<ListValue>("stack");
if (list is ResultListValue)
Expand Down Expand Up @@ -164,9 +168,10 @@ public async Task<Results> StackInfoFrame()
/// <returns></returns>
public async Task<ResultValue> StackListLocals(PrintValue printValues, int threadId, uint frameLevel)
{
string cmd = string.Format(CultureInfo.InvariantCulture, @"-stack-list-locals {0}", (int)printValues);
string cmd = "-stack-list-locals";
string args = string.Format(CultureInfo.InvariantCulture, $@"{(int)printValues}");

Results localsResults = await ThreadFrameCmdAsync(cmd, ResultClass.done, threadId, frameLevel);
Results localsResults = await ThreadFrameCmdAsync(cmd, args, ResultClass.done, threadId, frameLevel);
return localsResults.Find("locals");
}

Expand All @@ -180,8 +185,9 @@ public async Task<ResultValue> StackListLocals(PrintValue printValues, int threa
/// <returns>This returns an array of results of frames, which contains a level and an args array. </returns>
public virtual async Task<TupleValue[]> StackListArguments(PrintValue printValues, int threadId, uint lowFrameLevel, uint hiFrameLevel)
{
string cmd = string.Format(CultureInfo.InvariantCulture, @"-stack-list-arguments {0} {1} {2}", (int)printValues, lowFrameLevel, hiFrameLevel);
Results argumentsResults = await ThreadCmdAsync(cmd, ResultClass.done, threadId);
string command = "-stack-list-arguments";
string args = string.Format(CultureInfo.InvariantCulture, $@"{(int)printValues} {lowFrameLevel} {hiFrameLevel}");
Results argumentsResults = await ThreadCmdAsync(command, args, ResultClass.done, threadId);

return argumentsResults.Find<ListValue>("stack-args").IsEmpty()
? new TupleValue[0]
Expand Down Expand Up @@ -213,9 +219,9 @@ public async Task<ListValue> StackListArguments(PrintValue printValues, int thre
/// <returns>Returns an array of results for variables</returns>
public async Task<ValueListValue> StackListVariables(PrintValue printValues, int threadId, uint frameLevel)
{
string cmd = string.Format(CultureInfo.InvariantCulture, @"-stack-list-variables {0}", (int)printValues);

Results variablesResults = await ThreadFrameCmdAsync(cmd, ResultClass.done, threadId, frameLevel);
string cmd = "-stack-list-variables";
string args = string.Format(CultureInfo.InvariantCulture, $@"{(int)printValues}");
Results variablesResults = await ThreadFrameCmdAsync(cmd, args, ResultClass.done, threadId, frameLevel);
return variablesResults.Find<ValueListValue>("variables");
}

Expand All @@ -226,31 +232,36 @@ public async Task<ValueListValue> StackListVariables(PrintValue printValues, int
public async Task ExecStep(int threadId, ResultClass resultClass = ResultClass.running)
{
string command = "-exec-step";
await ThreadFrameCmdAsync(command, resultClass, threadId, 0);
string args = string.Empty;
await ThreadFrameCmdAsync(command, args, resultClass, threadId, 0);
}

public async Task ExecNext(int threadId, ResultClass resultClass = ResultClass.running)
{
string command = "-exec-next";
await ThreadFrameCmdAsync(command, resultClass, threadId, 0);
string args = string.Empty;
await ThreadFrameCmdAsync(command, args, resultClass, threadId, 0);
}

public async Task ExecFinish(int threadId, ResultClass resultClass = ResultClass.running)
{
string command = "-exec-finish";
await ThreadFrameCmdAsync(command, resultClass, threadId, 0);
string args = string.Empty;
await ThreadFrameCmdAsync(command, args, resultClass, threadId, 0);
}

public async Task ExecStepInstruction(int threadId, ResultClass resultClass = ResultClass.running)
{
string command = "-exec-step-instruction";
await ThreadFrameCmdAsync(command, resultClass, threadId, 0);
string args = string.Empty;
await ThreadFrameCmdAsync(command, args, resultClass, threadId, 0);
}

public async Task ExecNextInstruction(int threadId, ResultClass resultClass = ResultClass.running)
{
string command = "-exec-next-instruction";
await ThreadFrameCmdAsync(command, resultClass, threadId, 0);
string args = string.Empty;
await ThreadFrameCmdAsync(command, args, resultClass, threadId, 0);
}

/// <summary>
Expand Down Expand Up @@ -296,15 +307,17 @@ public async Task<string[]> DataListRegisterNames()

public async Task<TupleValue[]> DataListRegisterValues(int threadId)
{
string command = "-data-list-register-values x";
Results results = await ThreadCmdAsync(command, ResultClass.done, threadId);
string command = "-data-list-register-values";
string args = "x";
Results results = await ThreadCmdAsync(command, args, ResultClass.done, threadId);
return results.Find<ValueListValue>("register-values").AsArray<TupleValue>();
}

public async Task<string> DataEvaluateExpression(string expr, int threadId, uint frame)
{
string command = "-data-evaluate-expression \"" + expr + "\"";
Results results = await ThreadFrameCmdAsync(command, ResultClass.None, threadId, frame);
string command = "-data-evaluate-expression";
string args = $"\"{expr}\"";
Results results = await ThreadFrameCmdAsync(command, args, ResultClass.None, threadId, frame);
return results.FindString("value");
}

Expand Down Expand Up @@ -344,8 +357,9 @@ public virtual Task<bool> SetStepFiltering(bool enabled)
public virtual async Task<Results> VarCreate(string expression, int threadId, uint frameLevel, enum_EVALFLAGS dwFlags, ResultClass resultClass = ResultClass.done)
{
string quoteEscapedExpression = EscapeQuotes(HandleInvalidChars(expression));
string command = string.Format(CultureInfo.InvariantCulture, "-var-create - * \"{0}\"", quoteEscapedExpression);
Results results = await ThreadFrameCmdAsync(command, resultClass, threadId, frameLevel);
string command = "-var-create";
string args = string.Format(CultureInfo.InvariantCulture, $" - * \"{quoteEscapedExpression}\"");
Results results = await ThreadFrameCmdAsync(command, args, resultClass, threadId, frameLevel);

return results;
}
Expand Down Expand Up @@ -646,8 +660,8 @@ internal string HandleInvalidChars(string str)

#region Other

abstract protected Task<Results> ThreadFrameCmdAsync(string command, ResultClass expectedResultClass, int threadId, uint frameLevel);
abstract protected Task<Results> ThreadCmdAsync(string command, ResultClass expectedResultClass, int threadId);
abstract protected Task<Results> ThreadFrameCmdAsync(string command, string args, ResultClass expectedResultClass, int threadId, uint frameLevel);
abstract protected Task<Results> ThreadCmdAsync(string command, string args, ResultClass expectedResultClass, int threadId);

abstract public string GetSetEnvironmentVariableCommand(string name, string value);

Expand Down
44 changes: 34 additions & 10 deletions src/MICore/CommandFactories/gdb.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,24 +48,36 @@ public override bool AllowCommandsWhileRunning()
return false;
}

protected override async Task<Results> ThreadFrameCmdAsync(string command, ResultClass expectedResultClass, int threadId, uint frameLevel)
protected override async Task<Results> ThreadFrameCmdAsync(string command, string args, ResultClass expectedResultClass, int threadId, uint frameLevel)
{
// first aquire an exclusive lock. This is used as we don't want to fight with other commands that also require the current
// thread to be set to a particular value
ExclusiveLockToken lockToken = await _debugger.CommandLock.AquireExclusive();

try
{
await ThreadSelect(threadId, lockToken);
await StackSelectFrame(frameLevel, lockToken);

string threadFrameCommand;
// With source code of gdb 7.0.0, the --thread and --frame options were introduced and -thread-select and
// -stack-select-frame were deprecated
if (MajorVersion < 7)
{
await ThreadSelect(threadId, lockToken);
await StackSelectFrame(frameLevel, lockToken);
threadFrameCommand = string.Format(CultureInfo.InvariantCulture, $@"{command} {args}");
}
else
{
threadFrameCommand = string.Format(CultureInfo.InvariantCulture, $@"{command} --thread {threadId} --frame {frameLevel} {args}");
}

// Before we execute the provided command, we need to switch to a shared lock. This is because the provided
// command may be an expression evaluation command which could be long running, and we don't want to hold the
// exclusive lock during this.
lockToken.ConvertToSharedLock();
lockToken = null;

return await _debugger.CmdAsync(command, expectedResultClass);
return await _debugger.CmdAsync(threadFrameCommand, expectedResultClass);
}
finally
{
Expand All @@ -82,23 +94,34 @@ protected override async Task<Results> ThreadFrameCmdAsync(string command, Resul
}
}

protected override async Task<Results> ThreadCmdAsync(string command, ResultClass expectedResultClass, int threadId)
protected override async Task<Results> ThreadCmdAsync(string command, string args, ResultClass expectedResultClass, int threadId)
{
// first aquire an exclusive lock. This is used as we don't want to fight with other commands that also require the current
// thread to be set to a particular value
ExclusiveLockToken lockToken = await _debugger.CommandLock.AquireExclusive();

try
{
await ThreadSelect(threadId, lockToken);
string threadCommand;
// With source code of gdb 7.0.0, the --thread option was introduced and -thread-select
// was deprecated
if (MajorVersion < 7)
{
await ThreadSelect(threadId, lockToken);
threadCommand = string.Format(CultureInfo.InvariantCulture, $@"{command} {args}");
}
else
{
threadCommand = string.Format(CultureInfo.InvariantCulture, $@"{command} --thread {threadId} {args}"); ;
}

// Before we execute the provided command, we need to switch to a shared lock. This is because the provided
// command may be an expression evaluation command which could be long running, and we don't want to hold the
// exclusive lock during this.
lockToken.ConvertToSharedLock();
lockToken = null;

return await _debugger.CmdAsync(command, expectedResultClass);
return await _debugger.CmdAsync(threadCommand, expectedResultClass);
}
finally
{
Expand Down Expand Up @@ -301,12 +324,13 @@ public override async Task Catch(string name, bool onlyOnce = false, ResultClass

public override async Task<string[]> AutoComplete(string command, int threadId, uint frameLevel)
{
command = "-complete \"" + command + "\"";
string cmd = "-complete";
string args = $"\"{command}\"";
Results res;
if (threadId == -1)
res = await _debugger.CmdAsync(command, ResultClass.done);
res = await _debugger.CmdAsync($"{cmd} {args}", ResultClass.done);
else
res = await ThreadFrameCmdAsync(command, ResultClass.done, threadId, frameLevel);
res = await ThreadFrameCmdAsync(cmd, args, ResultClass.done, threadId, frameLevel);

var matchlist = res.Find<ValueListValue>("matches");

Expand Down
13 changes: 7 additions & 6 deletions src/MICore/CommandFactories/lldb.cs
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,10 @@ public async override Task<StringBuilder> BuildBreakInsert(string condition, boo

public override async Task<Results> VarCreate(string expression, int threadId, uint frameLevel, enum_EVALFLAGS dwFlags, ResultClass resultClass = ResultClass.done)
{
string command = "-var-create";
string quoteEscapedExpression = EscapeQuotes(expression);
string command = string.Format(CultureInfo.InvariantCulture, "-var-create - - \"{0}\"", quoteEscapedExpression); // use '-' to indicate that "--frame" should be used to determine the frame number
Results results = await ThreadFrameCmdAsync(command, resultClass, threadId, frameLevel);
string args = string.Format(CultureInfo.InvariantCulture, $"- - \"{quoteEscapedExpression}\""); // use '-' to indicate that "--frame" should be used to determine the frame number
Results results = await ThreadFrameCmdAsync(command, args, resultClass, threadId, frameLevel);

return results;
}
Expand All @@ -94,16 +95,16 @@ public override async Task<Results> VarListChildren(string variableReference, en
return results;
}

protected override async Task<Results> ThreadFrameCmdAsync(string command, ResultClass exepctedResultClass, int threadId, uint frameLevel)
protected override async Task<Results> ThreadFrameCmdAsync(string command, string args, ResultClass exepctedResultClass, int threadId, uint frameLevel)
{
string threadFrameCommand = string.Format(CultureInfo.InvariantCulture, @"{0} --thread {1} --frame {2}", command, threadId, frameLevel);
string threadFrameCommand = string.Format(CultureInfo.InvariantCulture, $@"{command} {args} --thread {threadId} --frame {frameLevel}");

return await _debugger.CmdAsync(threadFrameCommand, exepctedResultClass);
}

protected override async Task<Results> ThreadCmdAsync(string command, ResultClass expectedResultClass, int threadId)
protected override async Task<Results> ThreadCmdAsync(string command, string args, ResultClass expectedResultClass, int threadId)
{
string threadCommand = string.Format(CultureInfo.InvariantCulture, @"{0} --thread {1}", command, threadId);
string threadCommand = string.Format(CultureInfo.InvariantCulture, $@"{command} {args} --thread {threadId}");

return await _debugger.CmdAsync(threadCommand, expectedResultClass);
}
Expand Down
7 changes: 7 additions & 0 deletions src/MICore/Debugger.cs
Original file line number Diff line number Diff line change
Expand Up @@ -980,6 +980,13 @@ public void OnDebuggerProcessExit(/*OPTIONAL*/ string exitCode)
MIDebuggerInitializeFailedException exception;
string version = GdbVersionFromLog();

int majorVersion = -1;
if (!string.IsNullOrWhiteSpace(version))
{
int.TryParse(version.Split('.').FirstOrDefault(), out majorVersion);
}
MICommandFactory.MajorVersion = majorVersion;

// We can't use IsMinGW or IsCygwin because we never connected to the debugger
bool isMinGWOrCygwin = _launchOptions is LocalLaunchOptions &&
PlatformUtilities.IsWindows() &&
Expand Down