Skip to content

Instantly share code, notes, and snippets.

@lowleveldesign
Created August 23, 2016 15:06
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save lowleveldesign/bf4cf3e02e06d15f446658dd84296074 to your computer and use it in GitHub Desktop.
Save lowleveldesign/bf4cf3e02e06d15f446658dd84296074 to your computer and use it in GitHub Desktop.
Code which enumerates appdomains in a remote process using ETW
using Microsoft.Diagnostics.Tracing;
using Microsoft.Diagnostics.Tracing.Session;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
namespace ClrDacManaged
{
class Program
{
private const ushort DCStartInitEventId = 147;
private const ushort DCStartCompleteEventId = 145;
private const ushort AppDomainDCStartEventId = 157;
private readonly TimeSpan rundownTimeout = TimeSpan.FromSeconds(3);
private readonly Dictionary<int, ICollection<AppDomainInfo>> processAppDomainsMap = new Dictionary<int, ICollection<AppDomainInfo>>();
private readonly int currentProcessId = Process.GetCurrentProcess().Id;
private DateTime lastTimeEventWasReceivedUtc;
private TraceEventSession session;
private bool completed;
public struct AppDomainInfo
{
public long Id;
public string Name;
}
public void CollectAppDomainInfo()
{
Debug.Assert(!completed);
using (session = new TraceEventSession("MusketeerEtwSession")) {
session.Source.Dynamic.All += ProcessTraceEvent;
session.EnableProvider("Microsoft-Windows-DotNETRuntimeRundown", TraceEventLevel.Verbose,
0x40L | // StartRundownKeyword
0x8L // LoaderRundownKeyword
);
ThreadPool.QueueUserWorkItem(WatchDog);
lastTimeEventWasReceivedUtc = DateTime.UtcNow;
session.Source.Process();
}
completed = true;
}
void WatchDog(object o)
{
while (true) {
Thread.Sleep(TimeSpan.FromSeconds(1));
if (session.IsActive && DateTime.UtcNow.Subtract(
lastTimeEventWasReceivedUtc) > rundownTimeout) {
// rundown should be finished by now
session.Stop();
break;
}
}
}
public void Stop()
{
if (session != null && session.IsActive) {
session.Stop();
}
}
void ProcessTraceEvent(TraceEvent traceEvent)
{
lastTimeEventWasReceivedUtc = DateTime.UtcNow;
if (traceEvent.ProcessID == currentProcessId) {
return;
}
if ((ushort)traceEvent.ID == DCStartInitEventId) {
Debug.Assert(!processAppDomainsMap.ContainsKey(traceEvent.ProcessID));
processAppDomainsMap.Add(traceEvent.ProcessID, new List<AppDomainInfo>());
} else if ((ushort)traceEvent.ID == AppDomainDCStartEventId) {
Debug.Assert(processAppDomainsMap.ContainsKey(traceEvent.ProcessID));
processAppDomainsMap[traceEvent.ProcessID].Add(new AppDomainInfo() {
Id = (long)traceEvent.PayloadByName("AppDomainID"),
Name = (string)traceEvent.PayloadByName("AppDomainName")
});
}
}
public IEnumerable<int> GetManagedProcessIds()
{
Debug.Assert(completed);
return processAppDomainsMap.Keys;
}
public IEnumerable<AppDomainInfo> GetAppDomainsForProcess(int pid)
{
Debug.Assert(completed);
ICollection<AppDomainInfo> appDomains;
return processAppDomainsMap.TryGetValue(pid, out appDomains) ? appDomains : new AppDomainInfo[0];
}
static void Main(string[] args)
{
var p = new Program();
Console.CancelKeyPress += (o, ev) => {
p.Stop();
};
p.CollectAppDomainInfo();
foreach (var pid in p.GetManagedProcessIds()) {
Console.WriteLine("### Managed process: {0} ###", pid);
foreach (var appdomain in p.GetAppDomainsForProcess(pid)) {
Console.WriteLine("==> AppDomain: {0} ({1})", appdomain.Name, appdomain.Id);
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment