Skip to content

Commit

Permalink
Convert to Task
Browse files Browse the repository at this point in the history
  • Loading branch information
WardenGnaw authored and Trass3r committed Jul 14, 2021
1 parent 6cfe820 commit eee8458
Showing 1 changed file with 173 additions and 143 deletions.
316 changes: 173 additions & 143 deletions src/OpenDebugAD7/AD7DebugSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1415,208 +1415,238 @@ protected override void HandleGotoTargetsRequestAsync(IRequestResponder<GotoTarg
responder.SetResponse(response);
}

protected override void HandleStackTraceRequestAsync(IRequestResponder<StackTraceArguments, StackTraceResponse> responder)
protected override async void HandleStackTraceRequestAsync(IRequestResponder<StackTraceArguments, StackTraceResponse> responder)
{
int threadReference = responder.Arguments.ThreadId;
int startFrame = responder.Arguments.StartFrame.GetValueOrDefault(0);
int levels = responder.Arguments.Levels.GetValueOrDefault(0);

StackTraceResponse response = new StackTraceResponse()
try
{
TotalFrames = 0
};
int threadReference = responder.Arguments.ThreadId;
int startFrame = responder.Arguments.StartFrame.GetValueOrDefault(0);
int levels = responder.Arguments.Levels.GetValueOrDefault(0);

var response = new StackTraceResponse()
{
TotalFrames = 0
};

// Make sure we are stopped and receiving valid input or else return an empty stack trace
if (!m_isStopped || startFrame < 0 || levels < 0)
{
responder.SetResponse(response);
return;
}

// Make sure we are stopped and receiving valid input or else return an empty stack trace
if (m_isStopped && startFrame >= 0 && levels >= 0)
{
ThreadFrameEnumInfo frameEnumInfo = null;
IDebugThread2 thread;
lock (m_threads)
{
if (m_threads.TryGetValue(threadReference, out thread))
if (!m_threads.TryGetValue(threadReference, out thread))
{
enum_FRAMEINFO_FLAGS flags = enum_FRAMEINFO_FLAGS.FIF_FUNCNAME | // need a function name
enum_FRAMEINFO_FLAGS.FIF_FRAME | // need a frame object
enum_FRAMEINFO_FLAGS.FIF_FLAGS |
enum_FRAMEINFO_FLAGS.FIF_DEBUG_MODULEP;

uint radix = Constants.EvaluationRadix;

if (responder.Arguments.Format != null)
{
StackFrameFormat format = responder.Arguments.Format;

if (format.Hex == true)
{
radix = 16;
}

if (format.Line == true)
{
flags |= enum_FRAMEINFO_FLAGS.FIF_FUNCNAME_LINES;
}
// Invalid thread specified
responder.SetError(new ProtocolException(String.Format(CultureInfo.CurrentCulture, AD7Resources.Error_PropertyInvalid, StackTraceRequest.RequestType, "threadId")));
return;
}

if (format.Module == true)
{
flags |= enum_FRAMEINFO_FLAGS.FIF_FUNCNAME_MODULE;
}
enum_FRAMEINFO_FLAGS flags = enum_FRAMEINFO_FLAGS.FIF_FUNCNAME | // need a function name
enum_FRAMEINFO_FLAGS.FIF_FRAME | // need a frame object
enum_FRAMEINFO_FLAGS.FIF_FLAGS |
enum_FRAMEINFO_FLAGS.FIF_DEBUG_MODULEP;

if (format.Parameters == true)
{
flags |= enum_FRAMEINFO_FLAGS.FIF_FUNCNAME_ARGS;
}
uint radix = Constants.EvaluationRadix;

if (format.ParameterNames == true)
{
flags |= enum_FRAMEINFO_FLAGS.FIF_FUNCNAME_ARGS_NAMES;
}

if (format.ParameterTypes == true)
{
flags |= enum_FRAMEINFO_FLAGS.FIF_FUNCNAME_ARGS_TYPES;
}
if (responder.Arguments.Format != null)
{
StackFrameFormat format = responder.Arguments.Format;

if (format.ParameterValues == true)
{
flags |= enum_FRAMEINFO_FLAGS.FIF_FUNCNAME_ARGS_VALUES;
}
if (format.Hex == true)
{
radix = 16;
}
else

if (format.Line == true)
{
// No formatting flags provided in the request - use the default format, which includes the module name and argument names / types
flags |= enum_FRAMEINFO_FLAGS.FIF_FUNCNAME_MODULE |
enum_FRAMEINFO_FLAGS.FIF_FUNCNAME_ARGS |
enum_FRAMEINFO_FLAGS.FIF_FUNCNAME_ARGS_TYPES |
enum_FRAMEINFO_FLAGS.FIF_FUNCNAME_ARGS_NAMES;
flags |= enum_FRAMEINFO_FLAGS.FIF_FUNCNAME_LINES;
}

if (m_settingsCallback != null)
if (format.Module == true)
{
// MIEngine generally gets the radix from IDebugSettingsCallback110 rather than using the radix passed
m_settingsCallback.Radix = radix;
flags |= enum_FRAMEINFO_FLAGS.FIF_FUNCNAME_MODULE;
}

ErrorBuilder eb = new ErrorBuilder(() => AD7Resources.Error_Scenario_StackTrace);
if (format.Parameters == true)
{
flags |= enum_FRAMEINFO_FLAGS.FIF_FUNCNAME_ARGS;
}

try
if (format.ParameterNames == true)
{
eb.CheckHR(thread.EnumFrameInfo(flags, radix, out IEnumDebugFrameInfo2 frameEnum));
eb.CheckHR(frameEnum.GetCount(out uint totalFrames));
flags |= enum_FRAMEINFO_FLAGS.FIF_FUNCNAME_ARGS_NAMES;
}

frameEnumInfo = new ThreadFrameEnumInfo(frameEnum, totalFrames);
if (format.ParameterTypes == true)
{
flags |= enum_FRAMEINFO_FLAGS.FIF_FUNCNAME_ARGS_TYPES;
}
catch (AD7Exception ex)

if (format.ParameterValues == true)
{
responder.SetError(new ProtocolException(ex.Message, ex));
return;
flags |= enum_FRAMEINFO_FLAGS.FIF_FUNCNAME_ARGS_VALUES;
}
}
else
{
// Invalid thread specified
responder.SetError(new ProtocolException(String.Format(CultureInfo.CurrentCulture, AD7Resources.Error_PropertyInvalid, StackTraceRequest.RequestType, "threadId")));
return;
// No formatting flags provided in the request - use the default format, which includes the module name and argument names / types
flags |= enum_FRAMEINFO_FLAGS.FIF_FUNCNAME_MODULE |
enum_FRAMEINFO_FLAGS.FIF_FUNCNAME_ARGS |
enum_FRAMEINFO_FLAGS.FIF_FUNCNAME_ARGS_TYPES |
enum_FRAMEINFO_FLAGS.FIF_FUNCNAME_ARGS_NAMES;
}
}

if (startFrame < frameEnumInfo.TotalFrames)
{
if (startFrame != frameEnumInfo.CurrentPosition)
if (m_settingsCallback != null)
{
frameEnumInfo.FrameEnum.Reset();
frameEnumInfo.CurrentPosition = (uint)startFrame;

if (startFrame > 0)
{
frameEnumInfo.FrameEnum.Skip((uint)startFrame);
}
// MIEngine generally gets the radix from IDebugSettingsCallback110 rather than using the radix passed
m_settingsCallback.Radix = radix;
}

if (levels == 0)
ErrorBuilder eb = new ErrorBuilder(() => AD7Resources.Error_Scenario_StackTrace);

try
{
// take the rest of the stack frames
levels = (int)frameEnumInfo.TotalFrames - startFrame;
eb.CheckHR(thread.EnumFrameInfo(flags, radix, out IEnumDebugFrameInfo2 frameEnum));
eb.CheckHR(frameEnum.GetCount(out uint totalFrames));

frameEnumInfo = new ThreadFrameEnumInfo(frameEnum, totalFrames);
}
else
catch (AD7Exception ex)
{
levels = Math.Min((int)frameEnumInfo.TotalFrames - startFrame, levels);
responder.SetError(new ProtocolException(ex.Message, ex));
return;
}
}

if (startFrame >= frameEnumInfo.TotalFrames)
{
responder.SetResponse(response);
return;
}

var frameInfoArray = new FRAMEINFO[levels];
uint framesFetched = 0;
frameEnumInfo.FrameEnum.Next((uint)frameInfoArray.Length, frameInfoArray, ref framesFetched);
frameEnumInfo.CurrentPosition += framesFetched;
if (startFrame != frameEnumInfo.CurrentPosition)
{
frameEnumInfo.FrameEnum.Reset();
frameEnumInfo.CurrentPosition = (uint)startFrame;

for (int i = 0; i < framesFetched; i++)
if (startFrame > 0)
{
// TODO: annotated frames?
var frameInfo = frameInfoArray[i];
IDebugStackFrame2 frame = frameInfo.m_pFrame;
frameEnumInfo.FrameEnum.Skip((uint)startFrame);
}
}

int frameReference = 0;
TextPositionTuple textPosition = TextPositionTuple.Nil;
IDebugCodeContext2 memoryAddress = null;
if (levels == 0)
{
// take the rest of the stack frames
levels = (int)frameEnumInfo.TotalFrames - startFrame;
}
else
{
levels = Math.Min((int)frameEnumInfo.TotalFrames - startFrame, levels);
}

if (frame != null)
{
frameReference = m_frameHandles.Create(frame);
textPosition = TextPositionTuple.GetTextPositionOfFrame(m_pathConverter, frame) ?? TextPositionTuple.Nil;
frame.GetCodeContext(out memoryAddress);
}
var frameInfoArray = new FRAMEINFO[levels];
uint framesFetched = 0;
frameEnumInfo.FrameEnum.Next((uint)frameInfoArray.Length, frameInfoArray, ref framesFetched);
frameEnumInfo.CurrentPosition += framesFetched;

int? moduleId = null;
IDebugModule2 module = frameInfo.m_pModule;
if (module != null)
for (int i = 0; i < framesFetched; i++)
{
// TODO: annotated frames?
var frameInfo = frameInfoArray[i];
IDebugStackFrame2 frame = frameInfo.m_pFrame;

int frameReference = 0;
TextPositionTuple textPosition = TextPositionTuple.Nil;
IDebugCodeContext2 memoryAddress = null;

if (frame != null)
{
frameReference = m_frameHandles.Create(frame);
textPosition = TextPositionTuple.GetTextPositionOfFrame(m_pathConverter, frame) ?? TextPositionTuple.Nil;
frame.GetCodeContext(out memoryAddress);
}

int? moduleId = null;
IDebugModule2 module = frameInfo.m_pModule;
if (module != null)
{
lock (m_moduleMap)
{
lock (m_moduleMap)
if (m_moduleMap.TryGetValue(module, out int mapModuleId))
{
if (m_moduleMap.TryGetValue(module, out int mapModuleId))
{
moduleId = mapModuleId;
}
moduleId = mapModuleId;
}
}
}

string instructionPointerReference = null;
var contextInfo = new CONTEXT_INFO[1];
if (memoryAddress?.GetInfo(enum_CONTEXT_INFO_FIELDS.CIF_ADDRESS, contextInfo) == HRConstants.S_OK && contextInfo[0].dwFields.HasFlag(enum_CONTEXT_INFO_FIELDS.CIF_ADDRESS))
{
instructionPointerReference = contextInfo[0].bstrAddress;
}

response.StackFrames.Add(new ProtocolMessages.StackFrame()
{
Id = frameReference,
Name = frameInfo.m_bstrFuncName,
Source = textPosition.Source,
Line = textPosition.Line,
Column = textPosition.Column,
ModuleId = moduleId,
InstructionPointerReference = instructionPointerReference
});
string instructionPointerReference = null;
var contextInfo = new CONTEXT_INFO[1];
if (memoryAddress?.GetInfo(enum_CONTEXT_INFO_FIELDS.CIF_ADDRESS, contextInfo) == HRConstants.S_OK && contextInfo[0].dwFields.HasFlag(enum_CONTEXT_INFO_FIELDS.CIF_ADDRESS))
{
instructionPointerReference = contextInfo[0].bstrAddress;
}

if (!IsClientVS)
response.StackFrames.Add(new ProtocolMessages.StackFrame()
{
Parallel.ForEach(response.StackFrames, frame =>
Id = frameReference,
Name = frameInfo.m_bstrFuncName,
Source = textPosition.Source,
Line = textPosition.Line,
Column = textPosition.Column,
ModuleId = moduleId,
InstructionPointerReference = instructionPointerReference
});
}

if (!IsClientVS)
{
var cancellationTokenSource = new CancellationTokenSource();
try
{
CancellationToken cancellationToken = cancellationTokenSource.Token;
var frameTasks = response.StackFrames.Select(frame => Task.Run(() =>
{
if (frame.Source == null)
return;
var task = new Task<bool>(() => File.Exists(frame.Source.Path));
task.Start();
if (task.Wait(500) && !task.Result)
cancellationToken.ThrowIfCancellationRequested();
if (frame.Source != null && !File.Exists(frame.Source.Path))
{
cancellationToken.ThrowIfCancellationRequested();
// mark the stack frame to be skipped by default
frame.Source.PresentationHint = Source.PresentationHintValue.Deemphasize;
}
});
}
}));

response.TotalFrames = (int)frameEnumInfo.TotalFrames;
Task allFramesComplete = Task.WhenAll(frameTasks);
Task timeoutTask = Task.Delay(1000, cancellationToken);
try
{
await Task.WhenAny(allFramesComplete, timeoutTask);
}
catch (Exception e)
{
Debug.Fail("Ignoring exception computing frame state: " + e.ToString());
}
}
finally
{
cancellationTokenSource.Cancel();
cancellationTokenSource.Dispose();
}
}
}

responder.SetResponse(response);
response.TotalFrames = (int)frameEnumInfo.TotalFrames;

responder.SetResponse(response);
}
catch (Exception e)
{
responder.SetError(new ProtocolException(e.Message));
}
}

protected override void HandleScopesRequestAsync(IRequestResponder<ScopesArguments, ScopesResponse> responder)
Expand Down

0 comments on commit eee8458

Please sign in to comment.