Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Procdump Arguments Changed #1700

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,16 @@ internal static class Constants
public const string DumpModeKey = "CollectDump";

/// <summary>
/// Procdump 32 bit version
/// </summary>
public const string ProcdumpProcess = "procdump.exe";

/// <summary>
/// Procdump 64 bit version
/// </summary>
public const string Procdump64Process = "procdump64.exe";

///<summary>
/// Configuration key name for collect dump always
/// </summary>
public const string CollectDumpAlwaysKey = "CollectAlways";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

namespace Microsoft.TestPlatform.Extensions.BlameDataCollector.Interfaces
{
using System;

public interface INativeMethodsHelper
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can remove this interface and make NativeMethodsHelper a static class as it has methods which are not using any class level variables. Also class seems more like helper class this making it static makes sense.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Made it via interface to use it for unit tests.

{
/// <summary>
/// Returns if a process is 64 bit process
/// </summary>
/// <param name="processHandle">Process Handle</param>
/// <returns>Bool for Is64Bit</returns>
bool Is64Bit(IntPtr processHandle);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

namespace Microsoft.TestPlatform.Extensions.BlameDataCollector
{
using System;
using System.Runtime.InteropServices;
using Microsoft.TestPlatform.Extensions.BlameDataCollector.Interfaces;
using Microsoft.VisualStudio.TestPlatform.ObjectModel;

public class NativeMethodsHelper : INativeMethodsHelper
{
/// <summary>
/// Returns if a process is 64 bit process
/// </summary>
/// <param name="processHandle">Process Handle</param>
/// <returns>Bool for Is64Bit</returns>
public bool Is64Bit(IntPtr processHandle)
{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this work for 32 bit os as well

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We use this condition only for 64 bit

// WOW64 is the x86 emulator that allows 32 bit Windows - based applications to run seamlessly on 64 bit Windows.
bool isWow64 = false;

// If the function succeeds, the return value is a nonzero value.
if (!IsWow64Process(processHandle, out isWow64))
{
if (EqtTrace.IsVerboseEnabled)
{
EqtTrace.Verbose("NativeMethodsHelper: The call to IsWow64Process failed.");
}
}

return !isWow64;
}

// A pointer to a value that is set to TRUE if the process is running under WOW64.
// If the process is running under 32-bit Windows, the value is set to FALSE.
// If the process is a 64-bit application running under 64-bit Windows, the value is also set to FALSE.
[DllImport("kernel32.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool IsWow64Process([In] IntPtr process, [Out] out bool wow64Process);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@
namespace Microsoft.TestPlatform.Extensions.BlameDataCollector
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Text;
using Microsoft.TestPlatform.Extensions.BlameDataCollector.Interfaces;
using Microsoft.VisualStudio.TestPlatform.ObjectModel;
using Microsoft.VisualStudio.TestPlatform.PlatformAbstractions;
using Microsoft.VisualStudio.TestPlatform.PlatformAbstractions.Interfaces;
Expand All @@ -15,27 +17,35 @@ namespace Microsoft.TestPlatform.Extensions.BlameDataCollector

public class ProcessDumpUtility : IProcessDumpUtility
{
private static List<string> procDumpExceptionsList;
private IProcessHelper processHelper;
private IFileHelper fileHelper;
private IEnvironment environment;
private Process procDumpProcess;
private string testResultsDirectory;
private string dumpFileName;
private INativeMethodsHelper nativeMethodsHelper;

public ProcessDumpUtility()
: this(new ProcessHelper(), new FileHelper(), new PlatformEnvironment())
: this(new ProcessHelper(), new FileHelper(), new PlatformEnvironment(), new NativeMethodsHelper())
{
}

public ProcessDumpUtility(IProcessHelper processHelper, IFileHelper fileHelper, IEnvironment environment)
public ProcessDumpUtility(IProcessHelper processHelper, IFileHelper fileHelper, IEnvironment environment, INativeMethodsHelper nativeMethodsHelper)
{
this.processHelper = processHelper;
this.fileHelper = fileHelper;
this.environment = environment;
this.nativeMethodsHelper = nativeMethodsHelper;
ProcessDumpUtility.procDumpExceptionsList = new List<string>()
{
"STACK_OVERFLOW",
"ACCESS_VIOLATION"
};
}

/// <inheritdoc/>
public string GetDumpFile()
/// <inheritdoc/>
public string GetDumpFile()
{
if (this.procDumpProcess == null)
{
Expand Down Expand Up @@ -77,7 +87,7 @@ public void StartProcessDump(int processId, string dumpFileGuid, string testResu
this.testResultsDirectory = testResultsDirectory;

this.procDumpProcess = this.processHelper.LaunchProcess(
this.GetProcDumpExecutable(),
this.GetProcDumpExecutable(processId),
ProcessDumpUtility.BuildProcDumpArgs(processId, this.dumpFileName, isFullDump),
testResultsDirectory,
null,
Expand All @@ -101,37 +111,57 @@ public void StartProcessDump(int processId, string dumpFileGuid, string testResu
private static string BuildProcDumpArgs(int processId, string filename, bool isFullDump = false)
{
// -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.
// -g: Run as a native debugger in a managed process (no interop).
// -t: Write a dump when the process terminates.
// -ma: Full dump argument.
// -f: Filter the exceptions.
StringBuilder procDumpArgument = new StringBuilder("-accepteula -e 1 -g -t ");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice :)

if (isFullDump)
{
// This will create a fulldump of the process with specified filename
return "-accepteula -t -ma " + processId + " " + filename + ".dmp";
procDumpArgument.Append("-ma ");
}
else

foreach (var exceptionFilter in ProcessDumpUtility.procDumpExceptionsList)
{
// This will create a minidump of the process with specified filename
return "-accepteula -t " + processId + " " + filename + ".dmp";
procDumpArgument.Append($"-f {exceptionFilter} ");
}

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

if (EqtTrace.IsInfoEnabled)
{
EqtTrace.Info($"ProcessDumpUtility : The procdump argument is {argument}");
}

return argument;
}

/// <summary>
/// Get procdump executable path
/// </summary>
/// <param name="processId">
/// Process Id
/// </param>
/// <returns>procdump executable path</returns>
private string GetProcDumpExecutable()
private string GetProcDumpExecutable(int processId)
{
var procdumpPath = Environment.GetEnvironmentVariable("PROCDUMP_PATH");

if (!string.IsNullOrWhiteSpace(procdumpPath))
{
string filename = string.Empty;

if (this.environment.Architecture == PlatformArchitecture.X64)
// Launch procdump according to process architecture
if (this.environment.Architecture == PlatformArchitecture.X86)
{
filename = "procdump64.exe";
filename = Constants.ProcdumpProcess;
}
else if (this.environment.Architecture == PlatformArchitecture.X86)
else
{
filename = "procdump.exe";
filename = this.nativeMethodsHelper.Is64Bit(this.processHelper.GetProcessHandle(processId)) ?
Constants.Procdump64Process : Constants.ProcdumpProcess;
}

var procDumpExe = Path.Combine(procdumpPath, filename);
Expand All @@ -149,4 +179,4 @@ private string GetProcDumpExecutable()
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -103,5 +103,12 @@ public interface IProcessHelper
/// </summary>
/// <param name="process">Reference to process</param>
void WaitForProcessExit(object process);

/// <summary>
/// Gets the process handle for given process Id.
/// </summary>
/// <param name="processId">process id</param>
/// <returns>Process Handle</returns>
IntPtr GetProcessHandle(int processId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

namespace Microsoft.VisualStudio.TestPlatform.PlatformAbstractions
{
using System;
using System.Diagnostics;
using System.IO;
using Microsoft.VisualStudio.TestPlatform.PlatformAbstractions.Interfaces;

Expand All @@ -13,5 +15,10 @@ public string GetCurrentProcessLocation()
{
return Path.GetDirectoryName(this.GetCurrentProcessFileName());
}

public IntPtr GetProcessHandle(int processId)
{
return Process.GetProcessById(processId).Handle;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

namespace Microsoft.VisualStudio.TestPlatform.PlatformAbstractions
{
using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using Microsoft.VisualStudio.TestPlatform.PlatformAbstractions.Interfaces;
Expand All @@ -14,5 +16,13 @@ public string GetCurrentProcessLocation()
{
return Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
}

/// <inheritdoc/>
public IntPtr GetProcessHandle(int processId)
{
// An IntPtr representing the value of the handle field.
// If the handle has been marked invalid with SetHandleAsInvalid, this method still returns the original handle value, which can be a stale value.
return Process.GetProcessById(processId).SafeHandle.DangerousGetHandle();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ namespace Microsoft.VisualStudio.TestPlatform.PlatformAbstractions
{
using System;
using System.Collections.Generic;

using Microsoft.VisualStudio.TestPlatform.PlatformAbstractions.Interfaces;

/// <summary>
Expand Down Expand Up @@ -96,5 +95,10 @@ public void WaitForProcessExit(object process)
{
throw new NotImplementedException();
}

public IntPtr GetProcessHandle(int processId)
{
throw new NotImplementedException();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace Microsoft.VisualStudio.TestPlatform.PlatformAbstractions
/// <summary>
/// Helper class to deal with process related functionality.
/// </summary>
public class ProcessHelper : IProcessHelper
public partial class ProcessHelper : IProcessHelper
{
/// <inheritdoc/>
public object LaunchProcess(
Expand Down Expand Up @@ -101,5 +101,10 @@ public void WaitForProcessExit(object process)
{
throw new NotImplementedException();
}

public IntPtr GetProcessHandle(int processId)
{
throw new NotImplementedException();
}
}
}
Loading