Skip to content

Commit

Permalink
-Fix Import-DbgProfilerStackTrace not working
Browse files Browse the repository at this point in the history
-Fix Trace-DbgProfilerStack not being allowed to create global sessions
-Warn when attempting to operate on the last trace when no last trace exists
  • Loading branch information
lordmilko committed Dec 23, 2023
1 parent 9dd877e commit c84fc9c
Show file tree
Hide file tree
Showing 18 changed files with 158 additions and 40 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ We can assume that the "gci" command we executed was passed as a string to a var
```powershell
# Show the call stacks of any methods where the value "gci" was passed in (either as a raw string or
# a sub-member). Only show the first invocation of each method, and exclude namespace gunk from the
# resulting output
# resulting output (Tip: you can also specify parameter -Simple which implies -Unique -ExcludeNamespace)
C:\> Show-DbgProfilerStackTrace -StringValue gci -Unique -ExcludeNamespace
```

Expand Down
15 changes: 10 additions & 5 deletions src/DebugTools.PowerShell/Cmdlets/Base/StackFrameCmdlet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,19 @@ protected override void ProcessRecordEx()
{
var frames = Session.LastTrace;

foreach (var frame in frames)
if (frames == null)
WriteWarning("Last trace is empty. Did you forget to record a trace?");
else
{
Frame = frame.Root;
foreach (var frame in frames)
{
Frame = frame.Root;

if (ShouldIgnore())
continue;
if (ShouldIgnore())
continue;

DoProcessRecordEx();
DoProcessRecordEx();
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,14 @@ protected override void ProcessRecordEx()
frames.Add(Frame);
else
{
foreach (var frame in Session.LastTrace)
if (Session.LastTrace == null)
WriteWarning("Last trace is empty. Did you forget to record a trace?");
else
{
frames.Add(frame.Root);
foreach (var frame in Session.LastTrace)
{
frames.Add(frame.Root);
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ protected override void ProcessRecord()
{
var results = reader.Read(fs);

var session = new XmlFileProfilerSession(Path);
var session = new ProfilerSession(new FileXmlProfilerReaderConfig(Path));
session.Start(default);

var threads = new List<ThreadStack>();

Expand Down
4 changes: 4 additions & 0 deletions src/DebugTools.PowerShell/Cmdlets/TraceDbgProfilerStack.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ namespace DebugTools.PowerShell.Cmdlets
[Cmdlet(VerbsDiagnostic.Trace, "DbgProfilerStack")]
public class TraceDbgProfilerStack : ProfilerSessionCmdlet
{
public TraceDbgProfilerStack() : base(true)
{
}

protected override void ProcessRecordEx()
{
using (CtrlCHandler())
Expand Down
6 changes: 0 additions & 6 deletions src/DebugTools/Memory/DllInjector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,6 @@ public class DllInjector
private DataTargetMemoryStream dataTargetStream;
private Dictionary<string, ChaosPEFile> peFiles = new Dictionary<string, ChaosPEFile>();

public static int Test(string args)
{
Debug.WriteLine("success!");
return 0;
}

public DllInjector(Process process)
{
this.process = process;
Expand Down
16 changes: 12 additions & 4 deletions src/DebugTools/Profiler/ProfilerSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ namespace DebugTools.Profiler
{
public partial class ProfilerSession : IDisposable
{
public virtual int? PID => Target.ProcessId;
public int? PID => Target.ProcessId;

public virtual string Name => Target.Name;
public string Name => Target.Name;

public ProfilerSessionType Type { get; }

Expand Down Expand Up @@ -80,6 +80,15 @@ public ProfilerSession(IProfilerReaderConfig config)

switch (config.SessionType)
{
case ProfilerSessionType.Normal:
case ProfilerSessionType.Global:
Reader = new LiveEtwProfilerReader((LiveProfilerReaderConfig) config);
break;

case ProfilerSessionType.XmlFile:
Reader = new FileXmlProfilerReader((FileXmlProfilerReaderConfig) config);
break;

case ProfilerSessionType.EtwFile:
Reader = new FileEtwProfilerReader((FileEtwProfilerReaderConfig) config);
break;
Expand All @@ -89,8 +98,7 @@ public ProfilerSession(IProfilerReaderConfig config)
break;

default:
Reader = new LiveEtwProfilerReader((LiveProfilerReaderConfig) config);
break;
throw new NotImplementedException($"Don't know how to handle {nameof(ProfilerSessionType)} '{config.SessionType}'.");
}

SetEventHandlers();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System;

namespace DebugTools.Profiler
{
class FileXmlProfilerReaderConfig : IProfilerReaderConfig
{
public ProfilerSessionType SessionType => ProfilerSessionType.XmlFile;

public ProfilerSetting[] Settings => Array.Empty<ProfilerSetting>();

public string Path { get; }

public FileXmlProfilerReaderConfig(string path)
{
Path = path;
}
}
}
52 changes: 52 additions & 0 deletions src/DebugTools/Profiler/Reader/FileXmlProfilerReader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using System;
using DebugTools.Tracing;

namespace DebugTools.Profiler
{
class FileXmlProfilerReader : IProfilerReader
{
public IProfilerReaderConfig Config { get; }

public FileXmlProfilerReader(FileXmlProfilerReaderConfig config)
{
Config = config;
}

public void Initialize() => throw new NotImplementedException();

public void InitializeGlobal() => throw new NotImplementedException();

public void Execute() => throw new NotImplementedException();

public void Stop() => throw new NotImplementedException();

public IProfilerTarget CreateTarget() => new XmlFileProfilerTarget((FileXmlProfilerReaderConfig) Config);

public void Dispose()
{
}

#pragma warning disable CS0067
public event Action<MethodInfoArgs> MethodInfo;
public event Action<MethodInfoDetailedArgs> MethodInfoDetailed;
public event Action<ModuleLoadedArgs> ModuleLoaded;
public event Action<CallArgs> CallEnter;
public event Action<CallArgs> CallLeave;
public event Action<CallArgs> Tailcall;
public event Action<CallDetailedArgs> CallEnterDetailed;
public event Action<CallDetailedArgs> CallLeaveDetailed;
public event Action<CallDetailedArgs> TailcallDetailed;
public event Action<UnmanagedTransitionArgs> ManagedToUnmanaged;
public event Action<UnmanagedTransitionArgs> UnmanagedToManaged;
public event Action<ExceptionArgs> Exception;
public event Action<CallArgs> ExceptionFrameUnwind;
public event Action<ExceptionCompletedArgs> ExceptionCompleted;
public event Action<StaticFieldValueArgs> StaticFieldValue;
public event Action<ThreadArgs> ThreadCreate;
public event Action<ThreadArgs> ThreadDestroy;
public event Action<ThreadNameArgs> ThreadName;
public event Action<ShutdownArgs> Shutdown;
public event Action Completed;
#pragma warning enable CS0067
}
}
2 changes: 1 addition & 1 deletion src/DebugTools/Profiler/Target/EtwFileProfilerTarget.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace DebugTools.Profiler
class EtwFileProfilerTarget : IProfilerTarget
{
public string Name => config.FileName;
public int? ProcessId { get; }
public int? ProcessId => null;
public bool IsAlive => false; //Must be false so that GetImplicitProfilerSession doesn't see us

private FileEtwProfilerReaderConfig config;
Expand Down
36 changes: 36 additions & 0 deletions src/DebugTools/Profiler/Target/XmlFileProfilerTarget.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using System;
using System.Threading;

namespace DebugTools.Profiler
{
class XmlFileProfilerTarget : IProfilerTarget
{
public string Name => config.Path;
public int? ProcessId => null;
public bool IsAlive => false;

private FileXmlProfilerReaderConfig config;

public XmlFileProfilerTarget(FileXmlProfilerReaderConfig config)
{
this.config = config;
}

public void Start(Action startCallback, CancellationToken cancellationToken)
{
}

public void SetExitHandler(Action<bool> onTargetExit)
{
}

public void ExecuteCommand(MessageType messageType, object value)
{
throw new NotSupportedException();
}

public void Dispose()
{
}
}
}
14 changes: 0 additions & 14 deletions src/DebugTools/Profiler/XmlFileProfilerSession.cs

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@

namespace DebugTools
{
class InProessLocalDbgSessionProvider : LocalDbgSessionProvider<InjectedHostSession>
class InProcessLocalDbgSessionProvider : LocalDbgSessionProvider<InjectedHostSession>
{
public InProessLocalDbgSessionProvider() : base(DbgSessionType.InProcess, "Process")
public InProcessLocalDbgSessionProvider() : base(DbgSessionType.InProcess, "Process")
{
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public LocalDbgSessionProviderFactory()
{ typeof(LocalSOSProcess), new SOSLocalDbgSessionProvider() },
{ typeof(ProfilerSession), new ProfilerLocalDbgSessionProvider() },
{ typeof(LocalUiSession), new UiLocalDbgSessionProvider() },
{ typeof(InjectedHostSession), new InProessLocalDbgSessionProvider() }
{ typeof(InjectedHostSession), new InProcessLocalDbgSessionProvider() }
};

store = new LocalDbgSessionStore();
Expand Down
15 changes: 12 additions & 3 deletions src/DebugTools/Session/Local/ProfilerLocalDbgSessionProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public override ProfilerSession GetOrCreateSpecial(object context)
else
{
if (profilerContext.Mandatory)
throw new InvalidOperationException("Attempted to retrieve a the global profiler session, however one did not exist");
throw new InvalidOperationException("Attempted to retrieve the global profiler session, however one did not exist");
}

return global;
Expand Down Expand Up @@ -109,8 +109,7 @@ protected override bool TryGetFallbackSubSession(ProfilerSession[] dead, out Pro
return true;
}

//Special sessions are either file based or global. We don't want to allow implicitly returning file
//sessions, so we only check for global
//Special sessions are either file based or global. First, prefer global if it exists

var global = specialSessions.SingleOrDefault(s => s.Type == ProfilerSessionType.Global);

Expand All @@ -120,6 +119,16 @@ protected override bool TryGetFallbackSubSession(ProfilerSession[] dead, out Pro
return true;
}

//No global, we'll take anything we can get

var special = specialSessions.FirstOrDefault();

if (special != null)
{
subSession = special;
return true;
}

subSession = null;
return false;
}
Expand Down

0 comments on commit c84fc9c

Please sign in to comment.