static void Main(string[] args) { if (args.Length != 3) { Console.Error.WriteLine("Usage: GetCpuSampleDuration.exe <trace.etl> <imageName> <functionName>"); return; } string tracePath = args[0]; string imageName = args[1]; string functionName = args[2]; Dictionary <string, Duration> matchDurationByCommandLine = new Dictionary <string, Duration>(); using (ITraceProcessor trace = TraceProcessor.Create(tracePath)) { IPendingResult <ISymbolDataSource> pendingSymbolData = trace.UseSymbols(); IPendingResult <ICpuSampleDataSource> pendingCpuSamplingData = trace.UseCpuSamplingData(); trace.Process(); ISymbolDataSource symbolData = pendingSymbolData.Result; ICpuSampleDataSource cpuSamplingData = pendingCpuSamplingData.Result; symbolData.LoadSymbolsForConsoleAsync(SymCachePath.Automatic, SymbolPath.Automatic).GetAwaiter().GetResult(); Console.WriteLine(); IThreadStackPattern pattern = AnalyzerThreadStackPattern.Parse($"{imageName}!{functionName}"); foreach (ICpuSample sample in cpuSamplingData.Samples) { if (sample.IsExecutingDeferredProcedureCall == true || sample.IsExecutingInterruptServicingRoutine == true) { continue; } if (sample.Stack != null && sample.Stack.Matches(pattern)) { string commandLine = sample.Process.CommandLine; if (!matchDurationByCommandLine.ContainsKey(commandLine)) { matchDurationByCommandLine.Add(commandLine, Duration.Zero); } matchDurationByCommandLine[commandLine] += sample.Weight; } } } foreach (string commandLine in matchDurationByCommandLine.Keys) { Console.WriteLine($"{commandLine}: {matchDurationByCommandLine[commandLine]}"); } }
public static int Main(string[] args) { if (args.Length != 1) { Console.Error.WriteLine("Usage: FindZombieProcess.exe <trace.etl>"); return(1); } string tracePath = args[0]; TraceProcessorSettings settings = new TraceProcessorSettings { AllowLostEvents = true }; using (ITraceProcessor trace = TraceProcessor.Create(tracePath, settings)) { IPendingResult <IHandleDataSource> pendingHandleData = trace.UseHandles(); IPendingResult <ISymbolDataSource> pendingSymbolData = trace.UseSymbols(); trace.Process(); IHandleDataSource handleData = pendingHandleData.Result; ISymbolDataSource symbolData = pendingSymbolData.Result; symbolData.LoadSymbolsForConsoleAsync(SymCachePath.Automatic, SymbolPath.Automatic).GetAwaiter().GetResult(); foreach (IProcessHandle processHandle in handleData.ProcessHandles) { // Zombie processes are processes which have exited but which still have a running process holding a handle to them if (processHandle.Process != null && !processHandle.CloseTime.HasValue && processHandle.Process.ExitTime.HasValue) { string owningProcessName = processHandle.Owner?.ImageName ?? "Unknown"; string targetProcessName = processHandle.Process?.ImageName ?? "Unknown"; Console.WriteLine($"Owning process: {owningProcessName} has handle to: {targetProcessName}"); } } return(0); } }
static void RunWithOptions(Options opts) { using (ITraceProcessor trace = TraceProcessor.Create(opts.etlFileName)) { IPendingResult <ICpuSampleDataSource> pendingCpuSampleData = trace.UseCpuSamplingData(); IPendingResult <ISymbolDataSource> pendingSymbolData = trace.UseSymbols(); trace.Process(); ISymbolDataSource symbolData = pendingSymbolData.Result; ICpuSampleDataSource cpuSampleData = pendingCpuSampleData.Result; var symbolProgress = new Progress <SymbolLoadingProgress>(progress => { Console.Write("\r{0:P} {1} of {2} symbols processed ({3} loaded)", (double)progress.ImagesProcessed / progress.ImagesTotal, progress.ImagesProcessed, progress.ImagesTotal, progress.ImagesLoaded); }); symbolData.LoadSymbolsAsync( SymCachePath.Automatic, SymbolPath.Automatic, symbolProgress) .GetAwaiter().GetResult(); Console.WriteLine(); var profileWriter = new ProfileWriter(opts.etlFileName, opts.includeInlinedFunctions, opts.includeProcessAndThreadIds, opts.stripSourceFileNamePrefix); var timeStart = opts.timeStart ?? 0; var timeEnd = opts.timeEnd ?? decimal.MaxValue; var exportAllProcesses = opts.processFilter == "*"; var processFilterSet = new HashSet <string>( opts.processFilter.Trim().Split(",", StringSplitOptions.RemoveEmptyEntries)); for (int i = 0; i < cpuSampleData.Samples.Count; i++) { if (i % 100 == 0) { Console.Write("\r{0:P} {1} of {2} samples processed", (double)i / cpuSampleData.Samples.Count, i, cpuSampleData.Samples.Count); } var cpuSample = cpuSampleData.Samples[i]; if ((cpuSample.IsExecutingDeferredProcedureCall ?? false) || (cpuSample.IsExecutingInterruptServicingRoutine ?? false)) { continue; } if (!exportAllProcesses) { var processImage = cpuSample.Process.Images .FirstOrDefault(image => image.FileName == cpuSample.Process.ImageName); string imagePath = processImage?.Path ?? cpuSample.Process.ImageName; if (!processFilterSet.Any(filter => imagePath.Contains(filter.Replace("/", "\\")))) { continue; } } var timestamp = cpuSample.Timestamp.RelativeTimestamp.TotalSeconds; if (timestamp < timeStart || timestamp > timeEnd) { continue; } profileWriter.AddSample(cpuSample); } Console.WriteLine(); long outputSize = profileWriter.Write(opts.outputFileName); Console.WriteLine("Wrote {0:N0} bytes to {1}", outputSize, opts.outputFileName); } }
static int Main(string[] args) { if (args.Length != 1) { Console.Error.WriteLine("Usage: PotentialDelayLoads.exe <trace.etl>"); return(1); } string tracePath = args[0]; var settings = new TraceProcessorSettings { AllowLostEvents = true, }; using (ITraceProcessor trace = TraceProcessor.Create(tracePath, settings)) { IPendingResult <IReferenceSetDataSource> pendingReferenceSet = trace.UseReferenceSetData(); IPendingResult <IProcessDataSource> pendingProcesses = trace.UseProcesses(); IPendingResult <ISymbolDataSource> pendingSymbols = trace.UseSymbols(); IPendingResult <IImageSectionDataSource> pendingImageSections = trace.UseImageSections(); trace.Process(); IProcessDataSource processData = pendingProcesses.Result; IReferenceSetDataSource referenceSetData = pendingReferenceSet.Result; ISymbolDataSource symbolData = pendingSymbols.Result; IImageSectionDataSource imageSectionData = pendingImageSections.Result; symbolData.LoadSymbolsForConsoleAsync(SymCachePath.Automatic, SymbolPath.Automatic).GetAwaiter().GetResult(); // // Create a mapping of all static images loaded into all processes during the course of the trace. // This is a mapping of images to a dictionary of [processes, IsPotentialDelayLoadTarget] // Dictionary <string, Dictionary <string, bool> > potentialDelayLoads = new Dictionary <string, Dictionary <string, bool> >(); // // Keep track of the image data for all of the images we've seen loaded. We use this later to look up // section names for the offsets being accessed. // Dictionary <string, IImage> imageData = new Dictionary <string, IImage>(); foreach (var proc in processData.Processes) { foreach (var image in proc.Images) { string processName = GenerateProcessNameString(proc); if (image.LoadTime != null) { Dictionary <string, bool> processDict; if (!potentialDelayLoads.ContainsKey(image.Path)) { processDict = new Dictionary <string, bool>(); potentialDelayLoads.Add(image.Path, processDict); } else { processDict = potentialDelayLoads[image.Path]; } if (!processDict.ContainsKey(processName)) { bool eligibleForDelayLoad = (image.LoadReason == ImageLoadReason.StaticDependency); processDict.Add(processName, eligibleForDelayLoad); } // // Save off whether or not this image is a potential delay load target. We only consider // static dependencies for delay loads. // processDict[processName] = processDict[processName] && (image.LoadReason == ImageLoadReason.StaticDependency); // // Save off a pointer to the image data for this image so we can look up sections later // if (!imageData.ContainsKey(image.Path)) { imageData.Add(image.Path, image); } } } } // // Enumerate every page access. We're going to check each one to see if it was a 'code' page being accessed, // and if it was we conclude that code from this image was used during the trace by that process. Therefore, // it's not something that should be delay loaded. // foreach (IReferenceSetInterval refSetInterval in referenceSetData.Intervals) { foreach (IReferenceSetAccessedPage pageAccess in refSetInterval.PageAccesses) { // // Make sure the page was accessed from the usermode process. // if (pageAccess.ImpactedProcess == null) { continue; } // // Ignore the memory compression process. This is a system service. // if (pageAccess.ImpactedProcess.ImageName.Equals("MemCompression")) { continue; } // // Make sure we have a file path // if (pageAccess?.Page?.Path == null) { continue; } var fileBeingAccessed = pageAccess?.Page?.Path; // // Not all file paths are images (think MFT or data files). Make sure this is in our image // dictionary. // if (!imageData.ContainsKey(pageAccess.Page.Path)) { continue; } // // Make sure that this image was listed in the image data // if (!potentialDelayLoads.ContainsKey(fileBeingAccessed)) { continue; } // // Grab the image data, and use this to get the info on the page that was being accessed. // var data = imageData[pageAccess.Page.Path]; var sectionName = GetSectionNameFromPage(pageAccess, data, imageSectionData, pageAccess.ImpactedProcess); // // We really only want consider .text pages, as we want to find images where the 'code' is never // used. We have to include "unknown" as well since this is what shows up for images that we // can't find symbols for. This effectively means for images without symbols we consider all pages. // if (!(sectionName.Contains(".text") || sectionName.Contains("Unknown"))) { continue; } // // If the loader accessed the page, it's still a potential delay load candidiate. // if (IsLoaderAccessedPage(pageAccess)) { continue; } // // A .text page was accessed from somewhere other then the loader. This image isn't // a delay load candidate for this process. // string processName = GenerateProcessNameString(pageAccess.ImpactedProcess); if ((potentialDelayLoads[fileBeingAccessed]).ContainsKey(processName)) { if ((potentialDelayLoads[fileBeingAccessed])[processName]) { (potentialDelayLoads[fileBeingAccessed])[processName] = false; } } else { potentialDelayLoads[fileBeingAccessed].Add(processName, false); } } } // // Print out all potential delays loads we found. We modify the output format to be in // process->image style for easier consumption from the console. // List <Tuple <string, string> > delayLoads = new List <Tuple <string, string> >(); foreach (var imagesLoaded in potentialDelayLoads) { foreach (var processesDict in imagesLoaded.Value) { if (processesDict.Value == true) { delayLoads.Add(new Tuple <string, string>(processesDict.Key, imagesLoaded.Key)); } } } delayLoads.Sort(); foreach (var delayload in delayLoads) { Console.WriteLine("{0} can delay load {1}", delayload.Item1, delayload.Item2); } } return(0); }