File: ProcDumpArgsBuilder.cs
Web Access
Project: src\src\vstest\src\Microsoft.TestPlatform.Extensions.BlameDataCollector\Microsoft.TestPlatform.Extensions.BlameDataCollector.csproj (Microsoft.TestPlatform.Extensions.BlameDataCollector)
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Collections.Generic;
using System.Text;

using Microsoft.VisualStudio.TestPlatform.CoreUtilities.Helpers;
using Microsoft.VisualStudio.TestPlatform.Utilities.Helpers.Interfaces;

namespace Microsoft.TestPlatform.Extensions.BlameDataCollector;

#pragma warning disable CA1305

public class ProcDumpArgsBuilder : IProcDumpArgsBuilder
{
    private readonly IEnvironmentVariableHelper _environmentVariableHelper;

    public ProcDumpArgsBuilder() : this(new EnvironmentVariableHelper()) { }

    internal ProcDumpArgsBuilder(IEnvironmentVariableHelper environmentVariableHelper)
    {
        _environmentVariableHelper = environmentVariableHelper ?? throw new ArgumentNullException(nameof(environmentVariableHelper));
    }

    /// <inheritdoc />
    public string BuildTriggerBasedProcDumpArgs(int processId, string filename, IEnumerable<string> procDumpExceptionsList, bool isFullDump)
    {
        // -accepteula: Auto accept end-user license agreement
        //
        // -e: Write a dump when the process encounters an unhandled exception. Include the 1 to create dump on first chance exceptions.
        // We use -e 1 to make sure we are able to catch StackOverflow and AccessViolationException exceptions.
        // -g: Run as a native debugger in a managed process (no interop).
        // We use -g to be able to intercept  StackOverflow and AccessViolationException.
        // -t: Write a dump when the process terminates.
        // Collect the dump all the time, even if CollectAlways is not enabled to produce dumps for Environment.FailFast. We will later ignore the last
        // dump file for testhost when we know that test host did not crash.
        // -ma: Full dump argument.
        // -f: Filter the exceptions.
        // Filter the first chance exceptions only to those that are most likely to kill the whole process.

        // Fully override parameters to procdump
        var procdumpArgumentsFromEnv = _environmentVariableHelper.GetEnvironmentVariable("VSTEST_DUMP_PROCDUMPARGUMENTS")?.Trim();

        // Useful additional arguments are -n 100, to collect all dumps that you can, or -o to overwrite dump, or -f EXCEPTION_NAME to add exception to filter list
        var procdumpAdditonalArgumentsFromEnv = _environmentVariableHelper.GetEnvironmentVariable("VSTEST_DUMP_PROCDUMPADDITIONALARGUMENTS")?.Trim();
        StringBuilder procDumpArgument = new($"-accepteula -e 1 -g -t {procdumpAdditonalArgumentsFromEnv}");
        if (isFullDump)
        {
            procDumpArgument.Append("-ma ");
        }

        foreach (var exceptionFilter in procDumpExceptionsList)
        {
            procDumpArgument.Append($"-f {exceptionFilter} ");
        }

        procDumpArgument.Append($"{processId} {filename}.dmp");

        var argument = procdumpArgumentsFromEnv.IsNullOrWhiteSpace()
            ? procDumpArgument.ToString()
            : $"-accepteula {procdumpArgumentsFromEnv} {processId} {filename}.dmp";

        if (!argument.ToUpperInvariant().Contains("-accepteula".ToUpperInvariant()))
        {
            argument = $"-accepteula {argument}";
        }

        return argument;
    }

    /// <inheritdoc />
    public string BuildHangBasedProcDumpArgs(int processId, string filename, bool isFullDump)
    {
        // -accepteula: Auto accept end-user license agreement
        // -ma: Full dump argument.
        // -n: Number of dumps to capture.
        StringBuilder procDumpArgument = new("-accepteula -n 1");
        if (isFullDump)
        {
            procDumpArgument.Append(" -ma");
        }

        procDumpArgument.Append($" {processId} {filename}.dmp");
        var argument = procDumpArgument.ToString();

        return argument;
    }
}

#pragma warning restore CA1305