go my file uploader
This commit is contained in:
26
plugins/DotNetTools/CHANGELOG.txt
Normal file
26
plugins/DotNetTools/CHANGELOG.txt
Normal file
@@ -0,0 +1,26 @@
|
||||
1.6
|
||||
* Fixed .NET assembly tab performance issues
|
||||
* Added extra .NET memory counters to the .NET performance tab
|
||||
* Added "Show sizes in bytes" checkbox to the .NET performance tab
|
||||
* Added right-click menu to the .NET assembly tab
|
||||
* Removed all Win32 functions for querying .NET process performance
|
||||
|
||||
1.5
|
||||
* Rewrite of .NET Performance statistics and AppDomain enumeration
|
||||
|
||||
1.4
|
||||
* Process Hacker now displays managed stack traces for 32-bit .NET processes on 64-bit Windows
|
||||
* Fixed inaccurate stack traces when clicking Refresh
|
||||
* Added AppDomain column for threads in .NET programs
|
||||
|
||||
1.3
|
||||
* Improved .NET assembly enumeration timeout handling
|
||||
|
||||
1.2
|
||||
* Fixed inaccurate stack traces for certain .NET programs
|
||||
|
||||
1.1
|
||||
* Added managed symbol resolution for thread stacks
|
||||
|
||||
1.0
|
||||
* Initial release
|
||||
182
plugins/DotNetTools/DotNetTools.rc
Normal file
182
plugins/DotNetTools/DotNetTools.rc
Normal file
@@ -0,0 +1,182 @@
|
||||
// Microsoft Visual C++ generated resource script.
|
||||
//
|
||||
#include "resource.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 2 resource.
|
||||
//
|
||||
#include "winres.h"
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// English (Australia) resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENA)
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_AUS
|
||||
#pragma code_page(1252)
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TEXTINCLUDE
|
||||
//
|
||||
|
||||
1 TEXTINCLUDE
|
||||
BEGIN
|
||||
"resource.h\0"
|
||||
END
|
||||
|
||||
2 TEXTINCLUDE
|
||||
BEGIN
|
||||
"#include ""winres.h""\0"
|
||||
END
|
||||
|
||||
3 TEXTINCLUDE
|
||||
BEGIN
|
||||
"\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Version
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 1,6,0,0
|
||||
PRODUCTVERSION 1,6,0,0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
#else
|
||||
FILEFLAGS 0x0L
|
||||
#endif
|
||||
FILEOS 0x40004L
|
||||
FILETYPE 0x2L
|
||||
FILESUBTYPE 0x0L
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "0c0904b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "wj32"
|
||||
VALUE "FileDescription", ".NET tools plugin for Process Hacker"
|
||||
VALUE "FileVersion", "1.6"
|
||||
VALUE "InternalName", "DotNetTools"
|
||||
VALUE "LegalCopyright", "Licensed under the GNU GPL, v3."
|
||||
VALUE "OriginalFilename", "DotNetTools.dll"
|
||||
VALUE "ProductName", ".NET tools plugin for Process Hacker"
|
||||
VALUE "ProductVersion", "1.6"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0xc09, 1200
|
||||
END
|
||||
END
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Dialog
|
||||
//
|
||||
|
||||
IDD_PROCDOTNETPERF DIALOGEX 0, 0, 260, 260
|
||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||
CAPTION ".NET performance"
|
||||
FONT 8, "MS Shell Dlg", 400, 0, 0x1
|
||||
BEGIN
|
||||
CONTROL "",IDC_APPDOMAINS,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SORTASCENDING | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,7,246,59
|
||||
LTEXT "Categories:",IDC_STATIC,7,72,38,8
|
||||
COMBOBOX IDC_CATEGORIES,49,70,204,30,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
|
||||
CONTROL "",IDC_COUNTERS,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | WS_BORDER | WS_TABSTOP,7,88,246,154
|
||||
CONTROL "Show sizes in bytes",IDC_DOTNET_PERF_SHOWBYTES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,244,78,10
|
||||
END
|
||||
|
||||
IDD_PROCDOTNETASM DIALOGEX 0, 0, 260, 260
|
||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||
CAPTION ".NET assemblies"
|
||||
FONT 8, "MS Shell Dlg", 400, 0, 0x1
|
||||
BEGIN
|
||||
CONTROL ".NET assemblies",IDC_LIST,"PhTreeNew",WS_CLIPSIBLINGS | WS_CLIPCHILDREN | 0x1a,7,7,246,246,WS_EX_CLIENTEDGE
|
||||
END
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// DESIGNINFO
|
||||
//
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
GUIDELINES DESIGNINFO
|
||||
BEGIN
|
||||
IDD_PROCDOTNETPERF, DIALOG
|
||||
BEGIN
|
||||
LEFTMARGIN, 7
|
||||
RIGHTMARGIN, 253
|
||||
TOPMARGIN, 7
|
||||
BOTTOMMARGIN, 253
|
||||
END
|
||||
|
||||
IDD_PROCDOTNETASM, DIALOG
|
||||
BEGIN
|
||||
LEFTMARGIN, 7
|
||||
RIGHTMARGIN, 253
|
||||
TOPMARGIN, 7
|
||||
BOTTOMMARGIN, 253
|
||||
END
|
||||
END
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// AFX_DIALOG_LAYOUT
|
||||
//
|
||||
|
||||
IDD_PROCDOTNETASM AFX_DIALOG_LAYOUT
|
||||
BEGIN
|
||||
0
|
||||
END
|
||||
|
||||
IDD_PROCDOTNETPERF AFX_DIALOG_LAYOUT
|
||||
BEGIN
|
||||
0
|
||||
END
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Menu
|
||||
//
|
||||
|
||||
IDR_ASSEMBLY_MENU MENU
|
||||
BEGIN
|
||||
POPUP "CLR"
|
||||
BEGIN
|
||||
MENUITEM "Open &file location", ID_CLR_OPENFILELOCATION
|
||||
MENUITEM "&Copy\aCtrl+C", ID_CLR_COPY
|
||||
END
|
||||
END
|
||||
|
||||
#endif // English (Australia) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 3 resource.
|
||||
//
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
|
||||
116
plugins/DotNetTools/DotNetTools.vcxproj
Normal file
116
plugins/DotNetTools/DotNetTools.vcxproj
Normal file
@@ -0,0 +1,116 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{2B3235B0-31E1-44DA-81A1-183F40517E47}</ProjectGuid>
|
||||
<RootNamespace>DotNetTools</RootNamespace>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectName>DotNetTools</ProjectName>
|
||||
<WindowsTargetPlatformVersion>10.0.10586.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
<Import Project="..\Plugins.props" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LibraryPath>$(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86);$(NETFXKitsDir)Lib\um\x86;C:\Users\AirDog46\Downloads\processhacker-2.39-src\bin\Debug32</LibraryPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LibraryPath>$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(NETFXKitsDir)Lib\um\x64;C:\Users\AirDog46\Downloads\processhacker-2.39-src\bin\Release64</LibraryPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LibraryPath>$(VC_LibraryPath_x86);$(WindowsSDK_LibraryPath_x86);$(NETFXKitsDir)Lib\um\x86;$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(NETFXKitsDir)Lib\um\x64;C:\Users\AirDog46\Downloads\processhacker-2.39-src\bin\Release32</LibraryPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LibraryPath>$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(NETFXKitsDir)Lib\um\x64;$(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(NETFXKitsDir)Lib\um\x64;C:\Users\AirDog46\Downloads\processhacker-2.39-src\bin\Debug64</LibraryPath>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Link>
|
||||
<AdditionalDependencies>uxtheme.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Link>
|
||||
<AdditionalDependencies>uxtheme.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Link>
|
||||
<AdditionalDependencies>uxtheme.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Link>
|
||||
<AdditionalDependencies>uxtheme.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="asmpage.c" />
|
||||
<ClCompile Include="clrsup.c" />
|
||||
<ClCompile Include="counters.c" />
|
||||
<ClCompile Include="main.c" />
|
||||
<ClCompile Include="perfpage.c" />
|
||||
<ClCompile Include="stackext.c" />
|
||||
<ClCompile Include="svcext.c" />
|
||||
<ClCompile Include="treeext.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="clretw.h" />
|
||||
<ClInclude Include="clrsup.h" />
|
||||
<ClInclude Include="clr\dbgappdomain.h" />
|
||||
<ClInclude Include="clr\ipcenums.h" />
|
||||
<ClInclude Include="clr\ipcheader.h" />
|
||||
<ClInclude Include="clr\ipcshared.h" />
|
||||
<ClInclude Include="clr\perfcounterdefs.h" />
|
||||
<ClInclude Include="dn.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
<ClInclude Include="svcext.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="CHANGELOG.txt" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="DotNetTools.rc" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
</Project>
|
||||
86
plugins/DotNetTools/DotNetTools.vcxproj.filters
Normal file
86
plugins/DotNetTools/DotNetTools.vcxproj.filters
Normal file
@@ -0,0 +1,86 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\clr">
|
||||
<UniqueIdentifier>{6b9aae9c-fc27-4d95-b258-53eb88081e1b}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="main.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="perfpage.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="counters.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="asmpage.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="clrsup.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="stackext.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="treeext.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="svcext.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="dn.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="resource.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="clretw.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="clrsup.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="svcext.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="clr\dbgappdomain.h">
|
||||
<Filter>Header Files\clr</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="clr\ipcenums.h">
|
||||
<Filter>Header Files\clr</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="clr\ipcheader.h">
|
||||
<Filter>Header Files\clr</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="clr\ipcshared.h">
|
||||
<Filter>Header Files\clr</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="clr\perfcounterdefs.h">
|
||||
<Filter>Header Files\clr</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="CHANGELOG.txt" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="DotNetTools.rc">
|
||||
<Filter>Resource Files</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
1327
plugins/DotNetTools/asmpage.c
Normal file
1327
plugins/DotNetTools/asmpage.c
Normal file
File diff suppressed because it is too large
Load Diff
21
plugins/DotNetTools/clr/LICENSE.TXT
Normal file
21
plugins/DotNetTools/clr/LICENSE.TXT
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) .NET Foundation and Contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
139
plugins/DotNetTools/clr/dbgappdomain.h
Normal file
139
plugins/DotNetTools/clr/dbgappdomain.h
Normal file
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Process Hacker .NET Tools -
|
||||
* .NET Process IPC definitions
|
||||
*
|
||||
* Copyright (C) 2015-2016 dmex
|
||||
*
|
||||
* This file is part of Process Hacker.
|
||||
*
|
||||
* Process Hacker is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Process Hacker is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the current folder for more information.
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// dmex: This header has been highly modified.
|
||||
// Original: https://github.com/dotnet/coreclr/blob/master/src/debug/inc/dbgappdomain.h
|
||||
|
||||
#ifndef _DBG_APPDOMAIN_H_
|
||||
#define _DBG_APPDOMAIN_H_
|
||||
|
||||
#ifndef _WIN64
|
||||
#include <pshpack4.h>
|
||||
#endif
|
||||
typedef struct _AppDomainInfo
|
||||
{
|
||||
ULONG Id; // unique identifier
|
||||
INT NameLengthInBytes;
|
||||
PWSTR AppDomainName;
|
||||
PVOID AppDomains;
|
||||
} AppDomainInfo;
|
||||
#ifndef _WIN64
|
||||
#include <poppack.h>
|
||||
#endif
|
||||
|
||||
#include <pshpack4.h>
|
||||
typedef struct _AppDomainInfo_Wow64
|
||||
{
|
||||
ULONG Id; // unique identifier
|
||||
INT NameLengthInBytes;
|
||||
ULONG AppDomainName;
|
||||
ULONG AppDomains;
|
||||
} AppDomainInfo_Wow64;
|
||||
#include <poppack.h>
|
||||
|
||||
// AppDomain publishing server support:
|
||||
// Information about all appdomains in the process will be maintained
|
||||
// in the shared memory block for use by the debugger, etc.
|
||||
#ifndef _WIN64
|
||||
#include <pshpack4.h>
|
||||
#endif
|
||||
typedef struct _AppDomainEnumerationIPCBlock
|
||||
{
|
||||
HANDLE Mutex; // lock for serialization while manipulating AppDomain list.
|
||||
|
||||
INT TotalSlots; // Number of slots in AppDomainListElement array
|
||||
INT NumOfUsedSlots;
|
||||
INT LastFreedSlot;
|
||||
INT SizeInBytes; // Size of AppDomainInfo in bytes
|
||||
|
||||
INT ProcessNameLengthInBytes; // We can use psapi!GetModuleFileNameEx to get the module name.
|
||||
PVOID ProcessName; // This provides an alternative.
|
||||
|
||||
PVOID ListOfAppDomains;
|
||||
BOOL LockInvalid;
|
||||
} AppDomainEnumerationIPCBlock;
|
||||
#ifndef _WIN64
|
||||
#include <poppack.h>
|
||||
#endif
|
||||
|
||||
#include <pshpack4.h>
|
||||
typedef struct _AppDomainEnumerationIPCBlock_Wow64
|
||||
{
|
||||
ULONG Mutex; // lock for serialization while manipulating AppDomain list.
|
||||
|
||||
INT TotalSlots; // Number of slots in AppDomainListElement array
|
||||
INT NumOfUsedSlots;
|
||||
INT LastFreedSlot;
|
||||
INT SizeInBytes; // Size of AppDomainInfo in bytes
|
||||
|
||||
INT ProcessNameLengthInBytes; // We can use psapi!GetModuleFileNameEx to get the module name.
|
||||
ULONG ProcessName; // This provides an alternative.
|
||||
|
||||
ULONG ListOfAppDomains;
|
||||
BOOL LockInvalid;
|
||||
} AppDomainEnumerationIPCBlock_Wow64;
|
||||
#include <poppack.h>
|
||||
|
||||
|
||||
// Enforce the AppDomain IPC block binary layout.
|
||||
C_ASSERT(FIELD_OFFSET(AppDomainInfo_Wow64, Id) == 0x0);
|
||||
C_ASSERT(FIELD_OFFSET(AppDomainInfo_Wow64, NameLengthInBytes) == 0x4);
|
||||
C_ASSERT(FIELD_OFFSET(AppDomainInfo_Wow64, AppDomainName) == 0x8);
|
||||
C_ASSERT(FIELD_OFFSET(AppDomainInfo_Wow64, AppDomains) == 0xC);
|
||||
|
||||
#if defined(_WIN64)
|
||||
C_ASSERT(FIELD_OFFSET(AppDomainInfo, Id) == 0x0);
|
||||
C_ASSERT(FIELD_OFFSET(AppDomainInfo, NameLengthInBytes) == 0x4);
|
||||
C_ASSERT(FIELD_OFFSET(AppDomainInfo, AppDomainName) == 0x8);
|
||||
C_ASSERT(FIELD_OFFSET(AppDomainInfo, AppDomains) == 0x10);
|
||||
#endif
|
||||
|
||||
// Enforce the AppDomain IPC block binary layout.
|
||||
C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock_Wow64, Mutex) == 0x0);
|
||||
C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock_Wow64, TotalSlots) == 0x4);
|
||||
C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock_Wow64, NumOfUsedSlots) == 0x8);
|
||||
C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock_Wow64, LastFreedSlot) == 0xC);
|
||||
C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock_Wow64, SizeInBytes) == 0x10);
|
||||
C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock_Wow64, ProcessNameLengthInBytes) == 0x14);
|
||||
C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock_Wow64, ProcessName) == 0x18);
|
||||
C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock_Wow64, ListOfAppDomains) == 0x1C);
|
||||
C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock_Wow64, LockInvalid) == 0x20);
|
||||
|
||||
#if defined(_WIN64)
|
||||
C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock, Mutex) == 0x0);
|
||||
C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock, TotalSlots) == 0x8);
|
||||
C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock, NumOfUsedSlots) == 0xC);
|
||||
C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock, LastFreedSlot) == 0x10);
|
||||
C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock, SizeInBytes) == 0x14);
|
||||
C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock, ProcessNameLengthInBytes) == 0x18);
|
||||
// TODO: Why does Visual Studio have issues with these entries...
|
||||
//C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock, ProcessName) == 0x20);
|
||||
//C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock, ListOfAppDomains) == 0x28);
|
||||
//C_ASSERT(FIELD_OFFSET(AppDomainEnumerationIPCBlock, LockInvalid) == 0x30);
|
||||
#endif
|
||||
|
||||
#endif _DBG_APPDOMAIN_H_
|
||||
77
plugins/DotNetTools/clr/ipcenums.h
Normal file
77
plugins/DotNetTools/clr/ipcenums.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Process Hacker .NET Tools -
|
||||
* .NET Process IPC definitions
|
||||
*
|
||||
* Copyright (C) 2015-2016 dmex
|
||||
*
|
||||
* This file is part of Process Hacker.
|
||||
*
|
||||
* Process Hacker is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Process Hacker is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the current folder for more information.
|
||||
//-----------------------------------------------------------------------------
|
||||
// IPCEnums.h
|
||||
//
|
||||
// Define various enums used by IPCMan.
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// dmex: This header has been highly modified.
|
||||
// Original: https://github.com/dotnet/coreclr/blob/master/src/ipcman/ipcenums.h
|
||||
|
||||
#ifndef _IPC_ENUMS_H_
|
||||
#define _IPC_ENUMS_H_
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Each IPC client for an IPC block has one entry.
|
||||
//-----------------------------------------------------------------------------
|
||||
typedef enum _EIPCClient
|
||||
{
|
||||
eIPC_PerfCounters = 0,
|
||||
|
||||
// MAX used for arrays, insert above this.
|
||||
eIPC_MAX
|
||||
} EIPCClient;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Each IPC client for a LegacyPrivate block (debugging, perf counters, etc) has one entry.
|
||||
//-----------------------------------------------------------------------------
|
||||
typedef enum _ELegacyPrivateIPCClient
|
||||
{
|
||||
eLegacyPrivateIPC_PerfCounters = 0,
|
||||
eLegacyPrivateIPC_Obsolete_Debugger = 1,
|
||||
eLegacyPrivateIPC_AppDomain = 2,
|
||||
eLegacyPrivateIPC_Obsolete_Service = 3,
|
||||
eLegacyPrivateIPC_Obsolete_ClassDump = 4,
|
||||
eLegacyPrivateIPC_Obsolete_MiniDump = 5,
|
||||
eLegacyPrivateIPC_InstancePath = 6,
|
||||
|
||||
// MAX used for arrays, insert above this.
|
||||
eLegacyPrivateIPC_MAX
|
||||
} ELegacyPrivateIPCClient;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Each IPC client for a LegacyPublic block has one entry.
|
||||
//-----------------------------------------------------------------------------
|
||||
typedef enum _ELegacyPublicIPCClient
|
||||
{
|
||||
eLegacyPublicIPC_PerfCounters = 0,
|
||||
|
||||
// MAX used for arrays, insert above this.
|
||||
eLegacyPublicIPC_MAX
|
||||
} ELegacyPublicIPCClient;
|
||||
|
||||
#endif _IPC_ENUMS_H_
|
||||
545
plugins/DotNetTools/clr/ipcheader.h
Normal file
545
plugins/DotNetTools/clr/ipcheader.h
Normal file
@@ -0,0 +1,545 @@
|
||||
/*
|
||||
* Process Hacker .NET Tools -
|
||||
* .NET Process IPC definitions
|
||||
*
|
||||
* Copyright (C) 2015-2016 dmex
|
||||
*
|
||||
* This file is part of Process Hacker.
|
||||
*
|
||||
* Process Hacker is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Process Hacker is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the current folder for more information.
|
||||
//-----------------------------------------------------------------------------
|
||||
// IPCHeader.h
|
||||
//
|
||||
// Define the LegacyPrivate header format for IPC memory mapped files.
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// dmex: This header has been highly modified.
|
||||
// Original: https://github.com/dotnet/coreclr/blob/master/src/ipcman/ipcheader.h
|
||||
|
||||
#ifndef _IPC_HEADER_H_
|
||||
#define _IPC_HEADER_H_
|
||||
|
||||
#include "perfcounterdefs.h"
|
||||
#include "ipcenums.h"
|
||||
|
||||
// Current version of the IPC Block
|
||||
const USHORT VER_IPC_BLOCK = 4;
|
||||
// Legacy version of the IPC Block
|
||||
const USHORT VER_LEGACYPRIVATE_IPC_BLOCK = 2;
|
||||
const USHORT VER_LEGACYPUBLIC_IPC_BLOCK = 3;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Entry in the IPC Directory. Ensure binary compatibility across versions
|
||||
// if we add (or remove) entries. If we remove an block, the entry should
|
||||
// be EMPTY_ENTRY_OFFSET
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
const ULONG EMPTY_ENTRY_OFFSET = 0xFFFFFFFF;
|
||||
const ULONG EMPTY_ENTRY_SIZE = 0;
|
||||
|
||||
typedef struct IPCEntry
|
||||
{
|
||||
ULONG Offset; // offset of the IPC Block from the end of the Full IPC Header
|
||||
ULONG Size; // size (in bytes) of the block
|
||||
} IPCEntry;
|
||||
|
||||
// Newer versions of the CLR use Flags field
|
||||
const USHORT IPC_FLAG_USES_FLAGS = 0x1;
|
||||
const USHORT IPC_FLAG_INITIALIZED = 0x2;
|
||||
const USHORT IPC_FLAG_X86 = 0x4;
|
||||
|
||||
// In hindsight, we should have made the offsets be absolute, but we made them
|
||||
// relative to the end of the FullIPCHeader.
|
||||
// The problem is that as future versions added new Entries to the directory,
|
||||
// the header size grew.
|
||||
// Thus we make IPCEntry::Offset is relative to IPC_ENTRY_OFFSET_BASE, which
|
||||
// corresponds to sizeof(PrivateIPCHeader) for an v1.0 /v1.1 build.
|
||||
const ULONG IPC_ENTRY_OFFSET_BASE_X86 = 0x14;
|
||||
const ULONG IPC_ENTRY_OFFSET_BASE_X64 = 0x0;
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* The CLR opens memory mapped files to expose perfcounter values and other
|
||||
* information to other processes. Historically there have been three memory
|
||||
* mapped files: the BlockTable, the LegacyPrivateBlock, and the
|
||||
* LegacyPublicBlock.
|
||||
*
|
||||
* BlockTable - The block table was designed to work with multiple runtimes
|
||||
* running side by side in the same process (SxS in-proc). We have defined
|
||||
* semantics using interlocked operations that allow a runtime to allocate
|
||||
* a block from the block table in a thread-safe manner.
|
||||
*
|
||||
* LegacyPrivateBlock - The legacy private block was used by older versions
|
||||
* of the runtime to expose various information to the debugger. The
|
||||
* legacy private block is not compatible with in-proc SxS, and thus it
|
||||
* must be removed in the near future. Currently it is being used to expose
|
||||
* information about AppDomains to the debugger. We will need to keep the
|
||||
* code that knows how to read the legacy private block as long as we
|
||||
* continue to support .NET 3.5 SP1.
|
||||
*
|
||||
* LegacyPublicBlock - The legacy public block was used by older versions
|
||||
* of the runtime to expose perfcounter values. The legacy public block is
|
||||
* not compatible with in-proc SxS, and thus it has been removed. We will
|
||||
* need to keep the code that knows how to read the legacy public block as
|
||||
* long as we continue to support .NET 3.5 SP1.
|
||||
******************************************************************************/
|
||||
|
||||
/**************************************** BLOCK TABLE ****************************************/
|
||||
|
||||
#define IPC_BLOCK_TABLE_SIZE 65536
|
||||
#define IPC_BLOCK_SIZE 2048
|
||||
#define IPC_NUM_BLOCKS_IN_TABLE 32
|
||||
|
||||
C_ASSERT(IPC_BLOCK_TABLE_SIZE == IPC_NUM_BLOCKS_IN_TABLE * IPC_BLOCK_SIZE);
|
||||
|
||||
typedef struct _IPCHeader
|
||||
{
|
||||
// Chunk header
|
||||
volatile LONG Counter; // *** Volatile<LONG> *** value of 0 is special; means that this block has never been touched before by a writer
|
||||
ULONG RuntimeId; // value of 0 is special; means that chunk is currently free (runtime ids are always greater than 0)
|
||||
ULONG Reserved1;
|
||||
ULONG Reserved2;
|
||||
|
||||
// Standard header
|
||||
USHORT Version; // version of the IPC Block
|
||||
USHORT Flags; // flags field
|
||||
ULONG blockSize; // Size of the entire shared memory block
|
||||
USHORT BuildYear; // stamp for year built
|
||||
USHORT BuildNumber; // stamp for Month/Day built
|
||||
ULONG NumEntries; // Number of entries in the table
|
||||
|
||||
// Directory
|
||||
IPCEntry EntryTable[eIPC_MAX]; // entry describing each client's block
|
||||
} IPCHeader;
|
||||
|
||||
#define SXSPUBLIC_IPC_SIZE_NO_PADDING (sizeof(IPCHeader) + sizeof(PerfCounterIPCControlBlock))
|
||||
#define SXSPUBLIC_WOW64_IPC_SIZE_NO_PADDING (sizeof(IPCHeader) + sizeof(PerfCounterIPCControlBlock_Wow64))
|
||||
|
||||
#define SXSPUBLIC_IPC_PAD_SIZE (IPC_BLOCK_SIZE - SXSPUBLIC_IPC_SIZE_NO_PADDING)
|
||||
#define SXSPUBLIC_WOW64_IPC_PAD_SIZE (IPC_BLOCK_SIZE - SXSPUBLIC_WOW64_IPC_SIZE_NO_PADDING)
|
||||
|
||||
#ifndef _WIN64
|
||||
#include <pshpack4.h>
|
||||
#endif
|
||||
typedef struct _IPCControlBlock
|
||||
{
|
||||
// Header
|
||||
IPCHeader Header;
|
||||
|
||||
// Client blocks
|
||||
PerfCounterIPCControlBlock PerfIpcBlock;
|
||||
|
||||
// Padding
|
||||
BYTE Padding[SXSPUBLIC_IPC_PAD_SIZE];
|
||||
} IPCControlBlock;
|
||||
#ifndef _WIN64
|
||||
#include <poppack.h>
|
||||
#endif
|
||||
|
||||
#include <pshpack4.h>
|
||||
typedef struct _IPCControlBlock_Wow64
|
||||
{
|
||||
// Header
|
||||
IPCHeader Header;
|
||||
|
||||
// Client blocks
|
||||
PerfCounterIPCControlBlock_Wow64 PerfIpcBlock;
|
||||
|
||||
// Padding
|
||||
BYTE Padding[SXSPUBLIC_WOW64_IPC_PAD_SIZE];
|
||||
} IPCControlBlock_Wow64;
|
||||
#include <poppack.h>
|
||||
|
||||
C_ASSERT(sizeof(IPCControlBlock) == IPC_BLOCK_SIZE);
|
||||
C_ASSERT(sizeof(IPCControlBlock_Wow64) == IPC_BLOCK_SIZE);
|
||||
|
||||
#ifndef _WIN64
|
||||
#include <pshpack4.h>
|
||||
#endif
|
||||
typedef struct IPCControlBlockTable
|
||||
{
|
||||
IPCControlBlock Blocks[IPC_NUM_BLOCKS_IN_TABLE];
|
||||
} IPCControlBlockTable;
|
||||
#ifndef _WIN64
|
||||
#include <poppack.h>
|
||||
#endif
|
||||
|
||||
#include <pshpack4.h>
|
||||
typedef struct IPCControlBlockTable_Wow64
|
||||
{
|
||||
IPCControlBlock_Wow64 Blocks[IPC_NUM_BLOCKS_IN_TABLE];
|
||||
} IPCControlBlockTable_Wow64;
|
||||
#include <poppack.h>
|
||||
|
||||
C_ASSERT(sizeof(IPCControlBlockTable) == IPC_BLOCK_TABLE_SIZE);
|
||||
C_ASSERT(sizeof(IPCControlBlockTable_Wow64) == IPC_BLOCK_TABLE_SIZE);
|
||||
|
||||
|
||||
#ifndef _WIN64
|
||||
#include <pshpack4.h>
|
||||
#endif
|
||||
typedef struct LegacyPrivateIPCHeader
|
||||
{
|
||||
USHORT Version; // version of the IPC Block
|
||||
USHORT Flags; // flags field
|
||||
ULONG BlockSize; // Size of the entire shared memory block
|
||||
HINSTANCE hInstance; // Instance of module that created this header
|
||||
USHORT BuildYear; // stamp for year built
|
||||
USHORT BuildNumber; // stamp for Month/Day built
|
||||
ULONG NumEntries; // Number of entries in the table
|
||||
} LegacyPrivateIPCHeader;
|
||||
#ifndef _WIN64
|
||||
#include <poppack.h>
|
||||
#endif
|
||||
|
||||
#include <pshpack4.h>
|
||||
typedef struct LegacyPrivateIPCHeader_Wow64
|
||||
{
|
||||
USHORT Version; // version of the IPC Block
|
||||
USHORT Flags; // flags field
|
||||
ULONG BlockSize; // Size of the entire shared memory block
|
||||
ULONG hInstance; // Instance of module that created this header
|
||||
USHORT BuildYear; // stamp for year built
|
||||
USHORT BuildNumber; // stamp for Month/Day built
|
||||
ULONG NumEntries; // Number of entries in the table
|
||||
} LegacyPrivateIPCHeader_Wow64;
|
||||
#include <poppack.h>
|
||||
|
||||
#ifndef _WIN64
|
||||
#include <pshpack4.h>
|
||||
#endif
|
||||
typedef struct FullIPCHeaderLegacyPrivate
|
||||
{
|
||||
// Header
|
||||
LegacyPrivateIPCHeader Header;
|
||||
|
||||
// Directory
|
||||
IPCEntry EntryTable[eLegacyPrivateIPC_MAX]; // entry describing each client's block
|
||||
} FullIPCHeaderLegacyPrivate;
|
||||
#ifndef _WIN64
|
||||
#include <poppack.h>
|
||||
#endif
|
||||
|
||||
#include <pshpack4.h>
|
||||
typedef struct FullIPCHeaderLegacyPrivate_Wow64
|
||||
{
|
||||
// Header
|
||||
LegacyPrivateIPCHeader_Wow64 Header;
|
||||
|
||||
// Directory
|
||||
IPCEntry EntryTable[eLegacyPrivateIPC_MAX]; // entry describing each client's block
|
||||
} FullIPCHeaderLegacyPrivate_Wow64;
|
||||
#include <poppack.h>
|
||||
|
||||
#ifndef _WIN64
|
||||
#include <pshpack4.h>
|
||||
#endif
|
||||
typedef struct FullIPCHeaderLegacyPublic
|
||||
{
|
||||
// Header
|
||||
LegacyPrivateIPCHeader Header;
|
||||
|
||||
// Directory
|
||||
IPCEntry EntryTable[eLegacyPublicIPC_MAX]; // entry describing each client's block
|
||||
} FullIPCHeaderLegacyPublic;
|
||||
#ifndef _WIN64
|
||||
#include <poppack.h>
|
||||
#endif
|
||||
|
||||
#include <pshpack4.h>
|
||||
typedef struct FullIPCHeaderLegacyPublic_Wow64
|
||||
{
|
||||
// Header
|
||||
LegacyPrivateIPCHeader_Wow64 Header;
|
||||
|
||||
// Directory
|
||||
IPCEntry EntryTable[eLegacyPublicIPC_MAX]; // entry describing each client's block
|
||||
} FullIPCHeaderLegacyPublic_Wow64;
|
||||
#include <poppack.h>
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LegacyPrivate (per process) IPC Block for COM+ apps
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifndef _WIN64
|
||||
#include <pshpack4.h>
|
||||
#endif
|
||||
typedef struct _LegacyPrivateIPCControlBlock
|
||||
{
|
||||
FullIPCHeaderLegacyPrivate FullIPCHeader;
|
||||
|
||||
// Client blocks
|
||||
PerfCounterIPCControlBlock PerfIpcBlock; // no longer used but kept for compat
|
||||
AppDomainEnumerationIPCBlock AppDomainBlock;
|
||||
WCHAR InstancePath[MAX_PATH];
|
||||
} LegacyPrivateIPCControlBlock;
|
||||
#ifndef _WIN64
|
||||
#include <poppack.h>
|
||||
#endif
|
||||
|
||||
#include <pshpack4.h>
|
||||
typedef struct _LegacyPrivateIPCControlBlock_Wow64
|
||||
{
|
||||
FullIPCHeaderLegacyPrivate_Wow64 FullIPCHeader;
|
||||
|
||||
// Client blocks
|
||||
PerfCounterIPCControlBlock_Wow64 PerfIpcBlock; // no longer used but kept for compat
|
||||
AppDomainEnumerationIPCBlock_Wow64 AppDomainBlock;
|
||||
WCHAR InstancePath[MAX_PATH];
|
||||
} LegacyPrivateIPCControlBlock_Wow64;
|
||||
#include <poppack.h>
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LegacyPublic (per process) IPC Block for CLR apps
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifndef _WIN64
|
||||
#include <pshpack4.h>
|
||||
#endif
|
||||
typedef struct LegacyPublicIPCControlBlock
|
||||
{
|
||||
FullIPCHeaderLegacyPublic FullIPCHeaderLegacyPublic;
|
||||
|
||||
// Client blocks
|
||||
PerfCounterIPCControlBlock PerfIpcBlock;
|
||||
} LegacyPublicIPCControlBlock;
|
||||
#ifndef _WIN64
|
||||
#include <poppack.h>
|
||||
#endif
|
||||
|
||||
#include <pshpack4.h>
|
||||
typedef struct _LegacyPublicIPCControlBlock_Wow64
|
||||
{
|
||||
FullIPCHeaderLegacyPublic_Wow64 FullIPCHeaderLegacyPublic;
|
||||
|
||||
// Client blocks
|
||||
PerfCounterIPCControlBlock_Wow64 PerfIpcBlock;
|
||||
} LegacyPublicIPCControlBlock_Wow64;
|
||||
#include <poppack.h>
|
||||
|
||||
|
||||
//class IPCHeaderLockHolder
|
||||
//{
|
||||
// LONG Counter;
|
||||
// BOOL HaveLock;
|
||||
// IPCHeader & Header;
|
||||
//
|
||||
// public:
|
||||
//
|
||||
// IPCHeaderLockHolder(IPCHeader & header) : HaveLock(FALSE), Header(header) {}
|
||||
//
|
||||
// BOOL TryGetLock()
|
||||
// {
|
||||
// _ASSERTE(!HaveLock);
|
||||
// LONG oldCounter = Header.Counter;
|
||||
// if ((oldCounter & 1) != 0)
|
||||
// return FALSE;
|
||||
// Counter = oldCounter + 1;
|
||||
// if (InterlockedCompareExchange((LONG *)(&(Header.Counter)), Counter, oldCounter) != oldCounter)
|
||||
// return FALSE;
|
||||
// HaveLock = TRUE;
|
||||
//
|
||||
// return TRUE;
|
||||
// }
|
||||
//
|
||||
// BOOL TryGetLock(ULONG numRetries)
|
||||
// {
|
||||
// ULONG dwSwitchCount = 0;
|
||||
//
|
||||
// for (;;)
|
||||
// {
|
||||
// if (TryGetLock())
|
||||
// return TRUE;
|
||||
//
|
||||
// if (numRetries == 0)
|
||||
// return FALSE;
|
||||
//
|
||||
// --numRetries;
|
||||
// __SwitchToThread(0, ++dwSwitchCount);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// void FreeLock()
|
||||
// {
|
||||
// _ASSERTE(HaveLock);
|
||||
// _ASSERTE(Header.Counter == Counter);
|
||||
// ++Counter;
|
||||
// Counter = (Counter == 0) ? 2 : Counter;
|
||||
// Header.Counter = Counter;
|
||||
// HaveLock = FALSE;
|
||||
// }
|
||||
//
|
||||
// ~IPCHeaderLockHolder()
|
||||
// {
|
||||
// if (HaveLock)
|
||||
// FreeLock();
|
||||
// }
|
||||
//};
|
||||
//
|
||||
//class IPCHeaderReadHelper
|
||||
//{
|
||||
// IPCHeader CachedHeader;
|
||||
// IPCHeader * pUnreliableHeader;
|
||||
// BOOL IsOpen;
|
||||
//
|
||||
// public:
|
||||
//
|
||||
// IPCHeaderReadHelper() : pUnreliableHeader(NULL), IsOpen(FALSE) {}
|
||||
//
|
||||
// BOOL TryOpenHeader(IPCHeader * header)
|
||||
// {
|
||||
// _ASSERTE(!IsOpen);
|
||||
//
|
||||
// pUnreliableHeader = header;
|
||||
//
|
||||
// // Read the counter and the runtime ID from the header
|
||||
// CachedHeader.Counter = pUnreliableHeader->Counter;
|
||||
// if ((CachedHeader.Counter & 1) != 0)
|
||||
// return FALSE;
|
||||
// CachedHeader.RuntimeId = pUnreliableHeader->RuntimeId;
|
||||
//
|
||||
// // If runtime ID is 0, then this block is not allocated by
|
||||
// // a runtime, and thus there is no further work to do
|
||||
// if (CachedHeader.RuntimeId == 0)
|
||||
// {
|
||||
// IsOpen = TRUE;
|
||||
// return TRUE;
|
||||
// }
|
||||
//
|
||||
// // Read the rest of the values from the header
|
||||
// CachedHeader.Reserved1 = pUnreliableHeader->Reserved1;
|
||||
// CachedHeader.Reserved2 = pUnreliableHeader->Reserved2;
|
||||
// CachedHeader.Version = pUnreliableHeader->Version;
|
||||
// CachedHeader.Flags = pUnreliableHeader->Flags;
|
||||
// CachedHeader.blockSize = pUnreliableHeader->blockSize;
|
||||
// CachedHeader.BuildYear = pUnreliableHeader->BuildYear;
|
||||
// CachedHeader.BuildNumber = pUnreliableHeader->BuildNumber;
|
||||
// CachedHeader.numEntries = pUnreliableHeader->numEntries;
|
||||
//
|
||||
// // Verify that the header did not change during the read
|
||||
// LONG counter = pUnreliableHeader->Counter;
|
||||
// if (CachedHeader.Counter != counter)
|
||||
// return FALSE;
|
||||
//
|
||||
// // Since we know we got a clean read of numEntries, we
|
||||
// // should be able to assert this with confidence
|
||||
// if (CachedHeader.numEntries == 0)
|
||||
// {
|
||||
// _ASSERTE(!"numEntries from IPCBlock is zero");
|
||||
// return FALSE;
|
||||
// }
|
||||
// else if (CachedHeader.numEntries > eIPC_MAX)
|
||||
// {
|
||||
// _ASSERTE(!"numEntries from IPCBlock is too big");
|
||||
// return FALSE;
|
||||
// }
|
||||
//
|
||||
// if (CachedHeader.blockSize == 0)
|
||||
// {
|
||||
// _ASSERTE(!"blockSize from IPCBlock is zero");
|
||||
// return FALSE;
|
||||
// }
|
||||
// else if (CachedHeader.blockSize > IPC_BLOCK_SIZE)
|
||||
// {
|
||||
// _ASSERTE(!"blockSize from IPCBlock is too big");
|
||||
// return FALSE;
|
||||
// }
|
||||
//
|
||||
// // Copy the table
|
||||
// for (ULONG i = 0; i < CachedHeader.numEntries; ++i)
|
||||
// {
|
||||
// CachedHeader.EntryTable[i].Offset = pUnreliableHeader->EntryTable[i].Offset;
|
||||
// CachedHeader.EntryTable[i].Size = pUnreliableHeader->EntryTable[i].Size;
|
||||
// if (i == eIPC_PerfCounters)
|
||||
// {
|
||||
// if(!((SIZE_T)CachedHeader.EntryTable[i].Offset < IPC_BLOCK_SIZE) && ((SIZE_T)CachedHeader.EntryTable[i].Offset + CachedHeader.EntryTable[i].Size <= IPC_BLOCK_SIZE))
|
||||
// {
|
||||
// _ASSERTE(!"PerfCounter section offset + size is too large");
|
||||
// return FALSE;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // If eIPC_MAX > numEntries, then mark the left over
|
||||
// // slots in EntryTable as "empty".
|
||||
// for (ULONG i = CachedHeader.numEntries; i < eIPC_MAX; ++i)
|
||||
// {
|
||||
// CachedHeader.EntryTable[i].Offset = EMPTY_ENTRY_OFFSET;
|
||||
// CachedHeader.EntryTable[i].Size = EMPTY_ENTRY_SIZE;
|
||||
// }
|
||||
//
|
||||
// // Verify again that the header did not change during the read
|
||||
// counter = pUnreliableHeader->Counter;
|
||||
// if (CachedHeader.Counter != counter)
|
||||
// return FALSE;
|
||||
//
|
||||
// IsOpen = TRUE;
|
||||
// return TRUE;
|
||||
// }
|
||||
//
|
||||
//
|
||||
// BOOL HeaderHasChanged()
|
||||
// {
|
||||
// _ASSERTE(IsOpen);
|
||||
// LONG counter = pUnreliableHeader->Counter;
|
||||
// return (CachedHeader.Counter != counter) ? TRUE : FALSE;
|
||||
// }
|
||||
//
|
||||
// BOOL IsSentinal()
|
||||
// {
|
||||
// _ASSERTE(IsOpen);
|
||||
// return (CachedHeader.Counter == 0);
|
||||
// }
|
||||
//
|
||||
//
|
||||
// BOOL UseWow64Structs()
|
||||
// {
|
||||
// _ASSERTE(IsOpen);
|
||||
//#if !defined(_TARGET_X86_)
|
||||
// return ((CachedHeader.Flags & IPC_FLAG_X86) != 0) ? TRUE : FALSE;
|
||||
//#else
|
||||
// return FALSE;
|
||||
//#endif
|
||||
// }
|
||||
//
|
||||
// void * GetUnreliableSection(EIPCClient eClient)
|
||||
// {
|
||||
// if (!IsOpen)
|
||||
// {
|
||||
// _ASSERTE(!"IPCHeaderReadHelper is not open");
|
||||
// return NULL;
|
||||
// }
|
||||
//
|
||||
// if (eClient < 0 || eClient >= eIPC_MAX)
|
||||
// {
|
||||
// _ASSERTE(!"eClient is out of bounds");
|
||||
// return NULL;
|
||||
// }
|
||||
//
|
||||
// if (CachedHeader.EntryTable[eClient].Offset == EMPTY_ENTRY_OFFSET)
|
||||
// {
|
||||
// _ASSERTE(!"Section is empty");
|
||||
// return NULL;
|
||||
// }
|
||||
//
|
||||
// return (BYTE*)pUnreliableHeader + (SIZE_T)CachedHeader.EntryTable[eClient].Offset;
|
||||
// }
|
||||
//};
|
||||
|
||||
#endif // _IPC_HEADER_H_
|
||||
57
plugins/DotNetTools/clr/ipcshared.h
Normal file
57
plugins/DotNetTools/clr/ipcshared.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Process Hacker .NET Tools -
|
||||
* .NET Process IPC definitions
|
||||
*
|
||||
* Copyright (C) 2015-2016 dmex
|
||||
*
|
||||
* This file is part of Process Hacker.
|
||||
*
|
||||
* Process Hacker is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Process Hacker is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the current folder for more information.
|
||||
//-----------------------------------------------------------------------------
|
||||
// IPCShared.h
|
||||
//
|
||||
// Shared LegacyPrivate utility functions for IPC operations.
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// dmex: This header has been highly modified.
|
||||
// Original: https://github.com/dotnet/coreclr/blob/master/src/ipcman/ipcshared.h
|
||||
|
||||
#ifndef _IPC_SHARED_H_
|
||||
#define _IPC_SHARED_H_
|
||||
|
||||
// This is the name of the file backed session's name on the LS (debuggee)
|
||||
// Name of the LegacyPrivate (per-process) block. %lu resolved to a PID
|
||||
#define CorLegacyPrivateIPCBlock L"Cor_Private_IPCBlock_%lu"
|
||||
#define CorLegacyPrivateIPCBlockTempV4 L"Cor_Private_IPCBlock_v4_%lu"
|
||||
#define CorLegacyPublicIPCBlock L"Cor_Public_IPCBlock_%lu"
|
||||
#define CorSxSPublicIPCBlock L"Cor_SxSPublic_IPCBlock_%lu"
|
||||
#define CorSxSBoundaryDescriptor L"Cor_CLR_IPCBlock_%lu"
|
||||
#define CorSxSWriterPrivateNamespacePrefix L"Cor_CLR_WRITER"
|
||||
#define CorSxSReaderPrivateNamespacePrefix L"Cor_CLR_READER"
|
||||
#define CorSxSVistaPublicIPCBlock L"Cor_SxSPublic_IPCBlock"
|
||||
|
||||
#define CorLegacyPrivateIPCBlock_RS L"CLR_PRIVATE_RS_IPCBlock_%lu"
|
||||
#define CorLegacyPrivateIPCBlock_RSTempV4 L"CLR_PRIVATE_RS_IPCBlock_v4_%lu"
|
||||
#define CorLegacyPublicIPCBlock_RS L"CLR_PUBLIC_IPCBlock_%lu"
|
||||
#define CorSxSPublicIPCBlock_RS L"CLR_SXSPUBLIC_IPCBlock_%lu"
|
||||
|
||||
#define CorSxSPublicInstanceName L"%s_p%lu_r%lu"
|
||||
#define CorSxSPublicInstanceNameWhidbey L"%s_p%lu"
|
||||
|
||||
#endif _IPC_SHARED_H_
|
||||
333
plugins/DotNetTools/clr/perfcounterdefs.h
Normal file
333
plugins/DotNetTools/clr/perfcounterdefs.h
Normal file
@@ -0,0 +1,333 @@
|
||||
/*
|
||||
* Process Hacker .NET Tools -
|
||||
* .NET Process IPC definitions
|
||||
*
|
||||
* Copyright (C) 2015-2016 dmex
|
||||
*
|
||||
* This file is part of Process Hacker.
|
||||
*
|
||||
* Process Hacker is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Process Hacker is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the current folder for more information.
|
||||
//-----------------------------------------------------------------------------
|
||||
// PerfCounterDefs.h
|
||||
//
|
||||
// Internal Interface for CLR to use Performance counters.
|
||||
//-----------------------------------------------------------------------------
|
||||
//
|
||||
// dmex: This header has been highly modified.
|
||||
// Original: https://github.com/dotnet/coreclr/blob/master/src/inc/perfcounterdefs.h
|
||||
|
||||
#ifndef _PERF_COUNTERS_H_
|
||||
#define _PERF_COUNTERS_H_
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Name of global IPC block
|
||||
#define SHARED_PERF_IPC_NAME "SharedPerfIPCBlock"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Attributes for the IPC block
|
||||
#define PERF_ATTR_ON 0x0001 // Are we even updating any counters?
|
||||
#define PERF_ATTR_GLOBAL 0x0002 // Is this a global or private block?
|
||||
|
||||
//.............................................................................
|
||||
// Tri Counter. Support for the common trio of counters (Total, Current, and Instantaneous).
|
||||
typedef struct _TRICOUNT
|
||||
{
|
||||
ULONG Current; // Current, has +, -
|
||||
ULONG Total; // Total, has only +
|
||||
} TRICOUNT;
|
||||
|
||||
//.............................................................................
|
||||
// Interlocked Tri Counter. Support for the common trio of counters (Total, Current, and Instantaneous).
|
||||
typedef struct _TRICOUNT_IL
|
||||
{
|
||||
ULONG Current; // Current, has +, -
|
||||
ULONG Total; // Total, has only +
|
||||
} TRICOUNT_IL;
|
||||
|
||||
|
||||
//.............................................................................
|
||||
// Dual Counter. Support for the (Total and Instantaneous (rate)). Helpful in cases
|
||||
// where the current value is always same as the total value. ie. the counter is never
|
||||
// decremented.
|
||||
//.............................................................................
|
||||
typedef struct _DUALCOUNT
|
||||
{
|
||||
ULONG Total;
|
||||
} DUALCOUNT;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Format for the Perf Counter IPC Block
|
||||
// IPC block is broken up into sections. This marks it easier to marshall
|
||||
// into different perfmon objects
|
||||
//
|
||||
//.............................................................................
|
||||
// Naming convention (by prefix):
|
||||
// c - Raw count of something.
|
||||
// cb- count of bytes
|
||||
// time - time value.
|
||||
// depth - stack depth
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#define MAX_TRACKED_GENS 3 // number of generations we track
|
||||
|
||||
|
||||
#ifndef _WIN64
|
||||
#include <pshpack4.h>
|
||||
#endif
|
||||
typedef struct _Perf_GC
|
||||
{
|
||||
size_t cGenCollections[MAX_TRACKED_GENS]; // count of collects per gen
|
||||
size_t cbPromotedMem[MAX_TRACKED_GENS - 1]; // count of promoted memory
|
||||
size_t cbPromotedFinalizationMem; // count of memory promoted due to finalization
|
||||
size_t cProcessID; // process ID
|
||||
size_t cGenHeapSize[MAX_TRACKED_GENS]; // size of heaps per gen
|
||||
size_t cTotalCommittedBytes; // total number of committed bytes.
|
||||
size_t cTotalReservedBytes; // bytes reserved via VirtualAlloc
|
||||
size_t cLrgObjSize; // size of Large Object Heap
|
||||
size_t cSurviveFinalize; // count of instances surviving from finalizing
|
||||
size_t cHandles; // count of GC handles
|
||||
size_t cbAlloc; // bytes allocated
|
||||
size_t cbLargeAlloc; // bytes allocated for Large Objects
|
||||
size_t cInducedGCs; // number of explicit GCs
|
||||
ULONG timeInGC; // Time in GC
|
||||
ULONG timeInGCBase; // must follow time in GC counter
|
||||
size_t cPinnedObj; // # of Pinned Objects
|
||||
size_t cSinkBlocks; // # of sink blocks
|
||||
} Perf_GC;
|
||||
#ifndef _WIN64
|
||||
#include <poppack.h>
|
||||
#endif
|
||||
|
||||
// Perf_GC_Wow64 mimics in a 64 bit process, the layout of Perf_GC in a 32 bit process
|
||||
// It does this by replacing all size_t by ULONG
|
||||
#include <pshpack4.h>
|
||||
typedef struct _Perf_GC_Wow64
|
||||
{
|
||||
ULONG cGenCollections[MAX_TRACKED_GENS]; // count of collects per gen
|
||||
ULONG cbPromotedMem[MAX_TRACKED_GENS - 1]; // count of promoted memory
|
||||
ULONG cbPromotedFinalizationMem; // count of memory promoted due to finalization
|
||||
ULONG cProcessID; // process ID
|
||||
ULONG cGenHeapSize[MAX_TRACKED_GENS]; // size of heaps per gen
|
||||
ULONG cTotalCommittedBytes; // total number of committed bytes.
|
||||
ULONG cTotalReservedBytes; // bytes reserved via VirtualAlloc
|
||||
ULONG cLrgObjSize; // size of Large Object Heap
|
||||
ULONG cSurviveFinalize; // count of instances surviving from finalizing
|
||||
ULONG cHandles; // count of GC handles
|
||||
ULONG cbAlloc; // bytes allocated
|
||||
ULONG cbLargeAlloc; // bytes allocated for Large Objects
|
||||
ULONG cInducedGCs; // number of explicit GCs
|
||||
ULONG timeInGC; // Time in GC
|
||||
ULONG timeInGCBase; // must follow time in GC counter
|
||||
ULONG cPinnedObj; // # of Pinned Objects
|
||||
ULONG cSinkBlocks; // # of sink blocks
|
||||
} Perf_GC_Wow64;
|
||||
#include <poppack.h>
|
||||
|
||||
|
||||
|
||||
#ifndef _WIN64
|
||||
#include <pshpack4.h>
|
||||
#endif
|
||||
typedef struct Perf_Loading
|
||||
{
|
||||
TRICOUNT cClassesLoaded;
|
||||
TRICOUNT_IL cAppDomains; // Current # of AppDomains
|
||||
TRICOUNT cAssemblies; // Current # of Assemblies
|
||||
UNALIGNED LONGLONG timeLoading; // % time loading
|
||||
ULONG cAsmSearchLen; // Avg search length for assemblies
|
||||
DUALCOUNT cLoadFailures; // Classes Failed to load
|
||||
size_t cbLoaderHeapSize; // Total size of heap used by the loader
|
||||
DUALCOUNT cAppDomainsUnloaded; // Rate at which app domains are unloaded
|
||||
} Perf_Loading;
|
||||
#ifndef _WIN64
|
||||
#include <poppack.h>
|
||||
#endif
|
||||
|
||||
#include <pshpack4.h>
|
||||
typedef struct Perf_Loading_Wow64
|
||||
{
|
||||
TRICOUNT cClassesLoaded;
|
||||
TRICOUNT_IL cAppDomains; // Current # of AppDomains
|
||||
TRICOUNT cAssemblies; // Current # of Assemblies
|
||||
UNALIGNED LONGLONG timeLoading; // % time loading
|
||||
ULONG cAsmSearchLen; // Avg search length for assemblies
|
||||
DUALCOUNT cLoadFailures; // Classes Failed to load
|
||||
ULONG cbLoaderHeapSize; // Total size of heap used by the loader
|
||||
DUALCOUNT cAppDomainsUnloaded; // Rate at which app domains are unloaded
|
||||
} Perf_Loading_Wow64;
|
||||
#include <poppack.h>
|
||||
|
||||
|
||||
#ifndef _WIN64
|
||||
#include <pshpack4.h>
|
||||
#endif
|
||||
typedef struct Perf_Jit
|
||||
{
|
||||
ULONG cMethodsJitted; // number of methods jitted
|
||||
TRICOUNT cbILJitted; // IL jitted stats
|
||||
//DUALCOUNT cbPitched; // Total bytes pitched
|
||||
ULONG cJitFailures; // # of standard Jit failures
|
||||
ULONG timeInJit; // Time in JIT since last sample
|
||||
ULONG timeInJitBase; // Time in JIT base counter
|
||||
} Perf_Jit;
|
||||
#ifndef _WIN64
|
||||
#include <poppack.h>
|
||||
#endif
|
||||
|
||||
#ifndef _WIN64
|
||||
#include <pshpack4.h>
|
||||
#endif
|
||||
typedef struct Perf_Excep
|
||||
{
|
||||
DUALCOUNT cThrown; // Number of Exceptions thrown
|
||||
ULONG cFiltersExecuted; // Number of Filters executed
|
||||
ULONG cFinallysExecuted; // Number of Finallys executed
|
||||
ULONG cThrowToCatchStackDepth; // Delta from throw to catch site on stack
|
||||
} Perf_Excep;
|
||||
#ifndef _WIN64
|
||||
#include <poppack.h>
|
||||
#endif
|
||||
|
||||
#ifndef _WIN64
|
||||
#include <pshpack4.h>
|
||||
#endif
|
||||
typedef struct Perf_Interop
|
||||
{
|
||||
ULONG cCCW; // Number of CCWs
|
||||
ULONG cStubs; // Number of stubs
|
||||
ULONG cMarshalling; // # of time marshalling args and return values.
|
||||
ULONG cTLBImports; // Number of tlbs we import
|
||||
ULONG cTLBExports; // Number of tlbs we export
|
||||
} Perf_Interop;
|
||||
#ifndef _WIN64
|
||||
#include <poppack.h>
|
||||
#endif
|
||||
|
||||
#ifndef _WIN64
|
||||
#include <pshpack4.h>
|
||||
#endif
|
||||
typedef struct Perf_LocksAndThreads
|
||||
{
|
||||
// Locks
|
||||
DUALCOUNT cContention; // # of times in AwareLock::EnterEpilogue()
|
||||
TRICOUNT cQueueLength; // Lenght of queue
|
||||
// Threads
|
||||
ULONG cCurrentThreadsLogical; // Number (created - destroyed) of logical threads
|
||||
ULONG cCurrentThreadsPhysical; // Number (created - destroyed) of OS threads
|
||||
TRICOUNT cRecognizedThreads; // # of Threads execute in runtime's control
|
||||
} Perf_LocksAndThreads;
|
||||
#ifndef _WIN64
|
||||
#include <poppack.h>
|
||||
#endif
|
||||
|
||||
|
||||
// IMPORTANT!!!!!!!: The first two fields in the struct have to be together
|
||||
// and be the first two fields in the struct. The managed code in ChannelServices.cs
|
||||
// depends on this.
|
||||
#ifndef _WIN64
|
||||
#include <pshpack4.h>
|
||||
#endif
|
||||
typedef struct Perf_Contexts
|
||||
{
|
||||
// Contexts & Remoting
|
||||
DUALCOUNT cRemoteCalls; // # of remote calls
|
||||
ULONG cChannels; // Number of current channels
|
||||
ULONG cProxies; // Number of context proxies.
|
||||
ULONG cClasses; // # of Context-bound classes
|
||||
ULONG cObjAlloc; // # of context bound objects allocated
|
||||
ULONG cContexts; // The current number of contexts.
|
||||
} Perf_Contexts;
|
||||
#ifndef _WIN64
|
||||
#include <poppack.h>
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef _WIN64
|
||||
#include <pshpack4.h>
|
||||
#endif
|
||||
typedef struct Perf_Security
|
||||
{
|
||||
ULONG cTotalRTChecks; // Total runtime checks
|
||||
UNALIGNED LONGLONG timeAuthorize; // % time authenticating
|
||||
ULONG cLinkChecks; // link time checks
|
||||
ULONG timeRTchecks; // % time in Runtime checks
|
||||
ULONG timeRTchecksBase; // % time in Runtime checks base counter
|
||||
ULONG stackWalkDepth; // depth of stack for security checks
|
||||
} Perf_Security;
|
||||
#ifndef _WIN64
|
||||
#include <poppack.h>
|
||||
#endif
|
||||
|
||||
#include <pshpack4.h>
|
||||
typedef struct Perf_Security_Wow64
|
||||
{
|
||||
ULONG cTotalRTChecks; // Total runtime checks
|
||||
UNALIGNED LONGLONG timeAuthorize; // % time authenticating
|
||||
ULONG cLinkChecks; // link time checks
|
||||
ULONG timeRTchecks; // % time in Runtime checks
|
||||
ULONG timeRTchecksBase; // % time in Runtime checks base counter
|
||||
ULONG stackWalkDepth; // depth of stack for security checks
|
||||
} Perf_Security_Wow64;
|
||||
#include <poppack.h>
|
||||
|
||||
|
||||
#ifndef _WIN64
|
||||
#include <pshpack4.h>
|
||||
#endif
|
||||
typedef struct _PerfCounterIPCControlBlock
|
||||
{
|
||||
// Versioning info
|
||||
USHORT Bytes; // size of this entire block
|
||||
USHORT Attributes; // attributes for this block
|
||||
|
||||
// Counter Sections
|
||||
Perf_GC GC;
|
||||
Perf_Contexts Context;
|
||||
Perf_Interop Interop;
|
||||
Perf_Loading Loading;
|
||||
Perf_Excep Excep;
|
||||
Perf_LocksAndThreads LocksAndThreads;
|
||||
Perf_Jit Jit;
|
||||
Perf_Security Security;
|
||||
} PerfCounterIPCControlBlock;
|
||||
#ifndef _WIN64
|
||||
#include <poppack.h>
|
||||
#endif
|
||||
|
||||
#include <pshpack4.h>
|
||||
typedef struct _PerfCounterIPCControlBlock_Wow64
|
||||
{
|
||||
// Versioning info
|
||||
USHORT Bytes; // size of this entire block
|
||||
USHORT Attributes; // attributes for this block
|
||||
|
||||
// Counter Sections
|
||||
Perf_GC_Wow64 GC;
|
||||
Perf_Contexts Context;
|
||||
Perf_Interop Interop;
|
||||
Perf_Loading_Wow64 Loading;
|
||||
Perf_Excep Excep;
|
||||
Perf_LocksAndThreads LocksAndThreads;
|
||||
Perf_Jit Jit;
|
||||
Perf_Security_Wow64 Security;
|
||||
} PerfCounterIPCControlBlock_Wow64;
|
||||
#include <poppack.h>
|
||||
|
||||
|
||||
#endif _PERF_COUNTERS_H_
|
||||
146
plugins/DotNetTools/clretw.h
Normal file
146
plugins/DotNetTools/clretw.h
Normal file
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* Process Hacker .NET Tools
|
||||
*
|
||||
* Copyright (C) 2011-2015 wj32
|
||||
*
|
||||
* This file is part of Process Hacker.
|
||||
*
|
||||
* Process Hacker is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Process Hacker is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CLRETW_H
|
||||
#define CLRETW_H
|
||||
|
||||
// Keywords
|
||||
|
||||
#define CLR_LOADER_KEYWORD 0x8
|
||||
#define CLR_STARTENUMERATION_KEYWORD 0x40
|
||||
|
||||
// Event IDs
|
||||
|
||||
#define DCStartComplete_V1 145
|
||||
#define ModuleDCStart_V1 153
|
||||
#define AssemblyDCStart_V1 155
|
||||
#define AppDomainDCStart_V1 157
|
||||
#define RuntimeInformationDCStart 187
|
||||
|
||||
// Opcodes
|
||||
|
||||
#define CLR_METHODDC_DCSTARTCOMPLETE_OPCODE 14
|
||||
#define CLR_MODULEDCSTART_OPCODE 35
|
||||
|
||||
// Bit maps
|
||||
|
||||
// AppDomainFlags
|
||||
#define AppDomainFlags_Default 0x1
|
||||
#define AppDomainFlags_Executable 0x2
|
||||
#define AppDomainFlags_Shared 0x4
|
||||
|
||||
// AssemblyFlags
|
||||
#define AssemblyFlags_DomainNeutral 0x1
|
||||
#define AssemblyFlags_Dynamic 0x2
|
||||
#define AssemblyFlags_Native 0x4
|
||||
#define AssemblyFlags_Collectible 0x8
|
||||
|
||||
// ModuleFlags
|
||||
#define ModuleFlags_DomainNeutral 0x1
|
||||
#define ModuleFlags_Native 0x2
|
||||
#define ModuleFlags_Dynamic 0x4
|
||||
#define ModuleFlags_Manifest 0x8
|
||||
|
||||
// StartupMode
|
||||
#define StartupMode_ManagedExe 0x1
|
||||
#define StartupMode_HostedCLR 0x2
|
||||
#define StartupMode_IjwDll 0x4
|
||||
#define StartupMode_ComActivated 0x8
|
||||
#define StartupMode_Other 0x10
|
||||
|
||||
// StartupFlags
|
||||
#define StartupFlags_CONCURRENT_GC 0x1
|
||||
#define StartupFlags_LOADER_OPTIMIZATION_SINGLE_DOMAIN 0x2
|
||||
#define StartupFlags_LOADER_OPTIMIZATION_MULTI_DOMAIN 0x4
|
||||
#define StartupFlags_LOADER_SAFEMODE 0x10
|
||||
#define StartupFlags_LOADER_SETPREFERENCE 0x100
|
||||
#define StartupFlags_SERVER_GC 0x1000
|
||||
#define StartupFlags_HOARD_GC_VM 0x2000
|
||||
#define StartupFlags_SINGLE_VERSION_HOSTING_INTERFACE 0x4000
|
||||
#define StartupFlags_LEGACY_IMPERSONATION 0x10000
|
||||
#define StartupFlags_DISABLE_COMMITTHREADSTACK 0x20000
|
||||
#define StartupFlags_ALWAYSFLOW_IMPERSONATION 0x40000
|
||||
#define StartupFlags_TRIM_GC_COMMIT 0x80000
|
||||
#define StartupFlags_ETW 0x100000
|
||||
#define StartupFlags_SERVER_BUILD 0x200000
|
||||
#define StartupFlags_ARM 0x400000
|
||||
|
||||
// Templates
|
||||
|
||||
#include <pshpack1.h>
|
||||
|
||||
typedef struct _DCStartEnd
|
||||
{
|
||||
USHORT ClrInstanceID;
|
||||
} DCStartEnd, *PDCStartEnd;
|
||||
|
||||
typedef struct _ModuleLoadUnloadRundown_V1
|
||||
{
|
||||
ULONG64 ModuleID;
|
||||
ULONG64 AssemblyID;
|
||||
ULONG ModuleFlags; // ModuleFlags
|
||||
ULONG Reserved1;
|
||||
WCHAR ModuleILPath[1];
|
||||
// WCHAR ModuleNativePath[1];
|
||||
// USHORT ClrInstanceID;
|
||||
} ModuleLoadUnloadRundown_V1, *PModuleLoadUnloadRundown_V1;
|
||||
|
||||
typedef struct _AssemblyLoadUnloadRundown_V1
|
||||
{
|
||||
ULONG64 AssemblyID;
|
||||
ULONG64 AppDomainID;
|
||||
ULONG64 BindingID;
|
||||
ULONG AssemblyFlags; // AssemblyFlags
|
||||
WCHAR FullyQualifiedAssemblyName[1];
|
||||
// USHORT ClrInstanceID;
|
||||
} AssemblyLoadUnloadRundown_V1, *PAssemblyLoadUnloadRundown_V1;
|
||||
|
||||
typedef struct _AppDomainLoadUnloadRundown_V1
|
||||
{
|
||||
ULONG64 AppDomainID;
|
||||
ULONG AppDomainFlags; // AppDomainFlags
|
||||
WCHAR AppDomainName[1];
|
||||
// ULONG AppDomainIndex;
|
||||
// USHORT ClrInstanceID;
|
||||
} AppDomainLoadUnloadRundown_V1, *PAppDomainLoadUnloadRundown_V1;
|
||||
|
||||
typedef struct _RuntimeInformationRundown
|
||||
{
|
||||
USHORT ClrInstanceID;
|
||||
USHORT Sku;
|
||||
USHORT BclMajorVersion;
|
||||
USHORT BclMinorVersion;
|
||||
USHORT BclBuildNumber;
|
||||
USHORT BclQfeNumber;
|
||||
USHORT VMMajorVersion;
|
||||
USHORT VMMinorVersion;
|
||||
USHORT VMBuildNumber;
|
||||
USHORT VMQfeNumber;
|
||||
ULONG StartupFlags; // StartupFlags
|
||||
UCHAR StartupMode; // StartupMode
|
||||
WCHAR CommandLine[1];
|
||||
// GUID ComObjectGuid;
|
||||
// WCHAR RuntimeDllPath[1];
|
||||
} RuntimeInformationRundown, *PRuntimeInformationRundown;
|
||||
|
||||
#include <poppack.h>
|
||||
|
||||
#endif
|
||||
575
plugins/DotNetTools/clrsup.c
Normal file
575
plugins/DotNetTools/clrsup.c
Normal file
@@ -0,0 +1,575 @@
|
||||
/*
|
||||
* Process Hacker .NET Tools -
|
||||
* CLR data access functions
|
||||
*
|
||||
* Copyright (C) 2011-2015 wj32
|
||||
*
|
||||
* This file is part of Process Hacker.
|
||||
*
|
||||
* Process Hacker is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Process Hacker is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "dn.h"
|
||||
#include "clrsup.h"
|
||||
|
||||
static GUID IID_ICLRDataTarget_I = { 0x3e11ccee, 0xd08b, 0x43e5, { 0xaf, 0x01, 0x32, 0x71, 0x7a, 0x64, 0xda, 0x03 } };
|
||||
static GUID IID_IXCLRDataProcess = { 0x5c552ab6, 0xfc09, 0x4cb3, { 0x8e, 0x36, 0x22, 0xfa, 0x03, 0xc7, 0x98, 0xb7 } };
|
||||
|
||||
static ICLRDataTargetVtbl DnCLRDataTarget_VTable =
|
||||
{
|
||||
DnCLRDataTarget_QueryInterface,
|
||||
DnCLRDataTarget_AddRef,
|
||||
DnCLRDataTarget_Release,
|
||||
DnCLRDataTarget_GetMachineType,
|
||||
DnCLRDataTarget_GetPointerSize,
|
||||
DnCLRDataTarget_GetImageBase,
|
||||
DnCLRDataTarget_ReadVirtual,
|
||||
DnCLRDataTarget_WriteVirtual,
|
||||
DnCLRDataTarget_GetTLSValue,
|
||||
DnCLRDataTarget_SetTLSValue,
|
||||
DnCLRDataTarget_GetCurrentThreadID,
|
||||
DnCLRDataTarget_GetThreadContext,
|
||||
DnCLRDataTarget_SetThreadContext,
|
||||
DnCLRDataTarget_Request
|
||||
};
|
||||
|
||||
PCLR_PROCESS_SUPPORT CreateClrProcessSupport(
|
||||
_In_ HANDLE ProcessId
|
||||
)
|
||||
{
|
||||
PCLR_PROCESS_SUPPORT support;
|
||||
ICLRDataTarget *dataTarget;
|
||||
IXCLRDataProcess *dataProcess;
|
||||
|
||||
dataTarget = DnCLRDataTarget_Create(ProcessId);
|
||||
|
||||
if (!dataTarget)
|
||||
return NULL;
|
||||
|
||||
dataProcess = NULL;
|
||||
CreateXCLRDataProcess(ProcessId, dataTarget, &dataProcess);
|
||||
ICLRDataTarget_Release(dataTarget);
|
||||
|
||||
if (!dataProcess)
|
||||
return NULL;
|
||||
|
||||
support = PhAllocate(sizeof(CLR_PROCESS_SUPPORT));
|
||||
support->DataProcess = dataProcess;
|
||||
|
||||
return support;
|
||||
}
|
||||
|
||||
VOID FreeClrProcessSupport(
|
||||
_In_ PCLR_PROCESS_SUPPORT Support
|
||||
)
|
||||
{
|
||||
IXCLRDataProcess_Release(Support->DataProcess);
|
||||
PhFree(Support);
|
||||
}
|
||||
|
||||
PPH_STRING GetRuntimeNameByAddressClrProcess(
|
||||
_In_ PCLR_PROCESS_SUPPORT Support,
|
||||
_In_ ULONG64 Address,
|
||||
_Out_opt_ PULONG64 Displacement
|
||||
)
|
||||
{
|
||||
PPH_STRING buffer;
|
||||
ULONG bufferLength;
|
||||
ULONG returnLength;
|
||||
ULONG64 displacement;
|
||||
|
||||
bufferLength = 33;
|
||||
buffer = PhCreateStringEx(NULL, (bufferLength - 1) * 2);
|
||||
|
||||
returnLength = 0;
|
||||
|
||||
if (!SUCCEEDED(IXCLRDataProcess_GetRuntimeNameByAddress(
|
||||
Support->DataProcess,
|
||||
Address,
|
||||
0,
|
||||
bufferLength,
|
||||
&returnLength,
|
||||
buffer->Buffer,
|
||||
&displacement
|
||||
)))
|
||||
{
|
||||
PhDereferenceObject(buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Try again if our buffer was too small.
|
||||
if (returnLength > bufferLength)
|
||||
{
|
||||
PhDereferenceObject(buffer);
|
||||
bufferLength = returnLength;
|
||||
buffer = PhCreateStringEx(NULL, (bufferLength - 1) * 2);
|
||||
|
||||
if (!SUCCEEDED(IXCLRDataProcess_GetRuntimeNameByAddress(
|
||||
Support->DataProcess,
|
||||
Address,
|
||||
0,
|
||||
bufferLength,
|
||||
&returnLength,
|
||||
buffer->Buffer,
|
||||
&displacement
|
||||
)))
|
||||
{
|
||||
PhDereferenceObject(buffer);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (Displacement)
|
||||
*Displacement = displacement;
|
||||
|
||||
buffer->Length = (returnLength - 1) * 2;
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
PPH_STRING GetNameXClrDataAppDomain(
|
||||
_In_ PVOID AppDomain
|
||||
)
|
||||
{
|
||||
IXCLRDataAppDomain *appDomain;
|
||||
PPH_STRING buffer;
|
||||
ULONG bufferLength;
|
||||
ULONG returnLength;
|
||||
|
||||
appDomain = AppDomain;
|
||||
|
||||
bufferLength = 33;
|
||||
buffer = PhCreateStringEx(NULL, (bufferLength - 1) * 2);
|
||||
|
||||
returnLength = 0;
|
||||
|
||||
if (!SUCCEEDED(IXCLRDataAppDomain_GetName(appDomain, bufferLength, &returnLength, buffer->Buffer)))
|
||||
{
|
||||
PhDereferenceObject(buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Try again if our buffer was too small.
|
||||
if (returnLength > bufferLength)
|
||||
{
|
||||
PhDereferenceObject(buffer);
|
||||
bufferLength = returnLength;
|
||||
buffer = PhCreateStringEx(NULL, (bufferLength - 1) * 2);
|
||||
|
||||
if (!SUCCEEDED(IXCLRDataAppDomain_GetName(appDomain, bufferLength, &returnLength, buffer->Buffer)))
|
||||
{
|
||||
PhDereferenceObject(buffer);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
buffer->Length = (returnLength - 1) * 2;
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
PVOID LoadMscordacwks(
|
||||
_In_ BOOLEAN IsClrV4
|
||||
)
|
||||
{
|
||||
PVOID dllBase;
|
||||
PH_STRINGREF systemRootString;
|
||||
PH_STRINGREF mscordacwksPathString;
|
||||
PPH_STRING mscordacwksFileName;
|
||||
|
||||
LoadLibrary(L"mscoree.dll");
|
||||
|
||||
PhGetSystemRoot(&systemRootString);
|
||||
|
||||
if (IsClrV4)
|
||||
{
|
||||
#ifdef _WIN64
|
||||
PhInitializeStringRef(&mscordacwksPathString, L"\\Microsoft.NET\\Framework64\\v4.0.30319\\mscordacwks.dll");
|
||||
#else
|
||||
PhInitializeStringRef(&mscordacwksPathString, L"\\Microsoft.NET\\Framework\\v4.0.30319\\mscordacwks.dll");
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef _WIN64
|
||||
PhInitializeStringRef(&mscordacwksPathString, L"\\Microsoft.NET\\Framework64\\v2.0.50727\\mscordacwks.dll");
|
||||
#else
|
||||
PhInitializeStringRef(&mscordacwksPathString, L"\\Microsoft.NET\\Framework\\v2.0.50727\\mscordacwks.dll");
|
||||
#endif
|
||||
}
|
||||
|
||||
mscordacwksFileName = PhConcatStringRef2(&systemRootString, &mscordacwksPathString);
|
||||
dllBase = LoadLibrary(mscordacwksFileName->Buffer);
|
||||
PhDereferenceObject(mscordacwksFileName);
|
||||
|
||||
return dllBase;
|
||||
}
|
||||
|
||||
HRESULT CreateXCLRDataProcess(
|
||||
_In_ HANDLE ProcessId,
|
||||
_In_ ICLRDataTarget *Target,
|
||||
_Out_ struct IXCLRDataProcess **DataProcess
|
||||
)
|
||||
{
|
||||
ULONG flags;
|
||||
BOOLEAN clrV4;
|
||||
HMODULE dllBase;
|
||||
HRESULT (__stdcall *clrDataCreateInstance)(REFIID, ICLRDataTarget *, void **);
|
||||
|
||||
clrV4 = FALSE;
|
||||
|
||||
if (NT_SUCCESS(PhGetProcessIsDotNetEx(ProcessId, NULL, 0, NULL, &flags)))
|
||||
{
|
||||
if (flags & PH_CLR_VERSION_4_ABOVE)
|
||||
clrV4 = TRUE;
|
||||
}
|
||||
|
||||
// Load the correct version of mscordacwks.dll.
|
||||
|
||||
if (clrV4)
|
||||
{
|
||||
static PH_INITONCE initOnce = PH_INITONCE_INIT;
|
||||
static HMODULE mscordacwksDllBase;
|
||||
|
||||
if (PhBeginInitOnce(&initOnce))
|
||||
{
|
||||
mscordacwksDllBase = LoadMscordacwks(TRUE);
|
||||
PhEndInitOnce(&initOnce);
|
||||
}
|
||||
|
||||
dllBase = mscordacwksDllBase;
|
||||
}
|
||||
else
|
||||
{
|
||||
static PH_INITONCE initOnce = PH_INITONCE_INIT;
|
||||
static HMODULE mscordacwksDllBase;
|
||||
|
||||
if (PhBeginInitOnce(&initOnce))
|
||||
{
|
||||
mscordacwksDllBase = LoadMscordacwks(FALSE);
|
||||
PhEndInitOnce(&initOnce);
|
||||
}
|
||||
|
||||
dllBase = mscordacwksDllBase;
|
||||
}
|
||||
|
||||
if (!dllBase)
|
||||
return E_FAIL;
|
||||
|
||||
clrDataCreateInstance = PhGetProcedureAddress(dllBase, "CLRDataCreateInstance", 0);
|
||||
|
||||
if (!clrDataCreateInstance)
|
||||
return E_FAIL;
|
||||
|
||||
return clrDataCreateInstance(&IID_IXCLRDataProcess, Target, DataProcess);
|
||||
}
|
||||
|
||||
ICLRDataTarget *DnCLRDataTarget_Create(
|
||||
_In_ HANDLE ProcessId
|
||||
)
|
||||
{
|
||||
DnCLRDataTarget *dataTarget;
|
||||
HANDLE processHandle;
|
||||
BOOLEAN isWow64;
|
||||
|
||||
if (!NT_SUCCESS(PhOpenProcess(&processHandle, ProcessQueryAccess | PROCESS_VM_READ, ProcessId)))
|
||||
return NULL;
|
||||
|
||||
#ifdef _WIN64
|
||||
if (!NT_SUCCESS(PhGetProcessIsWow64(processHandle, &isWow64)))
|
||||
{
|
||||
NtClose(processHandle);
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
isWow64 = FALSE;
|
||||
#endif
|
||||
|
||||
dataTarget = PhAllocate(sizeof(DnCLRDataTarget));
|
||||
dataTarget->VTable = &DnCLRDataTarget_VTable;
|
||||
dataTarget->RefCount = 1;
|
||||
|
||||
dataTarget->ProcessId = ProcessId;
|
||||
dataTarget->ProcessHandle = processHandle;
|
||||
dataTarget->IsWow64 = isWow64;
|
||||
|
||||
return (ICLRDataTarget *)dataTarget;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_QueryInterface(
|
||||
_In_ ICLRDataTarget *This,
|
||||
_In_ REFIID Riid,
|
||||
_Out_ PVOID *Object
|
||||
)
|
||||
{
|
||||
if (
|
||||
IsEqualIID(Riid, &IID_IUnknown) ||
|
||||
IsEqualIID(Riid, &IID_ICLRDataTarget_I)
|
||||
)
|
||||
{
|
||||
DnCLRDataTarget_AddRef(This);
|
||||
*Object = This;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
*Object = NULL;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
ULONG STDMETHODCALLTYPE DnCLRDataTarget_AddRef(
|
||||
_In_ ICLRDataTarget *This
|
||||
)
|
||||
{
|
||||
DnCLRDataTarget *this = (DnCLRDataTarget *)This;
|
||||
|
||||
this->RefCount++;
|
||||
|
||||
return this->RefCount;
|
||||
}
|
||||
|
||||
ULONG STDMETHODCALLTYPE DnCLRDataTarget_Release(
|
||||
_In_ ICLRDataTarget *This
|
||||
)
|
||||
{
|
||||
DnCLRDataTarget *this = (DnCLRDataTarget *)This;
|
||||
|
||||
this->RefCount--;
|
||||
|
||||
if (this->RefCount == 0)
|
||||
{
|
||||
NtClose(this->ProcessHandle);
|
||||
|
||||
PhFree(this);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return this->RefCount;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_GetMachineType(
|
||||
_In_ ICLRDataTarget *This,
|
||||
_Out_ ULONG32 *machineType
|
||||
)
|
||||
{
|
||||
DnCLRDataTarget *this = (DnCLRDataTarget *)This;
|
||||
|
||||
#ifdef _WIN64
|
||||
if (!this->IsWow64)
|
||||
*machineType = IMAGE_FILE_MACHINE_AMD64;
|
||||
else
|
||||
*machineType = IMAGE_FILE_MACHINE_I386;
|
||||
#else
|
||||
*machineType = IMAGE_FILE_MACHINE_I386;
|
||||
#endif
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_GetPointerSize(
|
||||
_In_ ICLRDataTarget *This,
|
||||
_Out_ ULONG32 *pointerSize
|
||||
)
|
||||
{
|
||||
DnCLRDataTarget *this = (DnCLRDataTarget *)This;
|
||||
|
||||
#ifdef _WIN64
|
||||
if (!this->IsWow64)
|
||||
#endif
|
||||
*pointerSize = sizeof(PVOID);
|
||||
#ifdef _WIN64
|
||||
else
|
||||
*pointerSize = sizeof(ULONG);
|
||||
#endif
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
BOOLEAN NTAPI PhpGetImageBaseCallback(
|
||||
_In_ PLDR_DATA_TABLE_ENTRY Module,
|
||||
_In_opt_ PVOID Context
|
||||
)
|
||||
{
|
||||
PPHP_GET_IMAGE_BASE_CONTEXT context = Context;
|
||||
|
||||
if (RtlEqualUnicodeString(&Module->FullDllName, &context->ImagePath, TRUE) ||
|
||||
RtlEqualUnicodeString(&Module->BaseDllName, &context->ImagePath, TRUE))
|
||||
{
|
||||
context->BaseAddress = Module->DllBase;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_GetImageBase(
|
||||
_In_ ICLRDataTarget *This,
|
||||
_In_ LPCWSTR imagePath,
|
||||
_Out_ CLRDATA_ADDRESS *baseAddress
|
||||
)
|
||||
{
|
||||
DnCLRDataTarget *this = (DnCLRDataTarget *)This;
|
||||
PHP_GET_IMAGE_BASE_CONTEXT context;
|
||||
|
||||
RtlInitUnicodeString(&context.ImagePath, (PWSTR)imagePath);
|
||||
context.BaseAddress = NULL;
|
||||
PhEnumProcessModules(this->ProcessHandle, PhpGetImageBaseCallback, &context);
|
||||
|
||||
#ifdef _WIN64
|
||||
if (this->IsWow64)
|
||||
PhEnumProcessModules32(this->ProcessHandle, PhpGetImageBaseCallback, &context);
|
||||
#endif
|
||||
|
||||
if (context.BaseAddress)
|
||||
{
|
||||
*baseAddress = (CLRDATA_ADDRESS)context.BaseAddress;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
return E_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_ReadVirtual(
|
||||
_In_ ICLRDataTarget *This,
|
||||
_In_ CLRDATA_ADDRESS address,
|
||||
_Out_ BYTE *buffer,
|
||||
_In_ ULONG32 bytesRequested,
|
||||
_Out_ ULONG32 *bytesRead
|
||||
)
|
||||
{
|
||||
DnCLRDataTarget *this = (DnCLRDataTarget *)This;
|
||||
NTSTATUS status;
|
||||
SIZE_T numberOfBytesRead;
|
||||
|
||||
if (NT_SUCCESS(status = NtReadVirtualMemory(
|
||||
this->ProcessHandle,
|
||||
(PVOID)address,
|
||||
buffer,
|
||||
bytesRequested,
|
||||
&numberOfBytesRead
|
||||
)))
|
||||
{
|
||||
*bytesRead = (ULONG32)numberOfBytesRead;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
ULONG result;
|
||||
|
||||
result = RtlNtStatusToDosError(status);
|
||||
|
||||
return HRESULT_FROM_WIN32(result);
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_WriteVirtual(
|
||||
_In_ ICLRDataTarget *This,
|
||||
_In_ CLRDATA_ADDRESS address,
|
||||
_In_ BYTE *buffer,
|
||||
_In_ ULONG32 bytesRequested,
|
||||
_Out_ ULONG32 *bytesWritten
|
||||
)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_GetTLSValue(
|
||||
_In_ ICLRDataTarget *This,
|
||||
_In_ ULONG32 threadID,
|
||||
_In_ ULONG32 index,
|
||||
_Out_ CLRDATA_ADDRESS *value
|
||||
)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_SetTLSValue(
|
||||
_In_ ICLRDataTarget *This,
|
||||
_In_ ULONG32 threadID,
|
||||
_In_ ULONG32 index,
|
||||
_In_ CLRDATA_ADDRESS value
|
||||
)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_GetCurrentThreadID(
|
||||
_In_ ICLRDataTarget *This,
|
||||
_Out_ ULONG32 *threadID
|
||||
)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_GetThreadContext(
|
||||
_In_ ICLRDataTarget *This,
|
||||
_In_ ULONG32 threadID,
|
||||
_In_ ULONG32 contextFlags,
|
||||
_In_ ULONG32 contextSize,
|
||||
_Out_ BYTE *context
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
HANDLE threadHandle;
|
||||
CONTEXT buffer;
|
||||
|
||||
if (contextSize < sizeof(CONTEXT))
|
||||
return E_INVALIDARG;
|
||||
|
||||
memset(&buffer, 0, sizeof(CONTEXT));
|
||||
buffer.ContextFlags = contextFlags;
|
||||
|
||||
if (NT_SUCCESS(status = PhOpenThread(&threadHandle, THREAD_GET_CONTEXT, UlongToHandle(threadID))))
|
||||
{
|
||||
status = NtGetContextThread(threadHandle, &buffer);
|
||||
NtClose(threadHandle);
|
||||
}
|
||||
|
||||
if (NT_SUCCESS(status))
|
||||
{
|
||||
memcpy(context, &buffer, sizeof(CONTEXT));
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
return HRESULT_FROM_WIN32(RtlNtStatusToDosError(status));
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_SetThreadContext(
|
||||
_In_ ICLRDataTarget *This,
|
||||
_In_ ULONG32 threadID,
|
||||
_In_ ULONG32 contextSize,
|
||||
_In_ BYTE *context
|
||||
)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_Request(
|
||||
_In_ ICLRDataTarget *This,
|
||||
_In_ ULONG32 reqCode,
|
||||
_In_ ULONG32 inBufferSize,
|
||||
_In_ BYTE *inBuffer,
|
||||
_In_ ULONG32 outBufferSize,
|
||||
_Out_ BYTE *outBuffer
|
||||
)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
645
plugins/DotNetTools/clrsup.h
Normal file
645
plugins/DotNetTools/clrsup.h
Normal file
@@ -0,0 +1,645 @@
|
||||
/*
|
||||
* Process Hacker .NET Tools -
|
||||
* CLR data access functions
|
||||
*
|
||||
* Copyright (C) 2011-2015 wj32
|
||||
*
|
||||
* This file is part of Process Hacker.
|
||||
*
|
||||
* Process Hacker is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Process Hacker is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CLRSUP_H
|
||||
#define CLRSUP_H
|
||||
|
||||
#define CINTERFACE
|
||||
#define COBJMACROS
|
||||
#include <clrdata.h>
|
||||
#undef CINTERFACE
|
||||
#undef COBJMACROS
|
||||
|
||||
// General interfaces
|
||||
|
||||
typedef struct _CLR_PROCESS_SUPPORT
|
||||
{
|
||||
struct IXCLRDataProcess *DataProcess;
|
||||
} CLR_PROCESS_SUPPORT, *PCLR_PROCESS_SUPPORT;
|
||||
|
||||
PCLR_PROCESS_SUPPORT CreateClrProcessSupport(
|
||||
_In_ HANDLE ProcessId
|
||||
);
|
||||
|
||||
VOID FreeClrProcessSupport(
|
||||
_In_ PCLR_PROCESS_SUPPORT Support
|
||||
);
|
||||
|
||||
PPH_STRING GetRuntimeNameByAddressClrProcess(
|
||||
_In_ PCLR_PROCESS_SUPPORT Support,
|
||||
_In_ ULONG64 Address,
|
||||
_Out_opt_ PULONG64 Displacement
|
||||
);
|
||||
|
||||
PPH_STRING GetNameXClrDataAppDomain(
|
||||
_In_ PVOID AppDomain
|
||||
);
|
||||
|
||||
PVOID LoadMscordacwks(
|
||||
_In_ BOOLEAN IsClrV4
|
||||
);
|
||||
|
||||
HRESULT CreateXCLRDataProcess(
|
||||
_In_ HANDLE ProcessId,
|
||||
_In_ ICLRDataTarget *Target,
|
||||
_Out_ struct IXCLRDataProcess **DataProcess
|
||||
);
|
||||
|
||||
// xclrdata
|
||||
|
||||
typedef ULONG64 CLRDATA_ENUM;
|
||||
|
||||
typedef struct IXCLRDataProcess IXCLRDataProcess;
|
||||
typedef struct IXCLRDataAppDomain IXCLRDataAppDomain;
|
||||
typedef struct IXCLRDataTask IXCLRDataTask;
|
||||
typedef struct IXCLRDataStackWalk IXCLRDataStackWalk;
|
||||
typedef struct IXCLRDataFrame IXCLRDataFrame;
|
||||
|
||||
typedef struct IXCLRDataProcessVtbl
|
||||
{
|
||||
HRESULT (STDMETHODCALLTYPE *QueryInterface)(
|
||||
_In_ IXCLRDataProcess *This,
|
||||
_In_ REFIID riid,
|
||||
_Outptr_ void **ppvObject
|
||||
);
|
||||
|
||||
ULONG (STDMETHODCALLTYPE *AddRef)(
|
||||
_In_ IXCLRDataProcess *This
|
||||
);
|
||||
|
||||
ULONG (STDMETHODCALLTYPE *Release)(
|
||||
_In_ IXCLRDataProcess *This
|
||||
);
|
||||
|
||||
HRESULT (STDMETHODCALLTYPE *Flush)(
|
||||
_In_ IXCLRDataProcess *This
|
||||
);
|
||||
|
||||
HRESULT (STDMETHODCALLTYPE *StartEnumTasks)(
|
||||
_In_ IXCLRDataProcess *This,
|
||||
_Out_ CLRDATA_ENUM *handle
|
||||
);
|
||||
|
||||
HRESULT (STDMETHODCALLTYPE *EnumTask)(
|
||||
_In_ IXCLRDataProcess *This,
|
||||
_Inout_ CLRDATA_ENUM *handle,
|
||||
_Out_ IXCLRDataTask **task
|
||||
);
|
||||
|
||||
HRESULT (STDMETHODCALLTYPE *EndEnumTasks)(
|
||||
_In_ IXCLRDataProcess *This,
|
||||
_In_ CLRDATA_ENUM handle
|
||||
);
|
||||
|
||||
HRESULT (STDMETHODCALLTYPE *GetTaskByOSThreadID)(
|
||||
_In_ IXCLRDataProcess *This,
|
||||
_In_ ULONG32 osThreadID,
|
||||
_Out_ IXCLRDataTask **task
|
||||
);
|
||||
|
||||
PVOID GetTaskByUniqueID;
|
||||
PVOID GetFlags;
|
||||
PVOID IsSameObject;
|
||||
PVOID GetManagedObject;
|
||||
PVOID GetDesiredExecutionState;
|
||||
PVOID SetDesiredExecutionState;
|
||||
PVOID GetAddressType;
|
||||
|
||||
HRESULT (STDMETHODCALLTYPE *GetRuntimeNameByAddress)(
|
||||
_In_ IXCLRDataProcess *This,
|
||||
_In_ CLRDATA_ADDRESS address,
|
||||
_In_ ULONG32 flags,
|
||||
_In_ ULONG32 bufLen,
|
||||
_Out_ ULONG32 *nameLen,
|
||||
_Out_ WCHAR *nameBuf,
|
||||
_Out_ CLRDATA_ADDRESS *displacement
|
||||
);
|
||||
|
||||
// ...
|
||||
} IXCLRDataProcessVtbl;
|
||||
|
||||
typedef struct IXCLRDataProcess
|
||||
{
|
||||
struct IXCLRDataProcessVtbl *lpVtbl;
|
||||
} IXCLRDataProcess;
|
||||
|
||||
#define IXCLRDataProcess_QueryInterface(This, riid, ppvObject) \
|
||||
((This)->lpVtbl->QueryInterface(This, riid, ppvObject))
|
||||
|
||||
#define IXCLRDataProcess_AddRef(This) \
|
||||
((This)->lpVtbl->AddRef(This))
|
||||
|
||||
#define IXCLRDataProcess_Release(This) \
|
||||
((This)->lpVtbl->Release(This))
|
||||
|
||||
#define IXCLRDataProcess_GetRuntimeNameByAddress(This, address, flags, bufLen, nameLen, nameBuf, displacement) \
|
||||
((This)->lpVtbl->GetRuntimeNameByAddress(This, address, flags, bufLen, nameLen, nameBuf, displacement))
|
||||
|
||||
#define IXCLRDataProcess_Flush(This) \
|
||||
((This)->lpVtbl->Flush(This))
|
||||
|
||||
#define IXCLRDataProcess_StartEnumTasks(This, handle) \
|
||||
((This)->lpVtbl->StartEnumTasks(This, handle))
|
||||
|
||||
#define IXCLRDataProcess_EnumTask(This, handle, task) \
|
||||
((This)->lpVtbl->EnumTask(This, handle, task))
|
||||
|
||||
#define IXCLRDataProcess_EndEnumTasks(This, handle) \
|
||||
((This)->lpVtbl->EndEnumTasks(This, handle))
|
||||
|
||||
#define IXCLRDataProcess_GetTaskByOSThreadID(This, osThreadID, task) \
|
||||
((This)->lpVtbl->GetTaskByOSThreadID(This, osThreadID, task))
|
||||
|
||||
typedef struct IXCLRDataAppDomainVtbl
|
||||
{
|
||||
HRESULT (STDMETHODCALLTYPE *QueryInterface)(
|
||||
_In_ IXCLRDataAppDomain *This,
|
||||
_In_ REFIID riid,
|
||||
_Outptr_ void **ppvObject
|
||||
);
|
||||
|
||||
ULONG (STDMETHODCALLTYPE *AddRef)(
|
||||
_In_ IXCLRDataAppDomain *This
|
||||
);
|
||||
|
||||
ULONG (STDMETHODCALLTYPE *Release)(
|
||||
_In_ IXCLRDataAppDomain *This
|
||||
);
|
||||
|
||||
HRESULT (STDMETHODCALLTYPE *GetProcess)(
|
||||
_In_ IXCLRDataAppDomain *This,
|
||||
_Out_ IXCLRDataProcess **process
|
||||
);
|
||||
|
||||
HRESULT (STDMETHODCALLTYPE *GetName)(
|
||||
_In_ IXCLRDataAppDomain *This,
|
||||
_In_ ULONG32 bufLen,
|
||||
_Out_ ULONG32 *nameLen,
|
||||
_Out_ WCHAR *name
|
||||
);
|
||||
|
||||
HRESULT (STDMETHODCALLTYPE *GetUniqueID)(
|
||||
_In_ IXCLRDataAppDomain *This,
|
||||
_Out_ ULONG64 *id
|
||||
);
|
||||
|
||||
// ...
|
||||
} IXCLRDataAppDomainVtbl;
|
||||
|
||||
typedef struct IXCLRDataAppDomain
|
||||
{
|
||||
struct IXCLRDataAppDomainVtbl *lpVtbl;
|
||||
} IXCLRDataAppDomain;
|
||||
|
||||
#define IXCLRDataAppDomain_QueryInterface(This, riid, ppvObject) \
|
||||
((This)->lpVtbl->QueryInterface(This, riid, ppvObject))
|
||||
|
||||
#define IXCLRDataAppDomain_AddRef(This) \
|
||||
((This)->lpVtbl->AddRef(This))
|
||||
|
||||
#define IXCLRDataAppDomain_Release(This) \
|
||||
((This)->lpVtbl->Release(This))
|
||||
|
||||
#define IXCLRDataAppDomain_GetProcess(This, process) \
|
||||
((This)->lpVtbl->GetProcess(This, process))
|
||||
|
||||
#define IXCLRDataAppDomain_GetName(This, bufLen, nameLen, name) \
|
||||
((This)->lpVtbl->GetName(This, bufLen, nameLen, name))
|
||||
|
||||
#define IXCLRDataAppDomain_GetUniqueID(This, id) \
|
||||
((This)->lpVtbl->GetUniqueID(This, id))
|
||||
|
||||
typedef struct IXCLRDataTaskVtbl
|
||||
{
|
||||
HRESULT (STDMETHODCALLTYPE *QueryInterface)(
|
||||
_In_ IXCLRDataTask *This,
|
||||
_In_ REFIID riid,
|
||||
_Outptr_ void **ppvObject
|
||||
);
|
||||
|
||||
ULONG (STDMETHODCALLTYPE *AddRef)(
|
||||
_In_ IXCLRDataTask *This
|
||||
);
|
||||
|
||||
ULONG (STDMETHODCALLTYPE *Release)(
|
||||
_In_ IXCLRDataTask *This
|
||||
);
|
||||
|
||||
HRESULT (STDMETHODCALLTYPE *GetProcess)(
|
||||
_In_ IXCLRDataTask *This,
|
||||
_Out_ IXCLRDataProcess **process
|
||||
);
|
||||
|
||||
HRESULT (STDMETHODCALLTYPE *GetCurrentAppDomain)(
|
||||
_In_ IXCLRDataTask *This,
|
||||
_Out_ IXCLRDataAppDomain **appDomain
|
||||
);
|
||||
|
||||
HRESULT (STDMETHODCALLTYPE *GetUniqueID)(
|
||||
_In_ IXCLRDataTask *This,
|
||||
_Out_ ULONG64 *id
|
||||
);
|
||||
|
||||
HRESULT (STDMETHODCALLTYPE *GetFlags)(
|
||||
_In_ IXCLRDataTask *This,
|
||||
_Out_ ULONG32 *flags
|
||||
);
|
||||
|
||||
PVOID IsSameObject;
|
||||
PVOID GetManagedObject;
|
||||
PVOID GetDesiredExecutionState;
|
||||
PVOID SetDesiredExecutionState;
|
||||
|
||||
HRESULT (STDMETHODCALLTYPE *CreateStackWalk)(
|
||||
_In_ IXCLRDataTask *This,
|
||||
_In_ ULONG32 flags,
|
||||
_Out_ IXCLRDataStackWalk **stackWalk
|
||||
);
|
||||
|
||||
HRESULT (STDMETHODCALLTYPE *GetOSThreadID)(
|
||||
_In_ IXCLRDataTask *This,
|
||||
_Out_ ULONG32 *id
|
||||
);
|
||||
|
||||
PVOID GetContext;
|
||||
PVOID SetContext;
|
||||
PVOID GetCurrentExceptionState;
|
||||
PVOID Request;
|
||||
|
||||
HRESULT (STDMETHODCALLTYPE *GetName)(
|
||||
_In_ IXCLRDataTask *This,
|
||||
_In_ ULONG32 bufLen,
|
||||
_Out_ ULONG32 *nameLen,
|
||||
_Out_ WCHAR *name
|
||||
);
|
||||
|
||||
PVOID GetLastExceptionState;
|
||||
} IXCLRDataTaskVtbl;
|
||||
|
||||
typedef struct IXCLRDataTask
|
||||
{
|
||||
struct IXCLRDataTaskVtbl *lpVtbl;
|
||||
} IXCLRDataTask;
|
||||
|
||||
#define IXCLRDataTask_QueryInterface(This, riid, ppvObject) \
|
||||
((This)->lpVtbl->QueryInterface(This, riid, ppvObject))
|
||||
|
||||
#define IXCLRDataTask_AddRef(This) \
|
||||
((This)->lpVtbl->AddRef(This))
|
||||
|
||||
#define IXCLRDataTask_Release(This) \
|
||||
((This)->lpVtbl->Release(This))
|
||||
|
||||
#define IXCLRDataTask_GetProcess(This, process) \
|
||||
((This)->lpVtbl->GetProcess(This, process))
|
||||
|
||||
#define IXCLRDataTask_GetCurrentAppDomain(This, appDomain) \
|
||||
((This)->lpVtbl->GetCurrentAppDomain(This, appDomain))
|
||||
|
||||
#define IXCLRDataTask_GetUniqueID(This, id) \
|
||||
((This)->lpVtbl->GetUniqueID(This, id))
|
||||
|
||||
#define IXCLRDataTask_GetFlags(This, flags) \
|
||||
((This)->lpVtbl->GetFlags(This, flags))
|
||||
|
||||
#define IXCLRDataTask_CreateStackWalk(This, flags, stackWalk) \
|
||||
((This)->lpVtbl->CreateStackWalk(This, flags, stackWalk))
|
||||
|
||||
#define IXCLRDataTask_GetOSThreadID(This, id) \
|
||||
((This)->lpVtbl->GetOSThreadID(This, id))
|
||||
|
||||
#define IXCLRDataTask_GetName(This, bufLen, nameLen, name) \
|
||||
((This)->lpVtbl->GetName(This, bufLen, nameLen, name))
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CLRDATA_SIMPFRAME_UNRECOGNIZED = 0x1,
|
||||
CLRDATA_SIMPFRAME_MANAGED_METHOD = 0x2,
|
||||
CLRDATA_SIMPFRAME_RUNTIME_MANAGED_CODE = 0x4,
|
||||
CLRDATA_SIMPFRAME_RUNTIME_UNMANAGED_CODE = 0x8
|
||||
} CLRDataSimpleFrameType;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CLRDATA_DETFRAME_UNRECOGNIZED,
|
||||
CLRDATA_DETFRAME_UNKNOWN_STUB,
|
||||
CLRDATA_DETFRAME_CLASS_INIT,
|
||||
CLRDATA_DETFRAME_EXCEPTION_FILTER,
|
||||
CLRDATA_DETFRAME_SECURITY,
|
||||
CLRDATA_DETFRAME_CONTEXT_POLICY,
|
||||
CLRDATA_DETFRAME_INTERCEPTION,
|
||||
CLRDATA_DETFRAME_PROCESS_START,
|
||||
CLRDATA_DETFRAME_THREAD_START,
|
||||
CLRDATA_DETFRAME_TRANSITION_TO_MANAGED,
|
||||
CLRDATA_DETFRAME_TRANSITION_TO_UNMANAGED,
|
||||
CLRDATA_DETFRAME_COM_INTEROP_STUB,
|
||||
CLRDATA_DETFRAME_DEBUGGER_EVAL,
|
||||
CLRDATA_DETFRAME_CONTEXT_SWITCH,
|
||||
CLRDATA_DETFRAME_FUNC_EVAL,
|
||||
CLRDATA_DETFRAME_FINALLY
|
||||
} CLRDataDetailedFrameType;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
CLRDATA_STACK_SET_UNWIND_CONTEXT = 0x00000000,
|
||||
CLRDATA_STACK_SET_CURRENT_CONTEXT = 0x00000001
|
||||
} CLRDataStackSetContextFlag;
|
||||
|
||||
typedef struct IXCLRDataStackWalkVtbl
|
||||
{
|
||||
HRESULT (STDMETHODCALLTYPE *QueryInterface)(
|
||||
_In_ IXCLRDataStackWalk *This,
|
||||
_In_ REFIID riid,
|
||||
_Outptr_ void **ppvObject
|
||||
);
|
||||
|
||||
ULONG (STDMETHODCALLTYPE *AddRef)(
|
||||
_In_ IXCLRDataStackWalk *This
|
||||
);
|
||||
|
||||
ULONG (STDMETHODCALLTYPE *Release)(
|
||||
_In_ IXCLRDataStackWalk *This
|
||||
);
|
||||
|
||||
HRESULT (STDMETHODCALLTYPE *GetContext)(
|
||||
_In_ IXCLRDataStackWalk *This,
|
||||
_In_ ULONG32 contextFlags,
|
||||
_In_ ULONG32 contextBufSize,
|
||||
_Out_ ULONG32 *contextSize,
|
||||
_Out_ BYTE *contextBuf
|
||||
);
|
||||
|
||||
PVOID SetContext;
|
||||
|
||||
HRESULT (STDMETHODCALLTYPE *Next)(
|
||||
_In_ IXCLRDataStackWalk *This
|
||||
);
|
||||
|
||||
HRESULT (STDMETHODCALLTYPE *GetStackSizeSkipped)(
|
||||
_In_ IXCLRDataStackWalk *This,
|
||||
_Out_ ULONG64 *stackSizeSkipped
|
||||
);
|
||||
|
||||
HRESULT (STDMETHODCALLTYPE *GetFrameType)(
|
||||
_In_ IXCLRDataStackWalk *This,
|
||||
_Out_ CLRDataSimpleFrameType *simpleType,
|
||||
_Out_ CLRDataDetailedFrameType *detailedType
|
||||
);
|
||||
|
||||
HRESULT (STDMETHODCALLTYPE *GetFrame)(
|
||||
_In_ IXCLRDataStackWalk *This,
|
||||
_Out_ PVOID *frame
|
||||
);
|
||||
|
||||
HRESULT (STDMETHODCALLTYPE *Request)(
|
||||
_In_ IXCLRDataStackWalk *This,
|
||||
_In_ ULONG32 reqCode,
|
||||
_In_ ULONG32 inBufferSize,
|
||||
_In_ BYTE *inBuffer,
|
||||
_In_ ULONG32 outBufferSize,
|
||||
_Out_ BYTE *outBuffer
|
||||
);
|
||||
|
||||
HRESULT (STDMETHODCALLTYPE *SetContext2)(
|
||||
_In_ IXCLRDataStackWalk *This,
|
||||
_In_ ULONG32 flags,
|
||||
_In_ ULONG32 contextSize,
|
||||
_In_ BYTE *context
|
||||
);
|
||||
} IXCLRDataStackWalkVtbl;
|
||||
|
||||
typedef struct IXCLRDataStackWalk
|
||||
{
|
||||
struct IXCLRDataStackWalkVtbl *lpVtbl;
|
||||
} IXCLRDataStackWalk;
|
||||
|
||||
#define IXCLRDataStackWalk_QueryInterface(This, riid, ppvObject) \
|
||||
((This)->lpVtbl->QueryInterface(This, riid, ppvObject))
|
||||
|
||||
#define IXCLRDataStackWalk_AddRef(This) \
|
||||
((This)->lpVtbl->AddRef(This))
|
||||
|
||||
#define IXCLRDataStackWalk_Release(This) \
|
||||
((This)->lpVtbl->Release(This))
|
||||
|
||||
#define IXCLRDataStackWalk_GetContext(This, contextFlags, contextBufSize, contextSize, contextBuf) \
|
||||
((This)->lpVtbl->GetContext(This, contextFlags, contextBufSize, contextSize, contextBuf))
|
||||
|
||||
#define IXCLRDataStackWalk_Next(This) \
|
||||
((This)->lpVtbl->Next(This))
|
||||
|
||||
#define IXCLRDataStackWalk_GetStackSizeSkipped(This, stackSizeSkipped) \
|
||||
((This)->lpVtbl->GetStackSizeSkipped(This, stackSizeSkipped))
|
||||
|
||||
#define IXCLRDataStackWalk_GetFrameType(This, simpleType, detailedType) \
|
||||
((This)->lpVtbl->GetFrameType(This, simpleType, detailedType))
|
||||
|
||||
#define IXCLRDataStackWalk_GetFrame(This, frame) \
|
||||
((This)->lpVtbl->GetFrame(This, frame))
|
||||
|
||||
#define IXCLRDataStackWalk_Request(This, reqCode, inBufferSize, inBuffer, outBufferSize, outBuffer) \
|
||||
((This)->lpVtbl->SetContext2(This, reqCode, inBufferSize, inBuffer, outBufferSize, outBuffer))
|
||||
|
||||
#define IXCLRDataStackWalk_SetContext2(This, flags, contextSize, context) \
|
||||
((This)->lpVtbl->SetContext2(This, flags, contextSize, context))
|
||||
|
||||
typedef struct IXCLRDataFrameVtbl
|
||||
{
|
||||
HRESULT (STDMETHODCALLTYPE *QueryInterface)(
|
||||
_In_ IXCLRDataFrame *This,
|
||||
_In_ REFIID riid,
|
||||
_Outptr_ void **ppvObject
|
||||
);
|
||||
|
||||
ULONG (STDMETHODCALLTYPE *AddRef)(
|
||||
_In_ IXCLRDataFrame *This
|
||||
);
|
||||
|
||||
ULONG (STDMETHODCALLTYPE *Release)(
|
||||
_In_ IXCLRDataFrame *This
|
||||
);
|
||||
|
||||
HRESULT (STDMETHODCALLTYPE *GetFrameType)(
|
||||
_In_ IXCLRDataFrame *This,
|
||||
_Out_ CLRDataSimpleFrameType *simpleType,
|
||||
_Out_ CLRDataDetailedFrameType *detailedType
|
||||
);
|
||||
|
||||
HRESULT (STDMETHODCALLTYPE *GetContext)(
|
||||
_In_ IXCLRDataFrame *This,
|
||||
_In_ ULONG32 contextFlags,
|
||||
_In_ ULONG32 contextBufSize,
|
||||
_Out_ ULONG32 *contextSize,
|
||||
_Out_ BYTE *contextBuf
|
||||
);
|
||||
|
||||
PVOID GetAppDomain;
|
||||
PVOID GetNumArguments;
|
||||
PVOID GetArgumentByIndex;
|
||||
PVOID GetNumLocalVariables;
|
||||
PVOID GetLocalVariableByIndex;
|
||||
|
||||
HRESULT (STDMETHODCALLTYPE *GetCodeName)(
|
||||
_In_ IXCLRDataFrame *This,
|
||||
_In_ ULONG32 *flags,
|
||||
_In_ ULONG32 *bufLen,
|
||||
_Out_ ULONG32 *nameLen,
|
||||
_Out_ WCHAR *nameBuf
|
||||
);
|
||||
} IXCLRDataFrameVtbl;
|
||||
|
||||
typedef struct IXCLRDataFrame
|
||||
{
|
||||
IXCLRDataFrameVtbl *lpVtbl;
|
||||
} IXCLRDataFrame;
|
||||
|
||||
#define IXCLRDataFrame_QueryInterface(This, riid, ppvObject) \
|
||||
((This)->lpVtbl->QueryInterface(This, riid, ppvObject))
|
||||
|
||||
#define IXCLRDataFrame_AddRef(This) \
|
||||
((This)->lpVtbl->AddRef(This))
|
||||
|
||||
#define IXCLRDataFrame_Release(This) \
|
||||
((This)->lpVtbl->Release(This))
|
||||
|
||||
#define IXCLRDataFrame_GetFrameType(This, simpleType, detailedType) \
|
||||
((This)->lpVtbl->GetFrameType(This, simpleType, detailedType))
|
||||
|
||||
#define IXCLRDataFrame_GetContext(This, contextFlags, contextBufSize, contextSize, contextBuf) \
|
||||
((This)->lpVtbl->GetContext(This, contextFlags, contextBufSize, contextSize, contextBuf))
|
||||
|
||||
#define IXCLRDataFrame_GetCodeName(This, flags, bufLen, nameLen, nameBuf) \
|
||||
((This)->lpVtbl->GetCodeName(This, flags, bufLen, nameLen, nameBuf))
|
||||
|
||||
// DnCLRDataTarget
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ICLRDataTargetVtbl *VTable;
|
||||
|
||||
ULONG RefCount;
|
||||
|
||||
HANDLE ProcessId;
|
||||
HANDLE ProcessHandle;
|
||||
BOOLEAN IsWow64;
|
||||
} DnCLRDataTarget;
|
||||
|
||||
ICLRDataTarget *DnCLRDataTarget_Create(
|
||||
_In_ HANDLE ProcessId
|
||||
);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_QueryInterface(
|
||||
_In_ ICLRDataTarget *This,
|
||||
_In_ REFIID Riid,
|
||||
_Out_ PVOID *Object
|
||||
);
|
||||
|
||||
ULONG STDMETHODCALLTYPE DnCLRDataTarget_AddRef(
|
||||
_In_ ICLRDataTarget *This
|
||||
);
|
||||
|
||||
ULONG STDMETHODCALLTYPE DnCLRDataTarget_Release(
|
||||
_In_ ICLRDataTarget *This
|
||||
);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_GetMachineType(
|
||||
_In_ ICLRDataTarget *This,
|
||||
_Out_ ULONG32 *machineType
|
||||
);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_GetPointerSize(
|
||||
_In_ ICLRDataTarget *This,
|
||||
_Out_ ULONG32 *pointerSize
|
||||
);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_GetImageBase(
|
||||
_In_ ICLRDataTarget *This,
|
||||
_In_ LPCWSTR imagePath,
|
||||
_Out_ CLRDATA_ADDRESS *baseAddress
|
||||
);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_ReadVirtual(
|
||||
_In_ ICLRDataTarget *This,
|
||||
_In_ CLRDATA_ADDRESS address,
|
||||
_Out_ BYTE *buffer,
|
||||
_In_ ULONG32 bytesRequested,
|
||||
_Out_ ULONG32 *bytesRead
|
||||
);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_WriteVirtual(
|
||||
_In_ ICLRDataTarget *This,
|
||||
_In_ CLRDATA_ADDRESS address,
|
||||
_In_ BYTE *buffer,
|
||||
_In_ ULONG32 bytesRequested,
|
||||
_Out_ ULONG32 *bytesWritten
|
||||
);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_GetTLSValue(
|
||||
_In_ ICLRDataTarget *This,
|
||||
_In_ ULONG32 threadID,
|
||||
_In_ ULONG32 index,
|
||||
_Out_ CLRDATA_ADDRESS *value
|
||||
);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_SetTLSValue(
|
||||
_In_ ICLRDataTarget *This,
|
||||
_In_ ULONG32 threadID,
|
||||
_In_ ULONG32 index,
|
||||
_In_ CLRDATA_ADDRESS value
|
||||
);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_GetCurrentThreadID(
|
||||
_In_ ICLRDataTarget *This,
|
||||
_Out_ ULONG32 *threadID
|
||||
);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_GetThreadContext(
|
||||
_In_ ICLRDataTarget *This,
|
||||
_In_ ULONG32 threadID,
|
||||
_In_ ULONG32 contextFlags,
|
||||
_In_ ULONG32 contextSize,
|
||||
_Out_ BYTE *context
|
||||
);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_SetThreadContext(
|
||||
_In_ ICLRDataTarget *This,
|
||||
_In_ ULONG32 threadID,
|
||||
_In_ ULONG32 contextSize,
|
||||
_In_ BYTE *context
|
||||
);
|
||||
|
||||
HRESULT STDMETHODCALLTYPE DnCLRDataTarget_Request(
|
||||
_In_ ICLRDataTarget *This,
|
||||
_In_ ULONG32 reqCode,
|
||||
_In_ ULONG32 inBufferSize,
|
||||
_In_ BYTE *inBuffer,
|
||||
_In_ ULONG32 outBufferSize,
|
||||
_Out_ BYTE *outBuffer
|
||||
);
|
||||
|
||||
typedef struct _PHP_GET_IMAGE_BASE_CONTEXT
|
||||
{
|
||||
UNICODE_STRING ImagePath;
|
||||
PVOID BaseAddress;
|
||||
} PHP_GET_IMAGE_BASE_CONTEXT, *PPHP_GET_IMAGE_BASE_CONTEXT;
|
||||
|
||||
#endif
|
||||
1044
plugins/DotNetTools/counters.c
Normal file
1044
plugins/DotNetTools/counters.c
Normal file
File diff suppressed because it is too large
Load Diff
144
plugins/DotNetTools/dn.h
Normal file
144
plugins/DotNetTools/dn.h
Normal file
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Process Hacker .NET Tools
|
||||
*
|
||||
* Copyright (C) 2011-2015 wj32
|
||||
* Copyright (C) 2015-2016 dmex
|
||||
*
|
||||
* This file is part of Process Hacker.
|
||||
*
|
||||
* Process Hacker is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Process Hacker is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef DN_H
|
||||
#define DN_H
|
||||
|
||||
#define CINTERFACE
|
||||
#define COBJMACROS
|
||||
#include <phdk.h>
|
||||
#include <windowsx.h>
|
||||
|
||||
#include "resource.h"
|
||||
|
||||
#define PLUGIN_NAME L"ProcessHacker.DotNetTools"
|
||||
#define SETTING_NAME_ASM_TREE_LIST_COLUMNS (PLUGIN_NAME L".AsmTreeListColumns")
|
||||
#define SETTING_NAME_DOT_NET_CATEGORY_INDEX (PLUGIN_NAME L".DotNetCategoryIndex")
|
||||
#define SETTING_NAME_DOT_NET_COUNTERS_COLUMNS (PLUGIN_NAME L".DotNetListColumns")
|
||||
#define SETTING_NAME_DOT_NET_SHOW_BYTE_SIZE (PLUGIN_NAME L".DotNetShowByteSizes")
|
||||
|
||||
#define MSG_UPDATE (WM_APP + 1)
|
||||
|
||||
extern PPH_PLUGIN PluginInstance;
|
||||
|
||||
typedef struct _DN_THREAD_ITEM
|
||||
{
|
||||
PPH_THREAD_ITEM ThreadItem;
|
||||
|
||||
BOOLEAN ClrDataValid;
|
||||
PPH_STRING AppDomainText;
|
||||
} DN_THREAD_ITEM, *PDN_THREAD_ITEM;
|
||||
|
||||
// counters
|
||||
|
||||
PVOID GetPerfIpcBlock_V2(
|
||||
_In_ BOOLEAN Wow64,
|
||||
_In_ PVOID BlockTableAddress
|
||||
);
|
||||
|
||||
PVOID GetPerfIpcBlock_V4(
|
||||
_In_ BOOLEAN Wow64,
|
||||
_In_ PVOID BlockTableAddress
|
||||
);
|
||||
|
||||
BOOLEAN OpenDotNetPublicControlBlock_V2(
|
||||
_In_ HANDLE ProcessId,
|
||||
_Out_ HANDLE* BlockTableHandle,
|
||||
_Out_ PVOID* BlockTableAddress
|
||||
);
|
||||
|
||||
BOOLEAN OpenDotNetPublicControlBlock_V4(
|
||||
_In_ BOOLEAN IsImmersive,
|
||||
_In_ HANDLE ProcessHandle,
|
||||
_In_ HANDLE ProcessId,
|
||||
_Out_ HANDLE* BlockTableHandle,
|
||||
_Out_ PVOID* BlockTableAddress
|
||||
);
|
||||
|
||||
PPH_LIST QueryDotNetAppDomainsForPid_V2(
|
||||
_In_ BOOLEAN Wow64,
|
||||
_In_ HANDLE ProcessHandle,
|
||||
_In_ HANDLE ProcessId
|
||||
);
|
||||
|
||||
PPH_LIST QueryDotNetAppDomainsForPid_V4(
|
||||
_In_ BOOLEAN Wow64,
|
||||
_In_ HANDLE ProcessHandle,
|
||||
_In_ HANDLE ProcessId
|
||||
);
|
||||
|
||||
// asmpage
|
||||
|
||||
VOID AddAsmPageToPropContext(
|
||||
_In_ PPH_PLUGIN_PROCESS_PROPCONTEXT PropContext
|
||||
);
|
||||
|
||||
// perfpage
|
||||
|
||||
VOID AddPerfPageToPropContext(
|
||||
_In_ PPH_PLUGIN_PROCESS_PROPCONTEXT PropContext
|
||||
);
|
||||
|
||||
// stackext
|
||||
|
||||
VOID ProcessThreadStackControl(
|
||||
_In_ PPH_PLUGIN_THREAD_STACK_CONTROL Control
|
||||
);
|
||||
|
||||
VOID PredictAddressesFromClrData(
|
||||
_In_ struct _CLR_PROCESS_SUPPORT *Support,
|
||||
_In_ HANDLE ThreadId,
|
||||
_In_ PVOID PcAddress,
|
||||
_In_ PVOID FrameAddress,
|
||||
_In_ PVOID StackAddress,
|
||||
_Out_ PVOID *PredictedEip,
|
||||
_Out_ PVOID *PredictedEbp,
|
||||
_Out_ PVOID *PredictedEsp
|
||||
);
|
||||
|
||||
// svcext
|
||||
|
||||
VOID DispatchPhSvcRequest(
|
||||
_In_ PVOID Parameter
|
||||
);
|
||||
|
||||
// treeext
|
||||
|
||||
VOID InitializeTreeNewObjectExtensions(
|
||||
VOID
|
||||
);
|
||||
|
||||
VOID DispatchTreeNewMessage(
|
||||
__in PVOID Parameter
|
||||
);
|
||||
|
||||
#define DNTHTNC_APPDOMAIN 1
|
||||
|
||||
VOID ThreadTreeNewInitializing(
|
||||
__in PVOID Parameter
|
||||
);
|
||||
|
||||
VOID ThreadTreeNewUninitializing(
|
||||
__in PVOID Parameter
|
||||
);
|
||||
|
||||
#endif
|
||||
336
plugins/DotNetTools/main.c
Normal file
336
plugins/DotNetTools/main.c
Normal file
@@ -0,0 +1,336 @@
|
||||
/*
|
||||
* Process Hacker .NET Tools -
|
||||
* main program
|
||||
*
|
||||
* Copyright (C) 2011-2015 wj32
|
||||
* Copyright (C) 2015-2016 dmex
|
||||
*
|
||||
* This file is part of Process Hacker.
|
||||
*
|
||||
* Process Hacker is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Process Hacker is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "dn.h"
|
||||
|
||||
PPH_PLUGIN PluginInstance;
|
||||
static PH_CALLBACK_REGISTRATION PluginLoadCallbackRegistration;
|
||||
static PH_CALLBACK_REGISTRATION PluginUnloadCallbackRegistration;
|
||||
static PH_CALLBACK_REGISTRATION PluginShowOptionsCallbackRegistration;
|
||||
static PH_CALLBACK_REGISTRATION PluginMenuItemCallbackRegistration;
|
||||
static PH_CALLBACK_REGISTRATION PluginTreeNewMessageCallbackRegistration;
|
||||
static PH_CALLBACK_REGISTRATION PluginPhSvcRequestCallbackRegistration;
|
||||
static PH_CALLBACK_REGISTRATION MainWindowShowingCallbackRegistration;
|
||||
static PH_CALLBACK_REGISTRATION ProcessPropertiesInitializingCallbackRegistration;
|
||||
static PH_CALLBACK_REGISTRATION ProcessMenuInitializingCallbackRegistration;
|
||||
static PH_CALLBACK_REGISTRATION ThreadMenuInitializingCallbackRegistration;
|
||||
static PH_CALLBACK_REGISTRATION ModuleMenuInitializingCallbackRegistration;
|
||||
static PH_CALLBACK_REGISTRATION ProcessTreeNewInitializingCallbackRegistration;
|
||||
static PH_CALLBACK_REGISTRATION ThreadTreeNewInitializingCallbackRegistration;
|
||||
static PH_CALLBACK_REGISTRATION ThreadTreeNewUninitializingCallbackRegistration;
|
||||
static PH_CALLBACK_REGISTRATION ThreadStackControlCallbackRegistration;
|
||||
|
||||
VOID NTAPI LoadCallback(
|
||||
_In_opt_ PVOID Parameter,
|
||||
_In_opt_ PVOID Context
|
||||
)
|
||||
{
|
||||
NOTHING;
|
||||
}
|
||||
|
||||
VOID NTAPI UnloadCallback(
|
||||
_In_opt_ PVOID Parameter,
|
||||
_In_opt_ PVOID Context
|
||||
)
|
||||
{
|
||||
NOTHING;
|
||||
}
|
||||
|
||||
VOID NTAPI ShowOptionsCallback(
|
||||
_In_opt_ PVOID Parameter,
|
||||
_In_opt_ PVOID Context
|
||||
)
|
||||
{
|
||||
NOTHING;
|
||||
}
|
||||
|
||||
VOID NTAPI MenuItemCallback(
|
||||
_In_opt_ PVOID Parameter,
|
||||
_In_opt_ PVOID Context
|
||||
)
|
||||
{
|
||||
PPH_PLUGIN_MENU_ITEM menuItem = Parameter;
|
||||
|
||||
switch (menuItem->Id)
|
||||
{
|
||||
default:
|
||||
NOTHING;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
VOID NTAPI TreeNewMessageCallback(
|
||||
_In_opt_ PVOID Parameter,
|
||||
_In_opt_ PVOID Context
|
||||
)
|
||||
{
|
||||
DispatchTreeNewMessage(Parameter);
|
||||
}
|
||||
|
||||
VOID NTAPI PhSvcRequestCallback(
|
||||
_In_opt_ PVOID Parameter,
|
||||
_In_opt_ PVOID Context
|
||||
)
|
||||
{
|
||||
DispatchPhSvcRequest(Parameter);
|
||||
}
|
||||
|
||||
VOID NTAPI ThreadTreeNewInitializingCallback(
|
||||
_In_opt_ PVOID Parameter,
|
||||
_In_opt_ PVOID Context
|
||||
)
|
||||
{
|
||||
ThreadTreeNewInitializing(Parameter);
|
||||
}
|
||||
|
||||
VOID NTAPI ThreadTreeNewUninitializingCallback(
|
||||
_In_opt_ PVOID Parameter,
|
||||
_In_opt_ PVOID Context
|
||||
)
|
||||
{
|
||||
ThreadTreeNewUninitializing(Parameter);
|
||||
}
|
||||
|
||||
VOID NTAPI ProcessPropertiesInitializingCallback(
|
||||
_In_opt_ PVOID Parameter,
|
||||
_In_opt_ PVOID Context
|
||||
)
|
||||
{
|
||||
PPH_PLUGIN_PROCESS_PROPCONTEXT propContext = Parameter;
|
||||
BOOLEAN isDotNet;
|
||||
|
||||
if (NT_SUCCESS(PhGetProcessIsDotNet(propContext->ProcessItem->ProcessId, &isDotNet)))
|
||||
{
|
||||
if (isDotNet)
|
||||
{
|
||||
if (WindowsVersion >= WINDOWS_VISTA)
|
||||
AddAsmPageToPropContext(propContext);
|
||||
AddPerfPageToPropContext(propContext);
|
||||
}
|
||||
|
||||
if (propContext->ProcessItem->IsDotNet != isDotNet)
|
||||
propContext->ProcessItem->UpdateIsDotNet = TRUE; // force a refresh
|
||||
}
|
||||
}
|
||||
|
||||
VOID NTAPI ProcessMenuInitializingCallback(
|
||||
_In_opt_ PVOID Parameter,
|
||||
_In_opt_ PVOID Context
|
||||
)
|
||||
{
|
||||
NOTHING;
|
||||
}
|
||||
|
||||
VOID NTAPI ThreadMenuInitializingCallback(
|
||||
_In_opt_ PVOID Parameter,
|
||||
_In_opt_ PVOID Context
|
||||
)
|
||||
{
|
||||
NOTHING;
|
||||
}
|
||||
|
||||
VOID NTAPI ModuleMenuInitializingCallback(
|
||||
_In_opt_ PVOID Parameter,
|
||||
_In_opt_ PVOID Context
|
||||
)
|
||||
{
|
||||
NOTHING;
|
||||
}
|
||||
|
||||
VOID NTAPI ProcessTreeNewInitializingCallback(
|
||||
_In_opt_ PVOID Parameter,
|
||||
_In_opt_ PVOID Context
|
||||
)
|
||||
{
|
||||
NOTHING;
|
||||
}
|
||||
|
||||
VOID NTAPI ThreadStackControlCallback(
|
||||
_In_opt_ PVOID Parameter,
|
||||
_In_opt_ PVOID Context
|
||||
)
|
||||
{
|
||||
ProcessThreadStackControl(Parameter);
|
||||
}
|
||||
|
||||
VOID NTAPI ThreadItemCreateCallback(
|
||||
_In_ PVOID Object,
|
||||
_In_ PH_EM_OBJECT_TYPE ObjectType,
|
||||
_In_ PVOID Extension
|
||||
)
|
||||
{
|
||||
PDN_THREAD_ITEM dnThread = Extension;
|
||||
|
||||
memset(dnThread, 0, sizeof(DN_THREAD_ITEM));
|
||||
dnThread->ThreadItem = Object;
|
||||
}
|
||||
|
||||
VOID NTAPI ThreadItemDeleteCallback(
|
||||
_In_ PVOID Object,
|
||||
_In_ PH_EM_OBJECT_TYPE ObjectType,
|
||||
_In_ PVOID Extension
|
||||
)
|
||||
{
|
||||
PDN_THREAD_ITEM dnThread = Extension;
|
||||
|
||||
PhClearReference(&dnThread->AppDomainText);
|
||||
}
|
||||
|
||||
LOGICAL DllMain(
|
||||
_In_ HINSTANCE Instance,
|
||||
_In_ ULONG Reason,
|
||||
_Reserved_ PVOID Reserved
|
||||
)
|
||||
{
|
||||
switch (Reason)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
{
|
||||
PPH_PLUGIN_INFORMATION info;
|
||||
PH_SETTING_CREATE settings[] =
|
||||
{
|
||||
{ StringSettingType, SETTING_NAME_ASM_TREE_LIST_COLUMNS, L"" },
|
||||
{ IntegerSettingType, SETTING_NAME_DOT_NET_CATEGORY_INDEX, L"5" },
|
||||
{ StringSettingType, SETTING_NAME_DOT_NET_COUNTERS_COLUMNS, L"" },
|
||||
{ IntegerSettingType, SETTING_NAME_DOT_NET_SHOW_BYTE_SIZE, L"1" }
|
||||
};
|
||||
|
||||
PluginInstance = PhRegisterPlugin(PLUGIN_NAME, Instance, &info);
|
||||
|
||||
if (!PluginInstance)
|
||||
return FALSE;
|
||||
|
||||
info->DisplayName = L".NET Tools";
|
||||
info->Author = L"dmex, wj32";
|
||||
info->Description = L"Adds .NET performance counters, assembly information, thread stack support, and more.";
|
||||
info->Url = L"https://wj32.org/processhacker/forums/viewtopic.php?t=1111";
|
||||
info->HasOptions = FALSE;
|
||||
|
||||
PhRegisterCallback(
|
||||
PhGetPluginCallback(PluginInstance, PluginCallbackLoad),
|
||||
LoadCallback,
|
||||
NULL,
|
||||
&PluginLoadCallbackRegistration
|
||||
);
|
||||
PhRegisterCallback(
|
||||
PhGetPluginCallback(PluginInstance, PluginCallbackUnload),
|
||||
UnloadCallback,
|
||||
NULL,
|
||||
&PluginUnloadCallbackRegistration
|
||||
);
|
||||
PhRegisterCallback(
|
||||
PhGetPluginCallback(PluginInstance, PluginCallbackShowOptions),
|
||||
ShowOptionsCallback,
|
||||
NULL,
|
||||
&PluginShowOptionsCallbackRegistration
|
||||
);
|
||||
//PhRegisterCallback(
|
||||
// PhGetPluginCallback(PluginInstance, PluginCallbackMenuItem),
|
||||
// MenuItemCallback,
|
||||
// NULL,
|
||||
// &PluginMenuItemCallbackRegistration
|
||||
// );
|
||||
PhRegisterCallback(
|
||||
PhGetPluginCallback(PluginInstance, PluginCallbackTreeNewMessage),
|
||||
TreeNewMessageCallback,
|
||||
NULL,
|
||||
&PluginTreeNewMessageCallbackRegistration
|
||||
);
|
||||
PhRegisterCallback(
|
||||
PhGetPluginCallback(PluginInstance, PluginCallbackPhSvcRequest),
|
||||
PhSvcRequestCallback,
|
||||
NULL,
|
||||
&PluginPhSvcRequestCallbackRegistration
|
||||
);
|
||||
|
||||
//PhRegisterCallback(
|
||||
// PhGetGeneralCallback(GeneralCallbackMainWindowShowing),
|
||||
// MainWindowShowingCallback,
|
||||
// NULL,
|
||||
// &MainWindowShowingCallbackRegistration
|
||||
// );
|
||||
PhRegisterCallback(
|
||||
PhGetGeneralCallback(GeneralCallbackProcessPropertiesInitializing),
|
||||
ProcessPropertiesInitializingCallback,
|
||||
NULL,
|
||||
&ProcessPropertiesInitializingCallbackRegistration
|
||||
);
|
||||
//PhRegisterCallback(
|
||||
// PhGetGeneralCallback(GeneralCallbackProcessMenuInitializing),
|
||||
// ProcessMenuInitializingCallback,
|
||||
// NULL,
|
||||
// &ProcessMenuInitializingCallbackRegistration
|
||||
// );
|
||||
//PhRegisterCallback(
|
||||
// PhGetGeneralCallback(GeneralCallbackThreadMenuInitializing),
|
||||
// ThreadMenuInitializingCallback,
|
||||
// NULL,
|
||||
// &ThreadMenuInitializingCallbackRegistration
|
||||
// );
|
||||
//PhRegisterCallback(
|
||||
// PhGetGeneralCallback(GeneralCallbackModuleMenuInitializing),
|
||||
// ModuleMenuInitializingCallback,
|
||||
// NULL,
|
||||
// &ModuleMenuInitializingCallbackRegistration
|
||||
// );
|
||||
//PhRegisterCallback(
|
||||
// PhGetGeneralCallback(GeneralCallbackProcessTreeNewInitializing),
|
||||
// ProcessTreeNewInitializingCallback,
|
||||
// NULL,
|
||||
// &ProcessTreeNewInitializingCallbackRegistration
|
||||
// );
|
||||
PhRegisterCallback(
|
||||
PhGetGeneralCallback(GeneralCallbackThreadTreeNewInitializing),
|
||||
ThreadTreeNewInitializingCallback,
|
||||
NULL,
|
||||
&ThreadTreeNewInitializingCallbackRegistration
|
||||
);
|
||||
PhRegisterCallback(
|
||||
PhGetGeneralCallback(GeneralCallbackThreadTreeNewUninitializing),
|
||||
ThreadTreeNewUninitializingCallback,
|
||||
NULL,
|
||||
&ThreadTreeNewUninitializingCallbackRegistration
|
||||
);
|
||||
PhRegisterCallback(
|
||||
PhGetGeneralCallback(GeneralCallbackThreadStackControl),
|
||||
ThreadStackControlCallback,
|
||||
NULL,
|
||||
&ThreadStackControlCallbackRegistration
|
||||
);
|
||||
|
||||
PhPluginSetObjectExtension(
|
||||
PluginInstance,
|
||||
EmThreadItemType,
|
||||
sizeof(DN_THREAD_ITEM),
|
||||
ThreadItemCreateCallback,
|
||||
ThreadItemDeleteCallback
|
||||
);
|
||||
InitializeTreeNewObjectExtensions();
|
||||
|
||||
PhAddSettings(settings, ARRAYSIZE(settings));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
944
plugins/DotNetTools/perfpage.c
Normal file
944
plugins/DotNetTools/perfpage.c
Normal file
@@ -0,0 +1,944 @@
|
||||
/*
|
||||
* Process Hacker .NET Tools -
|
||||
* .NET Performance property page
|
||||
*
|
||||
* Copyright (C) 2011-2015 wj32
|
||||
* Copyright (C) 2015 dmex
|
||||
*
|
||||
* This file is part of Process Hacker.
|
||||
*
|
||||
* Process Hacker is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Process Hacker is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#include "dn.h"
|
||||
#include "clr\perfcounterdefs.h"
|
||||
|
||||
typedef enum _DOTNET_CATEGORY
|
||||
{
|
||||
// .NET CLR Exceptions (Runtime statistics on CLR exception handling)
|
||||
DOTNET_CATEGORY_EXCEPTIONS,
|
||||
|
||||
// .NET CLR Interop (Stats for CLR interop)
|
||||
DOTNET_CATEGORY_INTEROP,
|
||||
|
||||
// .NET CLR Jit (Stats for CLR Jit)
|
||||
DOTNET_CATEGORY_JIT,
|
||||
|
||||
// .NET CLR Loading (Statistics for CLR Class Loader)
|
||||
DOTNET_CATEGORY_LOADING,
|
||||
|
||||
// .NET CLR LocksAndThreads (Stats for CLR Locks and Threads)
|
||||
DOTNET_CATEGORY_LOCKSANDTHREADS,
|
||||
|
||||
// .NET CLR Memory (Counters for CLR Garbage Collected heap)
|
||||
DOTNET_CATEGORY_MEMORY,
|
||||
|
||||
// .NET CLR Remoting (Stats for CLR Remoting)
|
||||
DOTNET_CATEGORY_REMOTING,
|
||||
|
||||
// .NET CLR Security (Stats for CLR Security)
|
||||
DOTNET_CATEGORY_SECURITY
|
||||
} DOTNET_CATEGORY;
|
||||
|
||||
typedef struct _PERFPAGE_CONTEXT
|
||||
{
|
||||
HWND WindowHandle;
|
||||
PPH_PROCESS_ITEM ProcessItem;
|
||||
BOOLEAN Enabled;
|
||||
|
||||
HWND AppDomainsLv;
|
||||
HWND CountersLv;
|
||||
HWND CategoriesCb;
|
||||
|
||||
BOOLEAN ControlBlockValid;
|
||||
BOOLEAN ClrV4;
|
||||
BOOLEAN IsWow64;
|
||||
BOOLEAN ShowByteSize;
|
||||
DOTNET_CATEGORY CategoryIndex;
|
||||
HANDLE ProcessHandle;
|
||||
HANDLE BlockTableHandle;
|
||||
PVOID BlockTableAddress;
|
||||
|
||||
PH_CALLBACK_REGISTRATION ProcessesUpdatedCallbackRegistration;
|
||||
} PERFPAGE_CONTEXT, *PPERFPAGE_CONTEXT;
|
||||
|
||||
static PWSTR DotNetCategoryStrings[] =
|
||||
{
|
||||
L".NET CLR Exceptions",
|
||||
L".NET CLR Interop",
|
||||
L".NET CLR Jit",
|
||||
L".NET CLR Loading",
|
||||
L".NET CLR LocksAndThreads",
|
||||
L".NET CLR Memory",
|
||||
L".NET CLR Remoting",
|
||||
L".NET CLR Security"
|
||||
};
|
||||
|
||||
PPH_STRING FormatByteValue(
|
||||
_In_ PPERFPAGE_CONTEXT Context,
|
||||
_In_ ULONG64 Value
|
||||
)
|
||||
{
|
||||
if (Context->ShowByteSize)
|
||||
return PhaFormatUInt64(Value, TRUE);
|
||||
|
||||
return PhaFormatSize(Value, -1);
|
||||
}
|
||||
|
||||
VOID NTAPI ProcessesUpdatedCallback(
|
||||
_In_opt_ PVOID Parameter,
|
||||
_In_opt_ PVOID Context
|
||||
)
|
||||
{
|
||||
PPERFPAGE_CONTEXT context = Context;
|
||||
|
||||
if (context->WindowHandle)
|
||||
{
|
||||
PostMessage(context->WindowHandle, MSG_UPDATE, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
VOID UpdateCategoryValues(
|
||||
_In_ HWND hwndDlg,
|
||||
_In_ PPERFPAGE_CONTEXT Context
|
||||
)
|
||||
{
|
||||
ListView_DeleteAllItems(Context->CountersLv);
|
||||
|
||||
switch (Context->CategoryIndex)
|
||||
{
|
||||
case DOTNET_CATEGORY_EXCEPTIONS:
|
||||
{
|
||||
// This counter displays the total number of exceptions thrown since the start of the application. These include both .NET exceptions and unmanaged exceptions that get converted into .NET exceptions e.g. null pointer reference exception in unmanaged code would get re-thrown in managed code as a .NET System.NullReferenceException; this counter includes both handled and unhandled exceptions.Exceptions that are re-thrown would get counted again. Exceptions should only occur in rare situations and not in the normal control flow of the program.
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Exceps Thrown", NULL);
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Filters Executed", NULL);
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Finallys Executed", NULL);
|
||||
|
||||
// Reserved for future use.
|
||||
//PhAddListViewItem(Context->CountersLv, MAXINT, L" Delta from throw to catch site on stack", NULL);
|
||||
|
||||
// # of Exceps Thrown / sec
|
||||
// This counter displays the number of exceptions thrown per second.These include both.NET exceptions and unmanaged exceptions that get converted into.NET exceptions e.g.null pointer reference exception in unmanaged code would get re - thrown in managed code as a.NET System.NullReferenceException; this counter includes both handled and unhandled exceptions.Exceptions should only occur in rare situations and not in the normal control flow of the program; this counter was designed as an indicator of potential performance problems due to large(> 100s) rate of exceptions thrown.This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval.
|
||||
|
||||
// # of Filters / sec
|
||||
// This counter displays the number of.NET exception filters executed per second.An exception filter evaluates whether an exception should be handled or not.This counter tracks the rate of exception filters evaluated; irrespective of whether the exception was handled or not.This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval.
|
||||
|
||||
// # of Finallys / sec
|
||||
// This counter displays the number of finally blocks executed per second.A finally block is guaranteed to be executed regardless of how the try block was exited.Only the finally blocks that are executed for an exception are counted; finally blocks on normal code paths are not counted by this counter.This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval.
|
||||
|
||||
// Throw To Catch Depth / sec
|
||||
// This counter displays the number of stack frames traversed from the frame that threw the.NET exception to the frame that handled the exception per second.This counter resets to 0 when an exception handler is entered; so nested exceptions would show the handler to handler stack depth.This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval.* /
|
||||
}
|
||||
break;
|
||||
case DOTNET_CATEGORY_INTEROP:
|
||||
{
|
||||
// This counter displays the current number of Com-Callable-Wrappers (CCWs). A CCW is a proxy for the .NET managed object being referenced from unmanaged COM client(s). This counter was designed to indicate the number of managed objects being referenced by unmanaged COM code.
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"# of CCWs", NULL);
|
||||
|
||||
// This counter displays the current number of stubs created by the CLR. Stubs are responsible for marshalling arguments and return values from managed to unmanaged code and vice versa; during a COM Interop call or PInvoke call.
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Stubs", NULL);
|
||||
|
||||
// This counter displays the total number of times arguments and return values have been marshaled from managed to unmanaged code and vice versa since the start of the application. This counter is not incremented if the stubs are inlined. (Stubs are responsible for marshalling arguments and return values). Stubs usually get inlined if the marshalling overhead is small.
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Marshalling", NULL);
|
||||
|
||||
// Reserved for future use.
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"# of TLB imports / sec", NULL);
|
||||
|
||||
// Reserved for future use.
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"# of TLB exports / sec", NULL);
|
||||
}
|
||||
break;
|
||||
case DOTNET_CATEGORY_JIT:
|
||||
{
|
||||
// This counter displays the total number of methods compiled Just-In-Time (JIT) by the CLR JIT compiler since the start of the application. This counter does not include the pre-jitted methods.
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Methods Jitted", NULL);
|
||||
|
||||
// This counter displays the total IL bytes jitted since the start of the application. This counter is exactly equivalent to the "Total # of IL Bytes Jitted" counter.
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"# of IL Bytes Jitted", NULL);
|
||||
|
||||
// This counter displays the total IL bytes jitted since the start of the application. This counter is exactly equivalent to the "# of IL Bytes Jitted" counter.
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"Total # of IL Bytes Jitted", NULL);
|
||||
|
||||
// This counter displays the peak number of methods the JIT compiler has failed to JIT since the start of the application. This failure can occur if the IL cannot be verified or if there was an internal error in the JIT compiler.
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"Jit Failures", NULL);
|
||||
|
||||
// This counter displays the percentage of elapsed time spent in JIT compilation since the last JIT compilation phase. This counter is updated at the end of every JIT compilation phase. A JIT compilation phase is the phase when a method and its dependencies are being compiled.
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"% Time in Jit", NULL);
|
||||
|
||||
// IL Bytes Jitted / sec
|
||||
// This counter displays the rate at which IL bytes are jitted per second. This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval.
|
||||
}
|
||||
break;
|
||||
case DOTNET_CATEGORY_LOADING:
|
||||
{
|
||||
// This counter displays the current number of classes loaded in all Assemblies.
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"Current Classes Loaded", NULL);
|
||||
|
||||
// This counter displays the cumulative number of classes loaded in all Assemblies since the start of this application.
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"Total Classes Loaded", NULL);
|
||||
|
||||
// This counter displays the current number of AppDomains loaded in this application. AppDomains (application domains) provide a secure and versatile unit of processing that the CLR can use to provide isolation between applications running in the same process.
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"Current Appdomains", NULL);
|
||||
|
||||
// This counter displays the peak number of AppDomains loaded since the start of this application. AppDomains (application domains) provide a secure and versatile unit of processing that the CLR can use to provide isolation between applications running in the same process.
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"Total Appdomains", NULL);
|
||||
|
||||
// This counter displays the current number of Assemblies loaded across all AppDomains in this application. If the Assembly is loaded as domain - neutral from multiple AppDomains then this counter is incremented once only. Assemblies can be loaded as domain - neutral when their code can be shared by all AppDomains or they can be loaded as domain - specific when their code is private to the AppDomain.
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"Current Assemblies", NULL);
|
||||
|
||||
// This counter displays the total number of Assemblies loaded since the start of this application. If the Assembly is loaded as domain - neutral from multiple AppDomains then this counter is incremented once only. Assemblies can be loaded as domain - neutral when their code can be shared by all AppDomains or they can be loaded as domain - specific when their code is private to the AppDomain.
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"Total Assemblies", NULL);
|
||||
|
||||
// Reserved for future use.
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"Assembly Search Length", NULL);
|
||||
|
||||
// This counter displays the peak number of classes that have failed to load since the start of the application.These load failures could be due to many reasons like inadequate security or illegal format.Full details can be found in the profiling services help.
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"Total # of Load Failures", NULL);
|
||||
|
||||
// This counter displays the current size(in bytes) of the memory committed by the class loader across all AppDomains. (Committed memory is the physical memory for which space has been reserved on the disk paging file.)
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"Bytes in Loader Heap", NULL);
|
||||
|
||||
// This counter displays the total number of AppDomains unloaded since the start of the application. If an AppDomain is loaded and unloaded multiple times this counter would count each of those unloads as separate.
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"Total Appdomains Unloaded", NULL);
|
||||
|
||||
// Reserved for future use.
|
||||
//PhAddListViewItem(Context->CountersLv, MAXINT, L"% Time Loading", NULL);
|
||||
|
||||
// Rate of Load Failures
|
||||
// This counter displays the number of classes that failed to load per second. This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval. These load failures could be due to many reasons like inadequate security or illegal format. Full details can be found in the profiling services help.
|
||||
|
||||
// Rate of appdomains unloaded
|
||||
// This counter displays the number of AppDomains unloaded per second.This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval.
|
||||
|
||||
// Rate of Classes Loaded
|
||||
// This counter displays the number of classes loaded per second in all Assemblies.This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval.
|
||||
|
||||
// Rate of appdomains
|
||||
// This counter displays the number of AppDomains loaded per second.AppDomains(application domains) provide a secure and versatile unit of processing that the CLR can use to provide isolation between applications running in the same process.This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval.
|
||||
|
||||
// Rate of Assemblies
|
||||
// This counter displays the number of Assemblies loaded across all AppDomains per second.If the Assembly is loaded as domain - neutral from multiple AppDomains then this counter is incremented once only.Assemblies can be loaded as domain - neutral when their code can be shared by all AppDomains or they can be loaded as domain - specific when their code is private to the AppDomain.This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval.
|
||||
}
|
||||
break;
|
||||
case DOTNET_CATEGORY_LOCKSANDTHREADS:
|
||||
{
|
||||
// This counter displays the total number of times threads in the CLR have attempted to acquire a managed lock unsuccessfully. Managed locks can be acquired in many ways; by the "lock" statement in C# or by calling System.Monitor.Enter or by using MethodImplOptions.Synchronized custom attribute.
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"Total # of Contentions", NULL);
|
||||
|
||||
// This counter displays the total number of threads currently waiting to acquire some managed lock in the application. This counter is not an average over time; it displays the last observed value.
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"Current Queue Length", NULL);
|
||||
|
||||
// This counter displays the total number of threads that waited to acquire some managed lock since the start of the application.
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"Queue Length Peak", NULL);
|
||||
|
||||
// This counter displays the number of current.NET thread objects in the application.A.NET thread object is created either by new System.Threading.Thread or when an unmanaged thread enters the managed environment. This counters maintains the count of both running and stopped threads. This counter is not an average over time; it just displays the last observed value.
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Current Logical Threads", NULL);
|
||||
|
||||
// This counter displays the number of native OS threads created and owned by the CLR to act as underlying threads for .NET thread objects. This counters value does not include the threads used by the CLR in its internal operations; it is a subset of the threads in the OS process.
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Current Physical Threads", NULL);
|
||||
|
||||
// This counter displays the number of threads that are currently recognized by the CLR; they have a corresponding .NET thread object associated with them. These threads are not created by the CLR; they are created outside the CLR but have since run inside the CLR at least once. Only unique threads are tracked; threads with same thread ID re-entering the CLR or recreated after thread exit are not counted twice.
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Current Recognized Threads", NULL);
|
||||
|
||||
// This counter displays the total number of threads that have been recognized by the CLR since the start of this application; these threads have a corresponding .NET thread object associated with them. These threads are not created by the CLR; they are created outside the CLR but have since run inside the CLR at least once. Only unique threads are tracked; threads with same thread ID re-entering the CLR or recreated after thread exit are not counted twice.
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Total Recognized Threads", NULL);
|
||||
|
||||
// Contention Rate / sec
|
||||
// Rate at which threads in the runtime attempt to acquire a managed lock unsuccessfully.Managed locks can be acquired in many ways; by the "lock" statement in C# or by calling System.Monitor.Enter or by using MethodImplOptions.Synchronized custom attribute.
|
||||
|
||||
// Queue Length / sec
|
||||
// This counter displays the number of threads per second waiting to acquire some lock in the application. This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval.
|
||||
|
||||
// rate of recognized threads / sec
|
||||
// This counter displays the number of threads per second that have been recognized by the CLR; these threads have a corresponding .NET thread object associated with them. These threads are not created by the CLR; they are created outside the CLR but have since run inside the CLR at least once. Only unique threads are tracked; threads with same thread ID re-entering the CLR or recreated after thread exit are not counted twice. This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval.
|
||||
}
|
||||
break;
|
||||
case DOTNET_CATEGORY_MEMORY:
|
||||
{
|
||||
// This counter displays the number of times the generation 0 objects (youngest; most recently allocated) are garbage collected (Gen 0 GC) since the start of the application. Gen 0 GC occurs when the available memory in generation 0 is not sufficient to satisfy an allocation request. This counter is incremented at the end of a Gen 0 GC. Higher generation GCs include all lower generation GCs.This counter is explicitly incremented when a higher generation (Gen 1 or Gen 2) GC occurs. _Global_ counter value is not accurate and should be ignored. This counter displays the last observed value.
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"# Gen 0 Collections", NULL);
|
||||
|
||||
// This counter displays the number of times the generation 1 objects are garbage collected since the start of the application. The counter is incremented at the end of a Gen 1 GC. Higher generation GCs include all lower generation GCs. This counter is explicitly incremented when a higher generation (Gen 2) GC occurs. _Global_ counter value is not accurate and should be ignored. This counter displays the last observed value.
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"# Gen 1 Collections", NULL);
|
||||
|
||||
// This counter displays the number of times the generation 2 objects(older) are garbage collected since the start of the application.The counter is incremented at the end of a Gen 2 GC(also called full GC)._Global_ counter value is not accurate and should be ignored.This counter displays the last observed value.
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"# Gen 2 Collections", NULL);
|
||||
|
||||
// This counter displays the bytes of memory that survive garbage collection(GC) and are promoted from generation 0 to generation 1; objects that are promoted just because they are waiting to be finalized are not included in this counter.This counter displays the value observed at the end of the last GC; its not a cumulative counter.
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"Promoted Memory from Gen 0", NULL);
|
||||
|
||||
// This counter displays the bytes of memory that survive garbage collection(GC) and are promoted from generation 1 to generation 2; objects that are promoted just because they are waiting to be finalized are not included in this counter.This counter displays the value observed at the end of the last GC; its not a cumulative counter.This counter is reset to 0 if the last GC was a Gen 0 GC only.
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"Promoted Memory from Gen 1", NULL);
|
||||
|
||||
// This counter displays the bytes of memory that are promoted from generation 0 to generation 1 just because they are waiting to be finalized.This counter displays the value observed at the end of the last GC; its not a cumulative counter.
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"Promoted Finalization-Memory from Gen 0", NULL);
|
||||
|
||||
// Reserved for future use.
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"Process ID", NULL);
|
||||
|
||||
// This counter displays the maximum bytes that can be allocated in generation 0 (Gen 0); its does not indicate the current number of bytes allocated in Gen 0. A Gen 0 GC is triggered when the allocations since the last GC exceed this size.The Gen 0 size is tuned by the Garbage Collector and can change during the execution of the application.At the end of a Gen 0 collection the size of the Gen 0 heap is infact 0 bytes; this counter displays the size(in bytes) of allocations that would trigger the next Gen 0 GC.This counter is updated at the end of a GC; its not updated on every allocation.
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"Gen 0 Heap Size", NULL);
|
||||
|
||||
// This counter displays the current number of bytes in generation 1 (Gen 1); this counter does not display the maximum size of Gen 1. Objects are not directly allocated in this generation; they are promoted from previous Gen 0 GCs.This counter is updated at the end of a GC; its not updated on every allocation.
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"Gen 1 Heap Size", NULL);
|
||||
|
||||
// This counter displays the current number of bytes in generation 2 (Gen 2).Objects are not directly allocated in this generation; they are promoted from Gen 1 during previous Gen 1 GCs.This counter is updated at the end of a GC; its not updated on every allocation.
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"Gen 2 Heap Size", NULL);
|
||||
|
||||
// This counter displays the current size of the Large Object Heap in bytes.Objects greater than 20 KBytes are treated as large objects by the Garbage Collector and are directly allocated in a special heap; they are not promoted through the generations.This counter is updated at the end of a GC; its not updated on every allocation.
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"Large Object Heap Size", NULL);
|
||||
|
||||
// This counter displays the number of garbage collected objects that survive a collection because they are waiting to be finalized.If these objects hold references to other objects then those objects also survive but are not counted by this counter; the "Promoted Finalization-Memory from Gen 0" and "Promoted Finalization-Memory from Gen 1" counters represent all the memory that survived due to finalization.This counter is not a cumulative counter; its updated at the end of every GC with count of the survivors during that particular GC only.This counter was designed to indicate the extra overhead that the application might incur because of finalization.
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"Finalization Survivors", NULL);
|
||||
|
||||
// This counter displays the current number of GC Handles in use.GCHandles are handles to resources external to the CLR and the managed environment.Handles occupy small amounts of memory in the GCHeap but potentially expensive unmanaged resources.
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"# GC Handles", NULL);
|
||||
|
||||
// This counter displays the peak number of times a garbage collection was performed because of an explicit call to GC.Collect. Its a good practice to let the GC tune the frequency of its collections.
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"# Induced GC", NULL);
|
||||
|
||||
// % Time in GC is the percentage of elapsed time that was spent in performing a garbage collection(GC) since the last GC cycle. This counter is usually an indicator of the work done by the Garbage Collector on behalf of the application to collect and compact memory.This counter is updated only at the end of every GC and the counter value reflects the last observed value; its not an average.
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"% Time in GC", NULL);
|
||||
|
||||
// This counter is the sum of four other counters; Gen 0 Heap Size; Gen 1 Heap Size; Gen 2 Heap Size and the Large Object Heap Size. This counter indicates the current memory allocated in bytes on the GC Heaps.
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"# Bytes in all Heaps", NULL);
|
||||
|
||||
// This counter displays the amount of virtual memory(in bytes) currently committed by the Garbage Collector. (Committed memory is the physical memory for which space has been reserved on the disk paging file).
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"# Total Committed Bytes", NULL);
|
||||
|
||||
// This counter displays the amount of virtual memory(in bytes) currently reserved by the Garbage Collector. (Reserved memory is the virtual memory space reserved for the application but no disk or main memory pages have been used.)
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"# Total Reserved Bytes", NULL);
|
||||
|
||||
// This counter displays the number of pinned objects encountered in the last GC. This counter tracks the pinned objects only in the heaps that were garbage collected e.g. A Gen 0 GC would cause enumeration of pinned objects in the generation 0 heap only. A pinned object is one that the Garbage Collector cannot move in memory.
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Pinned Objects", NULL);
|
||||
|
||||
// This counter displays the current number of sync blocks in use. Sync blocks are per-object data structures allocated for storing synchronization information. Sync blocks hold weak references to managed objects and need to be scanned by the Garbage Collector. Sync blocks are not limited to storing synchronization information and can also store COM interop metadata. This counter was designed to indicate performance problems with heavy use of synchronization primitives.
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"# of Sink Blocks in use", NULL);
|
||||
|
||||
// Reserved for future use.
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"Total Bytes Allocated (since start)", NULL);
|
||||
|
||||
// Reserved for future use.
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"Total Bytes Allocated for Large Objects (since start)", NULL);
|
||||
|
||||
// Gen 0 Promoted Bytes / Sec
|
||||
// This counter displays the bytes per second that are promoted from generation 0 (youngest)to generation 1; objects that are promoted just because they are waiting to be finalized are not included in this counter.Memory is promoted when it survives a garbage collection.This counter was designed as an indicator of relatively long - lived objects being created per sec.This counter displays the difference between the values observed in the last two samples divided by the duration of the sample interval.
|
||||
|
||||
// Gen 1 Promoted Bytes / Sec
|
||||
// This counter displays the bytes per second that are promoted from generation 1 to generation 2 (oldest); objects that are promoted just because they are waiting to be finalized are not included in this counter.Memory is promoted when it survives a garbage collection.Nothing is promoted from generation 2 since it is the oldest.This counter was designed as an indicator of very long - lived objects being created per sec.This counter displays the difference between the values observed in the last two samples divided by the duration of the sample interval.
|
||||
|
||||
// Promoted Finalization - Memory from Gen 1
|
||||
// This counter displays the bytes of memory that are promoted from generation 1 to generation 2 just because they are waiting to be finalized.This counter displays the value observed at the end of the last GC; its not a cumulative counter.This counter is reset to 0 if the last GC was a Gen 0 GC only.
|
||||
|
||||
// Allocated Bytes / sec
|
||||
// This counter displays the rate of bytes per second allocated on the GC Heap.This counter is updated at the end of every GC; not at each allocation.This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval.
|
||||
}
|
||||
break;
|
||||
case DOTNET_CATEGORY_REMOTING:
|
||||
{
|
||||
// This counter displays the total number of remote procedure calls invoked since the start of this application. A remote procedure call is a call on any object outside the callers AppDomain.
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"Total Remote Calls", NULL);
|
||||
|
||||
// This counter displays the total number of remoting channels registered across all AppDomains since the start of the application. Channels are used to transport messages to and from remote objects.
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"Channels", NULL);
|
||||
|
||||
// This counter displays the total number of remoting proxy objects created in this process since the start of the process. Proxy object acts as a representative of the remote objects and ensures that all calls made on the proxy are forwarded to the correct remote object instance.
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"Context Proxies", NULL);
|
||||
|
||||
// This counter displays the current number of context-bound classes loaded. Classes that can be bound to a context are called context-bound classes; context-bound classes are marked with Context Attributes which provide usage rules for synchronization; thread affinity; transactions etc.
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"Context-Bound Classes Loaded", NULL);
|
||||
|
||||
// This counter displays the current number of remoting contexts in the application. A context is a boundary containing a collection of objects with the same usage rules like synchronization; thread affinity; transactions etc.
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"Contexts", NULL);
|
||||
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"# of context bound objects allocated", NULL);
|
||||
|
||||
// Remote Calls / sec
|
||||
// This counter displays the number of remote procedure calls invoked per second. A remote procedure call is a call on any object outside the callers AppDomain. This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval.
|
||||
|
||||
// Context - Bound Objects Alloc / sec
|
||||
// This counter displays the number of context - bound objects allocated per second. Instances of classes that can be bound to a context are called context - bound objects; context - bound classes are marked with Context Attributes which provide usage rules for synchronization; thread affinity; transactions etc.This counter is not an average over time; it displays the difference between the values observed in the last two samples divided by the duration of the sample interval.
|
||||
}
|
||||
break;
|
||||
case DOTNET_CATEGORY_SECURITY:
|
||||
{
|
||||
// This counter displays the total number of runtime Code Access Security(CAS) checks performed since the start of the application. Runtime CAS checks are performed when a caller makes a call to a callee demanding a particular permission; the runtime check is made on every call by the caller; the check is done by examining the current thread stack of the caller. This counter used together with "Stack Walk Depth" is indicative of performance penalty for security checks.
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"Total Runtime Checks", NULL);
|
||||
|
||||
// This counter displays the total number of linktime Code Access Security(CAS) checks since the start of the application. Linktime CAS checks are performed when a caller makes a call to a callee demanding a particular permission at JIT compile time; linktime check is performed once per caller. This count is not indicative of serious performance issues; its indicative of the security system activity.
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"# Link Time Checks", NULL);
|
||||
|
||||
// This counter displays the percentage of elapsed time spent in performing runtime Code Access Security(CAS) checks since the last such check. CAS allows code to be trusted to varying degrees and enforces these varying levels of trust depending on code identity. This counter is updated at the end of a runtime security check; it represents the last observed value; its not an average.
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"% Time in RT checks", NULL);
|
||||
|
||||
// This counter displays the depth of the stack during that last runtime Code Access Security check.Runtime Code Access Security check is performed by crawling the stack. This counter is not an average; it just displays the last observed value.
|
||||
PhAddListViewItem(Context->CountersLv, MAXINT, L"Stack Walk Depth", NULL);
|
||||
|
||||
// % Time Sig.Authenticating
|
||||
// Reserved for future use.
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
VOID AddProcessAppDomains(
|
||||
_In_ HWND hwndDlg,
|
||||
_In_ PPERFPAGE_CONTEXT Context
|
||||
)
|
||||
{
|
||||
SendMessage(Context->AppDomainsLv, WM_SETREDRAW, FALSE, 0);
|
||||
ListView_DeleteAllItems(Context->AppDomainsLv);
|
||||
|
||||
if (Context->ClrV4)
|
||||
{
|
||||
PPH_LIST processAppDomains = QueryDotNetAppDomainsForPid_V4(
|
||||
Context->IsWow64,
|
||||
Context->ProcessHandle,
|
||||
Context->ProcessItem->ProcessId
|
||||
);
|
||||
|
||||
for (ULONG i = 0; i < processAppDomains->Count; i++)
|
||||
{
|
||||
PhAddListViewItem(Context->AppDomainsLv, MAXINT, processAppDomains->Items[i], NULL);
|
||||
PhFree(processAppDomains->Items[i]);
|
||||
}
|
||||
|
||||
PhDereferenceObject(processAppDomains);
|
||||
}
|
||||
else
|
||||
{
|
||||
PPH_LIST processAppDomains = QueryDotNetAppDomainsForPid_V2(
|
||||
Context->IsWow64,
|
||||
Context->ProcessHandle,
|
||||
Context->ProcessItem->ProcessId
|
||||
);
|
||||
|
||||
for (ULONG i = 0; i < processAppDomains->Count; i++)
|
||||
{
|
||||
PhAddListViewItem(Context->AppDomainsLv, MAXINT, processAppDomains->Items[i], NULL);
|
||||
PhFree(processAppDomains->Items[i]);
|
||||
}
|
||||
|
||||
PhDereferenceObject(processAppDomains);
|
||||
}
|
||||
|
||||
SendMessage(Context->AppDomainsLv, WM_SETREDRAW, TRUE, 0);
|
||||
}
|
||||
|
||||
VOID UpdateCounterData(
|
||||
_In_ HWND hwndDlg,
|
||||
_In_ PPERFPAGE_CONTEXT Context
|
||||
)
|
||||
{
|
||||
PVOID perfStatBlock = NULL;
|
||||
Perf_GC dotNetPerfGC;
|
||||
Perf_Contexts dotNetPerfContext;
|
||||
Perf_Interop dotNetPerfInterop;
|
||||
Perf_Loading dotNetPerfLoading;
|
||||
Perf_Excep dotNetPerfExcep;
|
||||
Perf_LocksAndThreads dotNetPerfLocksAndThreads;
|
||||
Perf_Jit dotNetPerfJit;
|
||||
Perf_Security dotNetPerfSecurity;
|
||||
|
||||
if (Context->ClrV4)
|
||||
{
|
||||
perfStatBlock = GetPerfIpcBlock_V4(
|
||||
Context->IsWow64,
|
||||
Context->BlockTableAddress
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
perfStatBlock = GetPerfIpcBlock_V2(
|
||||
Context->IsWow64,
|
||||
Context->BlockTableAddress
|
||||
);
|
||||
}
|
||||
|
||||
if (!perfStatBlock)
|
||||
return;
|
||||
|
||||
if (Context->IsWow64)
|
||||
{
|
||||
PerfCounterIPCControlBlock_Wow64* perfBlock = perfStatBlock;
|
||||
Perf_GC_Wow64 dotNetPerfGC_Wow64 = perfBlock->GC;
|
||||
Perf_Loading_Wow64 dotNetPerfLoading_Wow64 = perfBlock->Loading;
|
||||
Perf_Security_Wow64 dotNetPerfSecurity_Wow64 = perfBlock->Security;
|
||||
|
||||
// Thunk the Wow64 structures into their 64bit versions (or 32bit version on x86).
|
||||
|
||||
dotNetPerfGC.cGenCollections[0] = dotNetPerfGC_Wow64.cGenCollections[0];
|
||||
dotNetPerfGC.cGenCollections[1] = dotNetPerfGC_Wow64.cGenCollections[1];
|
||||
dotNetPerfGC.cGenCollections[2] = dotNetPerfGC_Wow64.cGenCollections[2];
|
||||
dotNetPerfGC.cbPromotedMem[0] = dotNetPerfGC_Wow64.cbPromotedMem[0];
|
||||
dotNetPerfGC.cbPromotedMem[1] = dotNetPerfGC_Wow64.cbPromotedMem[1];
|
||||
dotNetPerfGC.cbPromotedFinalizationMem = dotNetPerfGC_Wow64.cbPromotedFinalizationMem;
|
||||
dotNetPerfGC.cProcessID = dotNetPerfGC_Wow64.cProcessID;
|
||||
dotNetPerfGC.cGenHeapSize[0] = dotNetPerfGC_Wow64.cGenHeapSize[0];
|
||||
dotNetPerfGC.cGenHeapSize[1] = dotNetPerfGC_Wow64.cGenHeapSize[1];
|
||||
dotNetPerfGC.cGenHeapSize[2] = dotNetPerfGC_Wow64.cGenHeapSize[2];
|
||||
dotNetPerfGC.cTotalCommittedBytes = dotNetPerfGC_Wow64.cTotalCommittedBytes;
|
||||
dotNetPerfGC.cTotalReservedBytes = dotNetPerfGC_Wow64.cTotalReservedBytes;
|
||||
dotNetPerfGC.cLrgObjSize = dotNetPerfGC_Wow64.cLrgObjSize;
|
||||
dotNetPerfGC.cSurviveFinalize = dotNetPerfGC_Wow64.cSurviveFinalize;
|
||||
dotNetPerfGC.cHandles = dotNetPerfGC_Wow64.cHandles;
|
||||
dotNetPerfGC.cbAlloc = dotNetPerfGC_Wow64.cbAlloc;
|
||||
dotNetPerfGC.cbLargeAlloc = dotNetPerfGC_Wow64.cbLargeAlloc;
|
||||
dotNetPerfGC.cInducedGCs = dotNetPerfGC_Wow64.cInducedGCs;
|
||||
dotNetPerfGC.timeInGC = dotNetPerfGC_Wow64.timeInGC;
|
||||
dotNetPerfGC.timeInGCBase = dotNetPerfGC_Wow64.timeInGCBase;
|
||||
dotNetPerfGC.cPinnedObj = dotNetPerfGC_Wow64.cPinnedObj;
|
||||
dotNetPerfGC.cSinkBlocks = dotNetPerfGC_Wow64.cSinkBlocks;
|
||||
|
||||
dotNetPerfContext = perfBlock->Context;
|
||||
dotNetPerfInterop = perfBlock->Interop;
|
||||
|
||||
dotNetPerfLoading.cClassesLoaded.Current = dotNetPerfLoading_Wow64.cClassesLoaded.Current;
|
||||
dotNetPerfLoading.cClassesLoaded.Total = dotNetPerfLoading_Wow64.cClassesLoaded.Total;
|
||||
dotNetPerfLoading.cAppDomains.Current = dotNetPerfLoading_Wow64.cAppDomains.Current;
|
||||
dotNetPerfLoading.cAppDomains.Total = dotNetPerfLoading_Wow64.cAppDomains.Total;
|
||||
dotNetPerfLoading.cAssemblies.Current = dotNetPerfLoading_Wow64.cAssemblies.Current;
|
||||
dotNetPerfLoading.cAssemblies.Total = dotNetPerfLoading_Wow64.cAssemblies.Total;
|
||||
dotNetPerfLoading.timeLoading = dotNetPerfLoading_Wow64.timeLoading;
|
||||
dotNetPerfLoading.cAsmSearchLen = dotNetPerfLoading_Wow64.cAsmSearchLen;
|
||||
dotNetPerfLoading.cLoadFailures.Total = dotNetPerfLoading_Wow64.cLoadFailures.Total;
|
||||
dotNetPerfLoading.cbLoaderHeapSize = dotNetPerfLoading_Wow64.cbLoaderHeapSize;
|
||||
dotNetPerfLoading.cAppDomainsUnloaded = dotNetPerfLoading_Wow64.cAppDomainsUnloaded;
|
||||
|
||||
dotNetPerfExcep = perfBlock->Excep;
|
||||
dotNetPerfLocksAndThreads = perfBlock->LocksAndThreads;
|
||||
dotNetPerfJit = perfBlock->Jit;
|
||||
|
||||
dotNetPerfSecurity.cTotalRTChecks = dotNetPerfSecurity_Wow64.cTotalRTChecks;
|
||||
dotNetPerfSecurity.timeAuthorize = dotNetPerfSecurity_Wow64.timeAuthorize;
|
||||
dotNetPerfSecurity.cLinkChecks = dotNetPerfSecurity_Wow64.cLinkChecks;
|
||||
dotNetPerfSecurity.timeRTchecks = dotNetPerfSecurity_Wow64.timeRTchecks;
|
||||
dotNetPerfSecurity.timeRTchecksBase = dotNetPerfSecurity_Wow64.timeRTchecksBase;
|
||||
dotNetPerfSecurity.stackWalkDepth = dotNetPerfSecurity_Wow64.stackWalkDepth;
|
||||
}
|
||||
else
|
||||
{
|
||||
PerfCounterIPCControlBlock* perfBlock = perfStatBlock;
|
||||
|
||||
dotNetPerfGC = perfBlock->GC;
|
||||
dotNetPerfContext = perfBlock->Context;
|
||||
dotNetPerfInterop = perfBlock->Interop;
|
||||
dotNetPerfLoading = perfBlock->Loading;
|
||||
dotNetPerfExcep = perfBlock->Excep;
|
||||
dotNetPerfLocksAndThreads = perfBlock->LocksAndThreads;
|
||||
dotNetPerfJit = perfBlock->Jit;
|
||||
dotNetPerfSecurity = perfBlock->Security;
|
||||
}
|
||||
|
||||
switch (Context->CategoryIndex)
|
||||
{
|
||||
case DOTNET_CATEGORY_EXCEPTIONS:
|
||||
{
|
||||
PhSetListViewSubItem(Context->CountersLv, 0, 1, PhaFormatUInt64(dotNetPerfExcep.cThrown.Total, TRUE)->Buffer);
|
||||
PhSetListViewSubItem(Context->CountersLv, 1, 1, PhaFormatUInt64(dotNetPerfExcep.cFiltersExecuted, TRUE)->Buffer);
|
||||
PhSetListViewSubItem(Context->CountersLv, 2, 1, PhaFormatUInt64(dotNetPerfExcep.cFinallysExecuted, TRUE)->Buffer);
|
||||
//PhSetListViewSubItem(Context->CountersLv, 3, 1, PhaFormatUInt64(dotNetPerfExcep.cThrowToCatchStackDepth, TRUE)->Buffer);
|
||||
}
|
||||
break;
|
||||
case DOTNET_CATEGORY_INTEROP:
|
||||
{
|
||||
PhSetListViewSubItem(Context->CountersLv, 0, 1, PhaFormatUInt64(dotNetPerfInterop.cCCW, TRUE)->Buffer);
|
||||
PhSetListViewSubItem(Context->CountersLv, 1, 1, PhaFormatUInt64(dotNetPerfInterop.cStubs, TRUE)->Buffer);
|
||||
PhSetListViewSubItem(Context->CountersLv, 2, 1, PhaFormatUInt64(dotNetPerfInterop.cMarshalling, TRUE)->Buffer);
|
||||
PhSetListViewSubItem(Context->CountersLv, 3, 1, PhaFormatUInt64(dotNetPerfInterop.cTLBImports, TRUE)->Buffer);
|
||||
PhSetListViewSubItem(Context->CountersLv, 4, 1, PhaFormatUInt64(dotNetPerfInterop.cTLBExports, TRUE)->Buffer);
|
||||
}
|
||||
break;
|
||||
case DOTNET_CATEGORY_JIT:
|
||||
{
|
||||
PhSetListViewSubItem(Context->CountersLv, 0, 1, PhaFormatUInt64(dotNetPerfJit.cMethodsJitted, TRUE)->Buffer);
|
||||
PhSetListViewSubItem(Context->CountersLv, 1, 1, FormatByteValue(Context, dotNetPerfJit.cbILJitted.Current)->Buffer);
|
||||
PhSetListViewSubItem(Context->CountersLv, 2, 1, FormatByteValue(Context, dotNetPerfJit.cbILJitted.Total)->Buffer);
|
||||
PhSetListViewSubItem(Context->CountersLv, 3, 1, PhaFormatUInt64(dotNetPerfJit.cJitFailures, TRUE)->Buffer);
|
||||
|
||||
if (dotNetPerfJit.timeInJitBase != 0)
|
||||
{
|
||||
PH_FORMAT format;
|
||||
WCHAR formatBuffer[10];
|
||||
|
||||
// TODO: TimeInJit is always above 100% for some processes ??
|
||||
// SeeAlso: https://github.com/dotnet/coreclr/blob/master/src/gc/gcee.cpp#L324
|
||||
PhInitFormatF(&format, (dotNetPerfJit.timeInJit << 8) * 100 / (FLOAT)(dotNetPerfJit.timeInJitBase << 8), 2);
|
||||
|
||||
if (PhFormatToBuffer(&format, 1, formatBuffer, sizeof(formatBuffer), NULL))
|
||||
PhSetListViewSubItem(Context->CountersLv, 4, 1, formatBuffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
PhSetListViewSubItem(Context->CountersLv, 4, 1, L"0.00");
|
||||
}
|
||||
}
|
||||
break;
|
||||
case DOTNET_CATEGORY_LOADING:
|
||||
{
|
||||
PhSetListViewSubItem(Context->CountersLv, 0, 1, PhaFormatUInt64(dotNetPerfLoading.cClassesLoaded.Current, TRUE)->Buffer);
|
||||
PhSetListViewSubItem(Context->CountersLv, 1, 1, PhaFormatUInt64(dotNetPerfLoading.cClassesLoaded.Total, TRUE)->Buffer);
|
||||
PhSetListViewSubItem(Context->CountersLv, 2, 1, PhaFormatUInt64(dotNetPerfLoading.cAppDomains.Current, TRUE)->Buffer);
|
||||
PhSetListViewSubItem(Context->CountersLv, 3, 1, PhaFormatUInt64(dotNetPerfLoading.cAppDomains.Total, TRUE)->Buffer);
|
||||
PhSetListViewSubItem(Context->CountersLv, 4, 1, PhaFormatUInt64(dotNetPerfLoading.cAssemblies.Current, TRUE)->Buffer);
|
||||
PhSetListViewSubItem(Context->CountersLv, 5, 1, PhaFormatUInt64(dotNetPerfLoading.cAssemblies.Total, TRUE)->Buffer);
|
||||
PhSetListViewSubItem(Context->CountersLv, 6, 1, PhaFormatUInt64(dotNetPerfLoading.cAsmSearchLen, TRUE)->Buffer);
|
||||
PhSetListViewSubItem(Context->CountersLv, 7, 1, PhaFormatUInt64(dotNetPerfLoading.cLoadFailures.Total, TRUE)->Buffer);
|
||||
PhSetListViewSubItem(Context->CountersLv, 8, 1, FormatByteValue(Context, dotNetPerfLoading.cbLoaderHeapSize)->Buffer);
|
||||
PhSetListViewSubItem(Context->CountersLv, 9, 1, PhaFormatUInt64(dotNetPerfLoading.cAppDomainsUnloaded.Total, TRUE)->Buffer);
|
||||
//PhSetListViewSubItem(Context->CountersLv, 10, 1, PhaFormatUInt64(dotNetPerfLoading.timeLoading, TRUE)->Buffer);
|
||||
}
|
||||
break;
|
||||
case DOTNET_CATEGORY_LOCKSANDTHREADS:
|
||||
{
|
||||
PhSetListViewSubItem(Context->CountersLv, 0, 1, PhaFormatUInt64(dotNetPerfLocksAndThreads.cContention.Total, TRUE)->Buffer);
|
||||
PhSetListViewSubItem(Context->CountersLv, 1, 1, PhaFormatUInt64(dotNetPerfLocksAndThreads.cQueueLength.Current, TRUE)->Buffer);
|
||||
PhSetListViewSubItem(Context->CountersLv, 2, 1, PhaFormatUInt64(dotNetPerfLocksAndThreads.cQueueLength.Total, TRUE)->Buffer);
|
||||
PhSetListViewSubItem(Context->CountersLv, 3, 1, PhaFormatUInt64(dotNetPerfLocksAndThreads.cCurrentThreadsLogical, TRUE)->Buffer);
|
||||
PhSetListViewSubItem(Context->CountersLv, 4, 1, PhaFormatUInt64(dotNetPerfLocksAndThreads.cCurrentThreadsPhysical, TRUE)->Buffer);
|
||||
PhSetListViewSubItem(Context->CountersLv, 5, 1, PhaFormatUInt64(dotNetPerfLocksAndThreads.cRecognizedThreads.Current, TRUE)->Buffer);
|
||||
PhSetListViewSubItem(Context->CountersLv, 6, 1, PhaFormatUInt64(dotNetPerfLocksAndThreads.cRecognizedThreads.Total, TRUE)->Buffer);
|
||||
}
|
||||
break;
|
||||
case DOTNET_CATEGORY_MEMORY:
|
||||
{
|
||||
PhSetListViewSubItem(Context->CountersLv, 0, 1, PhaFormatUInt64(dotNetPerfGC.cGenCollections[0], TRUE)->Buffer);
|
||||
PhSetListViewSubItem(Context->CountersLv, 1, 1, PhaFormatUInt64(dotNetPerfGC.cGenCollections[1], TRUE)->Buffer);
|
||||
PhSetListViewSubItem(Context->CountersLv, 2, 1, PhaFormatUInt64(dotNetPerfGC.cGenCollections[2], TRUE)->Buffer);
|
||||
PhSetListViewSubItem(Context->CountersLv, 3, 1, FormatByteValue(Context, dotNetPerfGC.cbPromotedMem[0])->Buffer);
|
||||
PhSetListViewSubItem(Context->CountersLv, 4, 1, FormatByteValue(Context, dotNetPerfGC.cbPromotedMem[1])->Buffer);
|
||||
PhSetListViewSubItem(Context->CountersLv, 5, 1, FormatByteValue(Context, dotNetPerfGC.cbPromotedFinalizationMem)->Buffer);
|
||||
PhSetListViewSubItem(Context->CountersLv, 6, 1, PhaFormatUInt64(dotNetPerfGC.cProcessID, FALSE)->Buffer);
|
||||
PhSetListViewSubItem(Context->CountersLv, 7, 1, FormatByteValue(Context, dotNetPerfGC.cGenHeapSize[0])->Buffer);
|
||||
PhSetListViewSubItem(Context->CountersLv, 8, 1, FormatByteValue(Context, dotNetPerfGC.cGenHeapSize[1])->Buffer);
|
||||
PhSetListViewSubItem(Context->CountersLv, 9, 1, FormatByteValue(Context, dotNetPerfGC.cGenHeapSize[2])->Buffer);
|
||||
PhSetListViewSubItem(Context->CountersLv, 10, 1, FormatByteValue(Context, dotNetPerfGC.cLrgObjSize)->Buffer);
|
||||
PhSetListViewSubItem(Context->CountersLv, 11, 1, PhaFormatUInt64(dotNetPerfGC.cSurviveFinalize, TRUE)->Buffer);
|
||||
PhSetListViewSubItem(Context->CountersLv, 12, 1, PhaFormatUInt64(dotNetPerfGC.cHandles, TRUE)->Buffer);
|
||||
PhSetListViewSubItem(Context->CountersLv, 13, 1, PhaFormatUInt64(dotNetPerfGC.cInducedGCs, TRUE)->Buffer);
|
||||
|
||||
if (dotNetPerfGC.timeInGCBase != 0)
|
||||
{
|
||||
PH_FORMAT format;
|
||||
WCHAR formatBuffer[10];
|
||||
|
||||
PhInitFormatF(&format, (FLOAT)dotNetPerfGC.timeInGC * 100 / (FLOAT)dotNetPerfGC.timeInGCBase, 2);
|
||||
|
||||
if (PhFormatToBuffer(&format, 1, formatBuffer, sizeof(formatBuffer), NULL))
|
||||
PhSetListViewSubItem(Context->CountersLv, 14, 1, formatBuffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
PhSetListViewSubItem(Context->CountersLv, 14, 1, L"0.00");
|
||||
}
|
||||
|
||||
// The CLR source says this value should be "Gen 0 Heap Size; Gen 1 Heap Size; Gen 2 Heap Size and the Large Object Heap Size",
|
||||
// but Perflib only counts Gen 1, Gen 2 and cLrgObjSize... For now, just do what perflib does.
|
||||
PhSetListViewSubItem(Context->CountersLv, 15, 1, FormatByteValue(Context, dotNetPerfGC.cGenHeapSize[1] + dotNetPerfGC.cGenHeapSize[2] + dotNetPerfGC.cLrgObjSize)->Buffer);
|
||||
PhSetListViewSubItem(Context->CountersLv, 16, 1, FormatByteValue(Context, dotNetPerfGC.cTotalCommittedBytes)->Buffer);
|
||||
PhSetListViewSubItem(Context->CountersLv, 17, 1, FormatByteValue(Context, dotNetPerfGC.cTotalReservedBytes)->Buffer);
|
||||
PhSetListViewSubItem(Context->CountersLv, 18, 1, PhaFormatUInt64(dotNetPerfGC.cPinnedObj, TRUE)->Buffer);
|
||||
PhSetListViewSubItem(Context->CountersLv, 19, 1, PhaFormatUInt64(dotNetPerfGC.cSinkBlocks, TRUE)->Buffer);
|
||||
PhSetListViewSubItem(Context->CountersLv, 20, 1, FormatByteValue(Context, dotNetPerfGC.cbAlloc)->Buffer);
|
||||
PhSetListViewSubItem(Context->CountersLv, 21, 1, FormatByteValue(Context, dotNetPerfGC.cbLargeAlloc)->Buffer);
|
||||
}
|
||||
break;
|
||||
case DOTNET_CATEGORY_REMOTING:
|
||||
{
|
||||
PhSetListViewSubItem(Context->CountersLv, 0, 1, PhaFormatUInt64(dotNetPerfContext.cRemoteCalls.Total, TRUE)->Buffer);
|
||||
PhSetListViewSubItem(Context->CountersLv, 1, 1, PhaFormatUInt64(dotNetPerfContext.cChannels, TRUE)->Buffer);
|
||||
PhSetListViewSubItem(Context->CountersLv, 2, 1, PhaFormatUInt64(dotNetPerfContext.cProxies, TRUE)->Buffer);
|
||||
PhSetListViewSubItem(Context->CountersLv, 3, 1, PhaFormatUInt64(dotNetPerfContext.cClasses, TRUE)->Buffer);
|
||||
PhSetListViewSubItem(Context->CountersLv, 4, 1, PhaFormatUInt64(dotNetPerfContext.cContexts, TRUE)->Buffer);
|
||||
PhSetListViewSubItem(Context->CountersLv, 5, 1, PhaFormatUInt64(dotNetPerfContext.cObjAlloc, TRUE)->Buffer);
|
||||
}
|
||||
break;
|
||||
case DOTNET_CATEGORY_SECURITY:
|
||||
{
|
||||
PhSetListViewSubItem(Context->CountersLv, 0, 1, PhaFormatUInt64(dotNetPerfSecurity.cTotalRTChecks, TRUE)->Buffer);
|
||||
PhSetListViewSubItem(Context->CountersLv, 1, 1, PhaFormatUInt64(dotNetPerfSecurity.cLinkChecks, TRUE)->Buffer);
|
||||
|
||||
if (dotNetPerfSecurity.timeRTchecksBase != 0)
|
||||
{
|
||||
PH_FORMAT format;
|
||||
WCHAR formatBuffer[10];
|
||||
|
||||
PhInitFormatF(&format, (FLOAT)dotNetPerfSecurity.timeRTchecks * 100 / (FLOAT)dotNetPerfSecurity.timeRTchecksBase, 2);
|
||||
|
||||
if (PhFormatToBuffer(&format, 1, formatBuffer, sizeof(formatBuffer), NULL))
|
||||
PhSetListViewSubItem(Context->CountersLv, 2, 1, formatBuffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
PhSetListViewSubItem(Context->CountersLv, 2, 1, L"0.00");
|
||||
}
|
||||
|
||||
PhSetListViewSubItem(Context->CountersLv, 3, 1, PhaFormatUInt64(dotNetPerfSecurity.stackWalkDepth, TRUE)->Buffer);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
INT_PTR CALLBACK DotNetPerfPageDlgProc(
|
||||
_In_ HWND hwndDlg,
|
||||
_In_ UINT uMsg,
|
||||
_In_ WPARAM wParam,
|
||||
_In_ LPARAM lParam
|
||||
)
|
||||
{
|
||||
LPPROPSHEETPAGE propSheetPage;
|
||||
PPH_PROCESS_PROPPAGECONTEXT propPageContext;
|
||||
PPH_PROCESS_ITEM processItem;
|
||||
PPERFPAGE_CONTEXT context;
|
||||
|
||||
if (PhPropPageDlgProcHeader(hwndDlg, uMsg, lParam, &propSheetPage, &propPageContext, &processItem))
|
||||
{
|
||||
context = propPageContext->Context;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
switch (uMsg)
|
||||
{
|
||||
case WM_INITDIALOG:
|
||||
{
|
||||
context = PhAllocate(sizeof(PERFPAGE_CONTEXT));
|
||||
memset(context, 0, sizeof(PERFPAGE_CONTEXT));
|
||||
|
||||
propPageContext->Context = context;
|
||||
context->WindowHandle = hwndDlg;
|
||||
context->ProcessItem = processItem;
|
||||
context->Enabled = TRUE;
|
||||
|
||||
context->AppDomainsLv = GetDlgItem(hwndDlg, IDC_APPDOMAINS);
|
||||
context->CountersLv = GetDlgItem(hwndDlg, IDC_COUNTERS);
|
||||
context->CategoriesCb = GetDlgItem(hwndDlg, IDC_CATEGORIES);
|
||||
|
||||
PhSetListViewStyle(context->AppDomainsLv, FALSE, TRUE);
|
||||
PhSetControlTheme(context->AppDomainsLv, L"explorer");
|
||||
PhAddListViewColumn(context->AppDomainsLv, 0, 0, 0, LVCFMT_LEFT, 300, L"Application domain");
|
||||
|
||||
PhSetListViewStyle(context->CountersLv, FALSE, TRUE);
|
||||
PhSetControlTheme(context->CountersLv, L"explorer");
|
||||
PhAddListViewColumn(context->CountersLv, 0, 0, 0, LVCFMT_LEFT, 250, L"Counter");
|
||||
PhAddListViewColumn(context->CountersLv, 1, 1, 1, LVCFMT_RIGHT, 140, L"Value");
|
||||
PhLoadListViewColumnsFromSetting(SETTING_NAME_DOT_NET_COUNTERS_COLUMNS, context->CountersLv);
|
||||
|
||||
if (PhGetIntegerSetting(SETTING_NAME_DOT_NET_SHOW_BYTE_SIZE))
|
||||
{
|
||||
context->ShowByteSize = TRUE;
|
||||
Button_SetCheck(GetDlgItem(hwndDlg, IDC_DOTNET_PERF_SHOWBYTES), TRUE);
|
||||
}
|
||||
|
||||
PhAddComboBoxStrings(context->CategoriesCb, DotNetCategoryStrings, ARRAYSIZE(DotNetCategoryStrings));
|
||||
context->CategoryIndex = PhGetIntegerSetting(SETTING_NAME_DOT_NET_CATEGORY_INDEX);
|
||||
ComboBox_SetCurSel(context->CategoriesCb, context->CategoryIndex);
|
||||
|
||||
#ifdef _WIN64
|
||||
context->IsWow64 = !!context->ProcessItem->IsWow64;
|
||||
#else
|
||||
// HACK: Work-around for Appdomain enumeration on 32bit.
|
||||
context->IsWow64 = TRUE;
|
||||
#endif
|
||||
|
||||
if (NT_SUCCESS(PhOpenProcess(
|
||||
&context->ProcessHandle,
|
||||
PROCESS_VM_READ | ProcessQueryAccess | PROCESS_DUP_HANDLE | SYNCHRONIZE,
|
||||
context->ProcessItem->ProcessId
|
||||
)))
|
||||
{
|
||||
ULONG flags = 0;
|
||||
|
||||
if (NT_SUCCESS(PhGetProcessIsDotNetEx(
|
||||
context->ProcessItem->ProcessId,
|
||||
context->ProcessHandle,
|
||||
context->ProcessItem->IsImmersive == 1 ? 0 : PH_CLR_USE_SECTION_CHECK,
|
||||
NULL,
|
||||
&flags
|
||||
)))
|
||||
{
|
||||
if (flags & PH_CLR_VERSION_4_ABOVE)
|
||||
{
|
||||
context->ClrV4 = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
// Skip AppDomain enumeration of 'Modern' .NET applications as they don't expose the CLR 'Private IPC' block.
|
||||
if (!context->ProcessItem->IsImmersive)
|
||||
{
|
||||
AddProcessAppDomains(hwndDlg, context);
|
||||
}
|
||||
}
|
||||
|
||||
if (context->ClrV4)
|
||||
{
|
||||
if (OpenDotNetPublicControlBlock_V4(
|
||||
!!context->ProcessItem->IsImmersive,
|
||||
context->ProcessHandle,
|
||||
context->ProcessItem->ProcessId,
|
||||
&context->BlockTableHandle,
|
||||
&context->BlockTableAddress
|
||||
))
|
||||
{
|
||||
context->ControlBlockValid = TRUE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (OpenDotNetPublicControlBlock_V2(
|
||||
context->ProcessItem->ProcessId,
|
||||
&context->BlockTableHandle,
|
||||
&context->BlockTableAddress
|
||||
))
|
||||
{
|
||||
context->ControlBlockValid = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (context->ControlBlockValid)
|
||||
{
|
||||
UpdateCategoryValues(hwndDlg, context);
|
||||
UpdateCounterData(hwndDlg, context);
|
||||
}
|
||||
|
||||
PhRegisterCallback(
|
||||
PhGetGeneralCallback(GeneralCallbackProcessesUpdated),
|
||||
ProcessesUpdatedCallback,
|
||||
context,
|
||||
&context->ProcessesUpdatedCallbackRegistration
|
||||
);
|
||||
}
|
||||
break;
|
||||
case WM_DESTROY:
|
||||
{
|
||||
PhUnregisterCallback(
|
||||
PhGetGeneralCallback(GeneralCallbackProcessesUpdated),
|
||||
&context->ProcessesUpdatedCallbackRegistration
|
||||
);
|
||||
|
||||
if (context->BlockTableAddress)
|
||||
{
|
||||
NtUnmapViewOfSection(NtCurrentProcess(), context->BlockTableAddress);
|
||||
}
|
||||
|
||||
if (context->BlockTableHandle)
|
||||
{
|
||||
NtClose(context->BlockTableHandle);
|
||||
}
|
||||
|
||||
if (context->ProcessHandle)
|
||||
{
|
||||
NtClose(context->ProcessHandle);
|
||||
}
|
||||
|
||||
PhSaveListViewColumnsToSetting(SETTING_NAME_DOT_NET_COUNTERS_COLUMNS, context->CountersLv);
|
||||
|
||||
PhFree(context);
|
||||
PhPropPageDlgProcDestroy(hwndDlg);
|
||||
}
|
||||
break;
|
||||
case WM_SHOWWINDOW:
|
||||
{
|
||||
PPH_LAYOUT_ITEM dialogItem;
|
||||
|
||||
if (dialogItem = PhBeginPropPageLayout(hwndDlg, propPageContext))
|
||||
{
|
||||
PhAddPropPageLayoutItem(hwndDlg, context->AppDomainsLv, dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
|
||||
PhAddPropPageLayoutItem(hwndDlg, context->CategoriesCb, dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_TOP | PH_ANCHOR_RIGHT);
|
||||
PhAddPropPageLayoutItem(hwndDlg, context->CountersLv, dialogItem, PH_ANCHOR_ALL);
|
||||
PhAddPropPageLayoutItem(hwndDlg, GetDlgItem(hwndDlg, IDC_DOTNET_PERF_SHOWBYTES), dialogItem, PH_ANCHOR_LEFT | PH_ANCHOR_BOTTOM);
|
||||
PhEndPropPageLayout(hwndDlg, propPageContext);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case WM_COMMAND:
|
||||
{
|
||||
switch (GET_WM_COMMAND_ID(wParam, lParam))
|
||||
{
|
||||
case IDC_CATEGORIES:
|
||||
{
|
||||
if (GET_WM_COMMAND_CMD(wParam, lParam) == CBN_SELCHANGE)
|
||||
{
|
||||
context->CategoryIndex = ComboBox_GetCurSel(context->CategoriesCb);
|
||||
PhSetIntegerSetting(SETTING_NAME_DOT_NET_CATEGORY_INDEX, context->CategoryIndex);
|
||||
|
||||
if (context->ControlBlockValid)
|
||||
{
|
||||
UpdateCategoryValues(hwndDlg, context);
|
||||
UpdateCounterData(hwndDlg, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case IDC_DOTNET_PERF_SHOWBYTES:
|
||||
{
|
||||
if (GET_WM_COMMAND_CMD(wParam, lParam) == BN_CLICKED)
|
||||
{
|
||||
context->ShowByteSize = !context->ShowByteSize;
|
||||
PhSetIntegerSetting(SETTING_NAME_DOT_NET_SHOW_BYTE_SIZE, context->ShowByteSize);
|
||||
|
||||
if (context->ControlBlockValid)
|
||||
{
|
||||
UpdateCategoryValues(hwndDlg, context);
|
||||
UpdateCounterData(hwndDlg, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case WM_NOTIFY:
|
||||
{
|
||||
LPNMHDR header = (LPNMHDR)lParam;
|
||||
|
||||
switch (header->code)
|
||||
{
|
||||
case PSN_SETACTIVE:
|
||||
context->Enabled = TRUE;
|
||||
break;
|
||||
case PSN_KILLACTIVE:
|
||||
context->Enabled = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
PhHandleListViewNotifyForCopy(lParam, context->AppDomainsLv);
|
||||
PhHandleListViewNotifyForCopy(lParam, context->CountersLv);
|
||||
}
|
||||
break;
|
||||
case MSG_UPDATE:
|
||||
{
|
||||
if (context->Enabled && context->ControlBlockValid)
|
||||
{
|
||||
UpdateCounterData(hwndDlg, context);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
VOID AddPerfPageToPropContext(
|
||||
_In_ PPH_PLUGIN_PROCESS_PROPCONTEXT PropContext
|
||||
)
|
||||
{
|
||||
PhAddProcessPropPage(
|
||||
PropContext->PropContext,
|
||||
PhCreateProcessPropPageContextEx(PluginInstance->DllBase, MAKEINTRESOURCE(IDD_PROCDOTNETPERF), DotNetPerfPageDlgProc, NULL)
|
||||
);
|
||||
}
|
||||
26
plugins/DotNetTools/resource.h
Normal file
26
plugins/DotNetTools/resource.h
Normal file
@@ -0,0 +1,26 @@
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by DotNetTools.rc
|
||||
//
|
||||
#define IDD_PROCDOTNETPERF 101
|
||||
#define ID_COPY 101
|
||||
#define IDD_PROCDOTNETASM 102
|
||||
#define IDR_ASSEMBLY_MENU 104
|
||||
#define IDC_APPDOMAINS 1001
|
||||
#define IDC_CATEGORIES 1002
|
||||
#define IDC_COUNTERS 1003
|
||||
#define IDC_LIST 1005
|
||||
#define IDC_DOTNET_PERF_SHOWBYTES 1006
|
||||
#define ID_CLR_OPENFILELOCATION 40001
|
||||
#define ID_CLR_COPY 40002
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 105
|
||||
#define _APS_NEXT_COMMAND_VALUE 40003
|
||||
#define _APS_NEXT_CONTROL_VALUE 1007
|
||||
#define _APS_NEXT_SYMED_VALUE 102
|
||||
#endif
|
||||
#endif
|
||||
321
plugins/DotNetTools/stackext.c
Normal file
321
plugins/DotNetTools/stackext.c
Normal file
@@ -0,0 +1,321 @@
|
||||
/*
|
||||
* Process Hacker .NET Tools -
|
||||
* thread stack extensions
|
||||
*
|
||||
* Copyright (C) 2011-2015 wj32
|
||||
*
|
||||
* This file is part of Process Hacker.
|
||||
*
|
||||
* Process Hacker is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Process Hacker is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "dn.h"
|
||||
#include "clrsup.h"
|
||||
#include "svcext.h"
|
||||
#include <symprv.h>
|
||||
|
||||
typedef struct _THREAD_STACK_CONTEXT
|
||||
{
|
||||
PCLR_PROCESS_SUPPORT Support;
|
||||
HANDLE ProcessId;
|
||||
HANDLE ThreadId;
|
||||
HANDLE ThreadHandle;
|
||||
|
||||
PVOID PredictedEip;
|
||||
PVOID PredictedEbp;
|
||||
PVOID PredictedEsp;
|
||||
|
||||
#ifdef _WIN64
|
||||
BOOLEAN IsWow64;
|
||||
BOOLEAN ConnectedToPhSvc;
|
||||
#endif
|
||||
} THREAD_STACK_CONTEXT, *PTHREAD_STACK_CONTEXT;
|
||||
|
||||
static PPH_HASHTABLE ContextHashtable;
|
||||
static PH_QUEUED_LOCK ContextHashtableLock = PH_QUEUED_LOCK_INIT;
|
||||
static PH_INITONCE ContextHashtableInitOnce = PH_INITONCE_INIT;
|
||||
|
||||
PTHREAD_STACK_CONTEXT FindThreadStackContext(
|
||||
_In_ PVOID UniqueKey
|
||||
)
|
||||
{
|
||||
PTHREAD_STACK_CONTEXT context;
|
||||
PVOID *item;
|
||||
|
||||
PhAcquireQueuedLockExclusive(&ContextHashtableLock);
|
||||
|
||||
item = PhFindItemSimpleHashtable(ContextHashtable, UniqueKey);
|
||||
|
||||
if (item)
|
||||
context = *item;
|
||||
else
|
||||
context = NULL;
|
||||
|
||||
PhReleaseQueuedLockExclusive(&ContextHashtableLock);
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
VOID ProcessThreadStackControl(
|
||||
_In_ PPH_PLUGIN_THREAD_STACK_CONTROL Control
|
||||
)
|
||||
{
|
||||
if (PhBeginInitOnce(&ContextHashtableInitOnce))
|
||||
{
|
||||
ContextHashtable = PhCreateSimpleHashtable(4);
|
||||
PhEndInitOnce(&ContextHashtableInitOnce);
|
||||
}
|
||||
|
||||
switch (Control->Type)
|
||||
{
|
||||
case PluginThreadStackInitializing:
|
||||
{
|
||||
PTHREAD_STACK_CONTEXT context;
|
||||
#if _WIN64
|
||||
HANDLE processHandle;
|
||||
#endif
|
||||
|
||||
context = PhAllocate(sizeof(THREAD_STACK_CONTEXT));
|
||||
memset(context, 0, sizeof(THREAD_STACK_CONTEXT));
|
||||
context->ProcessId = Control->u.Initializing.ProcessId;
|
||||
context->ThreadId = Control->u.Initializing.ThreadId;
|
||||
context->ThreadHandle = Control->u.Initializing.ThreadHandle;
|
||||
|
||||
#if _WIN64
|
||||
if (NT_SUCCESS(PhOpenProcess(&processHandle, ProcessQueryAccess, Control->u.Initializing.ProcessId)))
|
||||
{
|
||||
PhGetProcessIsWow64(processHandle, &context->IsWow64);
|
||||
NtClose(processHandle);
|
||||
}
|
||||
#endif
|
||||
|
||||
PhAcquireQueuedLockExclusive(&ContextHashtableLock);
|
||||
PhAddItemSimpleHashtable(ContextHashtable, Control->UniqueKey, context);
|
||||
PhReleaseQueuedLockExclusive(&ContextHashtableLock);
|
||||
}
|
||||
break;
|
||||
case PluginThreadStackUninitializing:
|
||||
{
|
||||
PTHREAD_STACK_CONTEXT context = FindThreadStackContext(Control->UniqueKey);
|
||||
|
||||
if (!context)
|
||||
return;
|
||||
|
||||
PhFree(context);
|
||||
|
||||
PhAcquireQueuedLockExclusive(&ContextHashtableLock);
|
||||
PhRemoveItemSimpleHashtable(ContextHashtable, Control->UniqueKey);
|
||||
PhReleaseQueuedLockExclusive(&ContextHashtableLock);
|
||||
}
|
||||
break;
|
||||
case PluginThreadStackResolveSymbol:
|
||||
{
|
||||
PTHREAD_STACK_CONTEXT context = FindThreadStackContext(Control->UniqueKey);
|
||||
PPH_STRING managedSymbol = NULL;
|
||||
ULONG64 displacement;
|
||||
|
||||
if (!context)
|
||||
return;
|
||||
|
||||
if (context->Support)
|
||||
{
|
||||
#ifndef _WIN64
|
||||
PVOID predictedEip;
|
||||
PVOID predictedEbp;
|
||||
PVOID predictedEsp;
|
||||
|
||||
predictedEip = context->PredictedEip;
|
||||
predictedEbp = context->PredictedEbp;
|
||||
predictedEsp = context->PredictedEsp;
|
||||
|
||||
PredictAddressesFromClrData(
|
||||
context->Support,
|
||||
context->ThreadId,
|
||||
Control->u.ResolveSymbol.StackFrame->PcAddress,
|
||||
Control->u.ResolveSymbol.StackFrame->FrameAddress,
|
||||
Control->u.ResolveSymbol.StackFrame->StackAddress,
|
||||
&context->PredictedEip,
|
||||
&context->PredictedEbp,
|
||||
&context->PredictedEsp
|
||||
);
|
||||
|
||||
// Fix up dbghelp EBP with real EBP given by the CLR data routines.
|
||||
if (Control->u.ResolveSymbol.StackFrame->PcAddress == predictedEip)
|
||||
{
|
||||
Control->u.ResolveSymbol.StackFrame->FrameAddress = predictedEbp;
|
||||
Control->u.ResolveSymbol.StackFrame->StackAddress = predictedEsp;
|
||||
}
|
||||
#endif
|
||||
|
||||
managedSymbol = GetRuntimeNameByAddressClrProcess(
|
||||
context->Support,
|
||||
(ULONG64)Control->u.ResolveSymbol.StackFrame->PcAddress,
|
||||
&displacement
|
||||
);
|
||||
}
|
||||
#ifdef _WIN64
|
||||
else if (context->IsWow64 && context->ConnectedToPhSvc)
|
||||
{
|
||||
PVOID predictedEip;
|
||||
PVOID predictedEbp;
|
||||
PVOID predictedEsp;
|
||||
|
||||
predictedEip = context->PredictedEip;
|
||||
predictedEbp = context->PredictedEbp;
|
||||
predictedEsp = context->PredictedEsp;
|
||||
|
||||
CallPredictAddressesFromClrData(
|
||||
context->ProcessId,
|
||||
context->ThreadId,
|
||||
Control->u.ResolveSymbol.StackFrame->PcAddress,
|
||||
Control->u.ResolveSymbol.StackFrame->FrameAddress,
|
||||
Control->u.ResolveSymbol.StackFrame->StackAddress,
|
||||
&context->PredictedEip,
|
||||
&context->PredictedEbp,
|
||||
&context->PredictedEsp
|
||||
);
|
||||
|
||||
// Fix up dbghelp EBP with real EBP given by the CLR data routines.
|
||||
if (Control->u.ResolveSymbol.StackFrame->PcAddress == predictedEip)
|
||||
{
|
||||
Control->u.ResolveSymbol.StackFrame->FrameAddress = predictedEbp;
|
||||
Control->u.ResolveSymbol.StackFrame->StackAddress = predictedEsp;
|
||||
}
|
||||
|
||||
managedSymbol = CallGetRuntimeNameByAddress(
|
||||
context->ProcessId,
|
||||
(ULONG64)Control->u.ResolveSymbol.StackFrame->PcAddress,
|
||||
&displacement
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (managedSymbol)
|
||||
{
|
||||
if (displacement != 0)
|
||||
PhMoveReference(&managedSymbol, PhFormatString(L"%s + 0x%I64x", managedSymbol->Buffer, displacement));
|
||||
|
||||
if (Control->u.ResolveSymbol.Symbol)
|
||||
PhMoveReference(&managedSymbol, PhFormatString(L"%s <-- %s", managedSymbol->Buffer, Control->u.ResolveSymbol.Symbol->Buffer));
|
||||
|
||||
PhMoveReference(&Control->u.ResolveSymbol.Symbol, managedSymbol);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PluginThreadStackBeginDefaultWalkStack:
|
||||
{
|
||||
PTHREAD_STACK_CONTEXT context = FindThreadStackContext(Control->UniqueKey);
|
||||
BOOLEAN isDotNet;
|
||||
|
||||
if (!context)
|
||||
return;
|
||||
|
||||
if (!NT_SUCCESS(PhGetProcessIsDotNet(context->ProcessId, &isDotNet)) || !isDotNet)
|
||||
return;
|
||||
|
||||
context->Support = CreateClrProcessSupport(context->ProcessId);
|
||||
|
||||
#ifdef _WIN64
|
||||
if (context->IsWow64)
|
||||
context->ConnectedToPhSvc = PhUiConnectToPhSvcEx(NULL, Wow64PhSvcMode, FALSE);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
case PluginThreadStackEndDefaultWalkStack:
|
||||
{
|
||||
PTHREAD_STACK_CONTEXT context = FindThreadStackContext(Control->UniqueKey);
|
||||
|
||||
if (!context)
|
||||
return;
|
||||
|
||||
if (context->Support)
|
||||
{
|
||||
FreeClrProcessSupport(context->Support);
|
||||
context->Support = NULL;
|
||||
}
|
||||
|
||||
#ifdef _WIN64
|
||||
if (context->ConnectedToPhSvc)
|
||||
{
|
||||
PhUiDisconnectFromPhSvc();
|
||||
context->ConnectedToPhSvc = FALSE;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
VOID PredictAddressesFromClrData(
|
||||
_In_ PCLR_PROCESS_SUPPORT Support,
|
||||
_In_ HANDLE ThreadId,
|
||||
_In_ PVOID PcAddress,
|
||||
_In_ PVOID FrameAddress,
|
||||
_In_ PVOID StackAddress,
|
||||
_Out_ PVOID *PredictedEip,
|
||||
_Out_ PVOID *PredictedEbp,
|
||||
_Out_ PVOID *PredictedEsp
|
||||
)
|
||||
{
|
||||
#ifdef _WIN64
|
||||
*PredictedEip = NULL;
|
||||
*PredictedEbp = NULL;
|
||||
*PredictedEsp = NULL;
|
||||
#else
|
||||
IXCLRDataTask *task;
|
||||
|
||||
*PredictedEip = NULL;
|
||||
*PredictedEbp = NULL;
|
||||
*PredictedEsp = NULL;
|
||||
|
||||
if (SUCCEEDED(IXCLRDataProcess_GetTaskByOSThreadID(
|
||||
Support->DataProcess,
|
||||
HandleToUlong(ThreadId),
|
||||
&task
|
||||
)))
|
||||
{
|
||||
IXCLRDataStackWalk *stackWalk;
|
||||
|
||||
if (SUCCEEDED(IXCLRDataTask_CreateStackWalk(task, 0xf, &stackWalk)))
|
||||
{
|
||||
HRESULT result;
|
||||
BOOLEAN firstTime = TRUE;
|
||||
CONTEXT context;
|
||||
ULONG contextSize;
|
||||
|
||||
memset(&context, 0, sizeof(CONTEXT));
|
||||
context.ContextFlags = CONTEXT_CONTROL;
|
||||
context.Eip = PtrToUlong(PcAddress);
|
||||
context.Ebp = PtrToUlong(FrameAddress);
|
||||
context.Esp = PtrToUlong(StackAddress);
|
||||
|
||||
result = IXCLRDataStackWalk_SetContext2(stackWalk, CLRDATA_STACK_SET_CURRENT_CONTEXT, sizeof(CONTEXT), (BYTE *)&context);
|
||||
|
||||
if (SUCCEEDED(result = IXCLRDataStackWalk_Next(stackWalk)) && result != S_FALSE)
|
||||
{
|
||||
if (SUCCEEDED(IXCLRDataStackWalk_GetContext(stackWalk, CONTEXT_CONTROL, sizeof(CONTEXT), &contextSize, (BYTE *)&context)))
|
||||
{
|
||||
*PredictedEip = UlongToPtr(context.Eip);
|
||||
*PredictedEbp = UlongToPtr(context.Ebp);
|
||||
*PredictedEsp = UlongToPtr(context.Esp);
|
||||
}
|
||||
}
|
||||
|
||||
IXCLRDataStackWalk_Release(stackWalk);
|
||||
}
|
||||
|
||||
IXCLRDataTask_Release(task);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
209
plugins/DotNetTools/svcext.c
Normal file
209
plugins/DotNetTools/svcext.c
Normal file
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
* Process Hacker .NET Tools -
|
||||
* phsvc extensions
|
||||
*
|
||||
* Copyright (C) 2015 wj32
|
||||
*
|
||||
* This file is part of Process Hacker.
|
||||
*
|
||||
* Process Hacker is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Process Hacker is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "dn.h"
|
||||
#include "svcext.h"
|
||||
#include "clrsup.h"
|
||||
|
||||
PPH_STRING CallGetRuntimeNameByAddress(
|
||||
_In_ HANDLE ProcessId,
|
||||
_In_ ULONG64 Address,
|
||||
_Out_opt_ PULONG64 Displacement
|
||||
)
|
||||
{
|
||||
NTSTATUS status;
|
||||
PH_PLUGIN_PHSVC_CLIENT client;
|
||||
DN_API_GETRUNTIMENAMEBYADDRESS in;
|
||||
DN_API_GETRUNTIMENAMEBYADDRESS out;
|
||||
ULONG bufferSize;
|
||||
PVOID buffer;
|
||||
PPH_STRING name = NULL;
|
||||
|
||||
if (!PhPluginQueryPhSvc(&client))
|
||||
return NULL;
|
||||
|
||||
in.i.ProcessId = HandleToUlong(ProcessId);
|
||||
in.i.Address = Address;
|
||||
|
||||
bufferSize = 0x1000;
|
||||
|
||||
if (!(buffer = client.CreateString(NULL, bufferSize, &in.i.Name)))
|
||||
return NULL;
|
||||
|
||||
status = PhPluginCallPhSvc(PluginInstance, DnGetRuntimeNameByAddressApiNumber, &in, sizeof(in), &out, sizeof(out));
|
||||
|
||||
if (status == STATUS_BUFFER_OVERFLOW)
|
||||
{
|
||||
client.FreeHeap(buffer);
|
||||
bufferSize = out.o.NameLength;
|
||||
|
||||
if (!(buffer = client.CreateString(NULL, bufferSize, &in.i.Name)))
|
||||
return NULL;
|
||||
|
||||
status = PhPluginCallPhSvc(PluginInstance, DnGetRuntimeNameByAddressApiNumber, &in, sizeof(in), &out, sizeof(out));
|
||||
}
|
||||
|
||||
if (NT_SUCCESS(status))
|
||||
{
|
||||
name = PhCreateStringEx(buffer, out.o.NameLength);
|
||||
|
||||
if (Displacement)
|
||||
*Displacement = out.o.Displacement;
|
||||
}
|
||||
|
||||
client.FreeHeap(buffer);
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
NTSTATUS DispatchGetRuntimeNameByAddress(
|
||||
_In_ PPH_PLUGIN_PHSVC_REQUEST Request,
|
||||
_In_ PDN_API_GETRUNTIMENAMEBYADDRESS In,
|
||||
_Out_ PDN_API_GETRUNTIMENAMEBYADDRESS Out
|
||||
)
|
||||
{
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
PVOID nameBuffer;
|
||||
PCLR_PROCESS_SUPPORT support;
|
||||
PPH_STRING name;
|
||||
|
||||
if (!NT_SUCCESS(status = Request->ProbeBuffer(&In->i.Name, sizeof(WCHAR), FALSE, &nameBuffer)))
|
||||
return status;
|
||||
|
||||
support = CreateClrProcessSupport(UlongToHandle(In->i.ProcessId));
|
||||
|
||||
if (!support)
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
|
||||
name = GetRuntimeNameByAddressClrProcess(support, In->i.Address, &Out->o.Displacement);
|
||||
|
||||
if (!name)
|
||||
{
|
||||
status = STATUS_UNSUCCESSFUL;
|
||||
goto CleanupExit;
|
||||
}
|
||||
|
||||
memcpy(nameBuffer, name->Buffer, min(name->Length, In->i.Name.Length));
|
||||
Out->o.NameLength = (ULONG)name->Length;
|
||||
|
||||
if (In->i.Name.Length < name->Length)
|
||||
status = STATUS_BUFFER_OVERFLOW;
|
||||
|
||||
CleanupExit:
|
||||
FreeClrProcessSupport(support);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
VOID CallPredictAddressesFromClrData(
|
||||
_In_ HANDLE ProcessId,
|
||||
_In_ HANDLE ThreadId,
|
||||
_In_ PVOID PcAddress,
|
||||
_In_ PVOID FrameAddress,
|
||||
_In_ PVOID StackAddress,
|
||||
_Out_ PVOID *PredictedEip,
|
||||
_Out_ PVOID *PredictedEbp,
|
||||
_Out_ PVOID *PredictedEsp
|
||||
)
|
||||
{
|
||||
PH_PLUGIN_PHSVC_CLIENT client;
|
||||
DN_API_PREDICTADDRESSESFROMCLRDATA in;
|
||||
DN_API_PREDICTADDRESSESFROMCLRDATA out;
|
||||
|
||||
*PredictedEip = NULL;
|
||||
*PredictedEbp = NULL;
|
||||
*PredictedEsp = NULL;
|
||||
|
||||
if (!PhPluginQueryPhSvc(&client))
|
||||
return;
|
||||
|
||||
in.i.ProcessId = HandleToUlong(ProcessId);
|
||||
in.i.ThreadId = HandleToUlong(ThreadId);
|
||||
in.i.PcAddress = PtrToUlong(PcAddress);
|
||||
in.i.FrameAddress = PtrToUlong(FrameAddress);
|
||||
in.i.StackAddress = PtrToUlong(StackAddress);
|
||||
|
||||
if (NT_SUCCESS(PhPluginCallPhSvc(PluginInstance, DnPredictAddressesFromClrDataApiNumber, &in, sizeof(in), &out, sizeof(out))))
|
||||
{
|
||||
*PredictedEip = UlongToPtr(out.o.PredictedEip);
|
||||
*PredictedEbp = UlongToPtr(out.o.PredictedEbp);
|
||||
*PredictedEsp = UlongToPtr(out.o.PredictedEsp);
|
||||
}
|
||||
}
|
||||
|
||||
NTSTATUS DispatchPredictAddressesFromClrData(
|
||||
_In_ PPH_PLUGIN_PHSVC_REQUEST Request,
|
||||
_In_ PDN_API_PREDICTADDRESSESFROMCLRDATA In,
|
||||
_Out_ PDN_API_PREDICTADDRESSESFROMCLRDATA Out
|
||||
)
|
||||
{
|
||||
PCLR_PROCESS_SUPPORT support;
|
||||
PVOID predictedEip;
|
||||
PVOID predictedEbp;
|
||||
PVOID predictedEsp;
|
||||
|
||||
support = CreateClrProcessSupport(UlongToHandle(In->i.ProcessId));
|
||||
|
||||
if (!support)
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
|
||||
PredictAddressesFromClrData(
|
||||
support,
|
||||
UlongToHandle(In->i.ThreadId),
|
||||
UlongToPtr(In->i.PcAddress),
|
||||
UlongToPtr(In->i.FrameAddress),
|
||||
UlongToPtr(In->i.StackAddress),
|
||||
&predictedEip,
|
||||
&predictedEbp,
|
||||
&predictedEsp
|
||||
);
|
||||
FreeClrProcessSupport(support);
|
||||
|
||||
Out->o.PredictedEip = PtrToUlong(predictedEip);
|
||||
Out->o.PredictedEbp = PtrToUlong(predictedEbp);
|
||||
Out->o.PredictedEsp = PtrToUlong(predictedEsp);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
VOID DispatchPhSvcRequest(
|
||||
_In_ PVOID Parameter
|
||||
)
|
||||
{
|
||||
PPH_PLUGIN_PHSVC_REQUEST request = Parameter;
|
||||
PVOID inBuffer;
|
||||
|
||||
// InBuffer can alias OutBuffer, so make a copy of InBuffer.
|
||||
inBuffer = PhAllocateCopy(request->InBuffer, request->InLength);
|
||||
|
||||
switch (request->SubId)
|
||||
{
|
||||
case DnGetRuntimeNameByAddressApiNumber:
|
||||
request->ReturnStatus = DispatchGetRuntimeNameByAddress(request, inBuffer, request->OutBuffer);
|
||||
break;
|
||||
case DnPredictAddressesFromClrDataApiNumber:
|
||||
request->ReturnStatus = DispatchPredictAddressesFromClrData(request, inBuffer, request->OutBuffer);
|
||||
break;
|
||||
}
|
||||
|
||||
PhFree(inBuffer);
|
||||
}
|
||||
87
plugins/DotNetTools/svcext.h
Normal file
87
plugins/DotNetTools/svcext.h
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Process Hacker .NET Tools -
|
||||
* phsvc extensions
|
||||
*
|
||||
* Copyright (C) 2015 wj32
|
||||
*
|
||||
* This file is part of Process Hacker.
|
||||
*
|
||||
* Process Hacker is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Process Hacker is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SVCEXT_H
|
||||
#define SVCEXT_H
|
||||
|
||||
// API
|
||||
|
||||
typedef enum _DN_API_NUMBER
|
||||
{
|
||||
DnGetRuntimeNameByAddressApiNumber = 1,
|
||||
DnPredictAddressesFromClrDataApiNumber = 2
|
||||
} DN_API_NUMBER;
|
||||
|
||||
typedef union _DN_API_GETRUNTIMENAMEBYADDRESS
|
||||
{
|
||||
struct
|
||||
{
|
||||
ULONG ProcessId;
|
||||
ULONG Reserved;
|
||||
ULONG64 Address;
|
||||
PH_RELATIVE_STRINGREF Name; // out
|
||||
} i;
|
||||
struct
|
||||
{
|
||||
ULONG64 Displacement;
|
||||
ULONG NameLength;
|
||||
} o;
|
||||
} DN_API_GETRUNTIMENAMEBYADDRESS, *PDN_API_GETRUNTIMENAMEBYADDRESS;
|
||||
|
||||
typedef union _DN_API_PREDICTADDRESSESFROMCLRDATA
|
||||
{
|
||||
struct
|
||||
{
|
||||
ULONG ProcessId;
|
||||
ULONG ThreadId;
|
||||
ULONG PcAddress;
|
||||
ULONG FrameAddress;
|
||||
ULONG StackAddress;
|
||||
} i;
|
||||
struct
|
||||
{
|
||||
ULONG PredictedEip;
|
||||
ULONG PredictedEbp;
|
||||
ULONG PredictedEsp;
|
||||
} o;
|
||||
} DN_API_PREDICTADDRESSESFROMCLRDATA, *PDN_API_PREDICTADDRESSESFROMCLRDATA;
|
||||
|
||||
// Calls
|
||||
|
||||
PPH_STRING CallGetRuntimeNameByAddress(
|
||||
_In_ HANDLE ProcessId,
|
||||
_In_ ULONG64 Address,
|
||||
_Out_opt_ PULONG64 Displacement
|
||||
);
|
||||
|
||||
VOID CallPredictAddressesFromClrData(
|
||||
_In_ HANDLE ProcessId,
|
||||
_In_ HANDLE ThreadId,
|
||||
_In_ PVOID PcAddress,
|
||||
_In_ PVOID FrameAddress,
|
||||
_In_ PVOID StackAddress,
|
||||
_Out_ PVOID *PredictedEip,
|
||||
_Out_ PVOID *PredictedEbp,
|
||||
_Out_ PVOID *PredictedEsp
|
||||
);
|
||||
|
||||
#endif
|
||||
296
plugins/DotNetTools/treeext.c
Normal file
296
plugins/DotNetTools/treeext.c
Normal file
@@ -0,0 +1,296 @@
|
||||
/*
|
||||
* Process Hacker .NET Tools -
|
||||
* thread list extensions
|
||||
*
|
||||
* Copyright (C) 2015 wj32
|
||||
*
|
||||
* This file is part of Process Hacker.
|
||||
*
|
||||
* Process Hacker is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Process Hacker is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "dn.h"
|
||||
#include "clrsup.h"
|
||||
|
||||
VOID NTAPI ThreadsContextCreateCallback(
|
||||
_In_ PVOID Object,
|
||||
_In_ PH_EM_OBJECT_TYPE ObjectType,
|
||||
_In_ PVOID Extension
|
||||
);
|
||||
|
||||
VOID NTAPI ThreadsContextDeleteCallback(
|
||||
_In_ PVOID Object,
|
||||
_In_ PH_EM_OBJECT_TYPE ObjectType,
|
||||
_In_ PVOID Extension
|
||||
);
|
||||
|
||||
VOID ThreadTreeNewMessage(
|
||||
_In_ PVOID Parameter
|
||||
);
|
||||
|
||||
LONG ThreadTreeNewSortFunction(
|
||||
_In_ PVOID Node1,
|
||||
_In_ PVOID Node2,
|
||||
_In_ ULONG SubId,
|
||||
_In_ PVOID Context
|
||||
);
|
||||
|
||||
#define THREAD_TREE_CONTEXT_TYPE 1
|
||||
|
||||
typedef struct _THREAD_TREE_CONTEXT
|
||||
{
|
||||
ULONG Type;
|
||||
HANDLE ProcessId;
|
||||
PH_CALLBACK_REGISTRATION AddedCallbackRegistration;
|
||||
PCLR_PROCESS_SUPPORT Support;
|
||||
} THREAD_TREE_CONTEXT, *PTHREAD_TREE_CONTEXT;
|
||||
|
||||
static PPH_HASHTABLE ContextHashtable;
|
||||
static PH_QUEUED_LOCK ContextHashtableLock = PH_QUEUED_LOCK_INIT;
|
||||
static PH_INITONCE ContextHashtableInitOnce = PH_INITONCE_INIT;
|
||||
|
||||
VOID InitializeTreeNewObjectExtensions(
|
||||
VOID
|
||||
)
|
||||
{
|
||||
PhPluginSetObjectExtension(
|
||||
PluginInstance,
|
||||
EmThreadsContextType,
|
||||
sizeof(THREAD_TREE_CONTEXT),
|
||||
ThreadsContextCreateCallback,
|
||||
ThreadsContextDeleteCallback
|
||||
);
|
||||
}
|
||||
|
||||
VOID AddTreeNewColumn(
|
||||
_In_ PPH_PLUGIN_TREENEW_INFORMATION TreeNewInfo,
|
||||
_In_ PVOID Context,
|
||||
_In_ ULONG SubId,
|
||||
_In_ BOOLEAN Visible,
|
||||
_In_ PWSTR Text,
|
||||
_In_ ULONG Width,
|
||||
_In_ ULONG Alignment,
|
||||
_In_ ULONG TextFlags,
|
||||
_In_ BOOLEAN SortDescending,
|
||||
_In_ PPH_PLUGIN_TREENEW_SORT_FUNCTION SortFunction
|
||||
)
|
||||
{
|
||||
PH_TREENEW_COLUMN column;
|
||||
|
||||
memset(&column, 0, sizeof(PH_TREENEW_COLUMN));
|
||||
column.Visible = Visible;
|
||||
column.SortDescending = SortDescending;
|
||||
column.Text = Text;
|
||||
column.Width = Width;
|
||||
column.Alignment = Alignment;
|
||||
column.DisplayIndex = TreeNew_GetVisibleColumnCount(TreeNewInfo->TreeNewHandle);
|
||||
column.TextFlags = TextFlags;
|
||||
|
||||
PhPluginAddTreeNewColumn(
|
||||
PluginInstance,
|
||||
TreeNewInfo->CmData,
|
||||
&column,
|
||||
SubId,
|
||||
Context,
|
||||
SortFunction
|
||||
);
|
||||
}
|
||||
|
||||
VOID DispatchTreeNewMessage(
|
||||
_In_ PVOID Parameter
|
||||
)
|
||||
{
|
||||
PPH_PLUGIN_TREENEW_MESSAGE message = Parameter;
|
||||
|
||||
switch (*(PULONG)message->Context)
|
||||
{
|
||||
case THREAD_TREE_CONTEXT_TYPE:
|
||||
ThreadTreeNewMessage(Parameter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static VOID ThreadAddedHandler(
|
||||
_In_opt_ PVOID Parameter,
|
||||
_In_opt_ PVOID Context
|
||||
)
|
||||
{
|
||||
PPH_THREAD_ITEM threadItem = Parameter;
|
||||
PDN_THREAD_ITEM dnThread;
|
||||
PTHREAD_TREE_CONTEXT context = Context;
|
||||
|
||||
dnThread = PhPluginGetObjectExtension(PluginInstance, threadItem, EmThreadItemType);
|
||||
memset(dnThread, 0, sizeof(DN_THREAD_ITEM));
|
||||
dnThread->ThreadItem = threadItem;
|
||||
}
|
||||
|
||||
VOID NTAPI ThreadsContextCreateCallback(
|
||||
_In_ PVOID Object,
|
||||
_In_ PH_EM_OBJECT_TYPE ObjectType,
|
||||
_In_ PVOID Extension
|
||||
)
|
||||
{
|
||||
PPH_THREADS_CONTEXT threadsContext = Object;
|
||||
PTHREAD_TREE_CONTEXT context = Extension;
|
||||
|
||||
memset(context, 0, sizeof(THREAD_TREE_CONTEXT));
|
||||
context->Type = THREAD_TREE_CONTEXT_TYPE;
|
||||
context->ProcessId = threadsContext->Provider->ProcessId;
|
||||
|
||||
PhRegisterCallback(
|
||||
&threadsContext->Provider->ThreadAddedEvent,
|
||||
ThreadAddedHandler,
|
||||
context,
|
||||
&context->AddedCallbackRegistration
|
||||
);
|
||||
}
|
||||
|
||||
VOID NTAPI ThreadsContextDeleteCallback(
|
||||
_In_ PVOID Object,
|
||||
_In_ PH_EM_OBJECT_TYPE ObjectType,
|
||||
_In_ PVOID Extension
|
||||
)
|
||||
{
|
||||
PPH_THREADS_CONTEXT threadsContext = Object;
|
||||
PTHREAD_TREE_CONTEXT context = Extension;
|
||||
|
||||
PhUnregisterCallback(
|
||||
&threadsContext->Provider->ThreadAddedEvent,
|
||||
&context->AddedCallbackRegistration
|
||||
);
|
||||
|
||||
if (context->Support)
|
||||
FreeClrProcessSupport(context->Support);
|
||||
}
|
||||
|
||||
VOID ThreadTreeNewInitializing(
|
||||
_In_ PVOID Parameter
|
||||
)
|
||||
{
|
||||
PPH_PLUGIN_TREENEW_INFORMATION info = Parameter;
|
||||
PPH_THREADS_CONTEXT threadsContext;
|
||||
PTHREAD_TREE_CONTEXT context;
|
||||
BOOLEAN isDotNet;
|
||||
|
||||
threadsContext = info->SystemContext;
|
||||
context = PhPluginGetObjectExtension(PluginInstance, threadsContext, EmThreadsContextType);
|
||||
|
||||
if (NT_SUCCESS(PhGetProcessIsDotNet(threadsContext->Provider->ProcessId, &isDotNet)) && isDotNet)
|
||||
{
|
||||
PCLR_PROCESS_SUPPORT support;
|
||||
|
||||
support = CreateClrProcessSupport(threadsContext->Provider->ProcessId);
|
||||
|
||||
if (!support)
|
||||
return;
|
||||
|
||||
context->Support = support;
|
||||
|
||||
AddTreeNewColumn(info, context, DNTHTNC_APPDOMAIN, TRUE, L"AppDomain", 120, PH_ALIGN_LEFT, 0, FALSE, ThreadTreeNewSortFunction);
|
||||
}
|
||||
}
|
||||
|
||||
VOID ThreadTreeNewUninitializing(
|
||||
_In_ PVOID Parameter
|
||||
)
|
||||
{
|
||||
NOTHING;
|
||||
}
|
||||
|
||||
VOID UpdateThreadClrData(
|
||||
_In_ PTHREAD_TREE_CONTEXT Context,
|
||||
_Inout_ PDN_THREAD_ITEM DnThread
|
||||
)
|
||||
{
|
||||
if (!DnThread->ClrDataValid)
|
||||
{
|
||||
IXCLRDataProcess *process;
|
||||
IXCLRDataTask *task;
|
||||
IXCLRDataAppDomain *appDomain;
|
||||
|
||||
if (Context->Support)
|
||||
process = Context->Support->DataProcess;
|
||||
else
|
||||
return;
|
||||
|
||||
if (SUCCEEDED(IXCLRDataProcess_GetTaskByOSThreadID(process, HandleToUlong(DnThread->ThreadItem->ThreadId), &task)))
|
||||
{
|
||||
if (SUCCEEDED(IXCLRDataTask_GetCurrentAppDomain(task, &appDomain)))
|
||||
{
|
||||
DnThread->AppDomainText = GetNameXClrDataAppDomain(appDomain);
|
||||
IXCLRDataAppDomain_Release(appDomain);
|
||||
}
|
||||
|
||||
IXCLRDataTask_Release(task);
|
||||
}
|
||||
|
||||
DnThread->ClrDataValid = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
VOID ThreadTreeNewMessage(
|
||||
_In_ PVOID Parameter
|
||||
)
|
||||
{
|
||||
PPH_PLUGIN_TREENEW_MESSAGE message = Parameter;
|
||||
PTHREAD_TREE_CONTEXT context = message->Context;
|
||||
|
||||
if (message->Message == TreeNewGetCellText)
|
||||
{
|
||||
PPH_TREENEW_GET_CELL_TEXT getCellText = message->Parameter1;
|
||||
PPH_THREAD_NODE threadNode = (PPH_THREAD_NODE)getCellText->Node;
|
||||
PDN_THREAD_ITEM dnThread;
|
||||
|
||||
dnThread = PhPluginGetObjectExtension(PluginInstance, threadNode->ThreadItem, EmThreadItemType);
|
||||
|
||||
switch (message->SubId)
|
||||
{
|
||||
case DNTHTNC_APPDOMAIN:
|
||||
UpdateThreadClrData(context, dnThread);
|
||||
getCellText->Text = PhGetStringRef(dnThread->AppDomainText);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LONG ThreadTreeNewSortFunction(
|
||||
_In_ PVOID Node1,
|
||||
_In_ PVOID Node2,
|
||||
_In_ ULONG SubId,
|
||||
_In_ PVOID Context
|
||||
)
|
||||
{
|
||||
PTHREAD_TREE_CONTEXT context = Context;
|
||||
LONG result;
|
||||
PPH_THREAD_NODE node1 = Node1;
|
||||
PPH_THREAD_NODE node2 = Node2;
|
||||
PDN_THREAD_ITEM dnThread1;
|
||||
PDN_THREAD_ITEM dnThread2;
|
||||
|
||||
dnThread1 = PhPluginGetObjectExtension(PluginInstance, node1->ThreadItem, EmThreadItemType);
|
||||
dnThread2 = PhPluginGetObjectExtension(PluginInstance, node2->ThreadItem, EmThreadItemType);
|
||||
|
||||
result = 0;
|
||||
|
||||
switch (SubId)
|
||||
{
|
||||
case DNTHTNC_APPDOMAIN:
|
||||
UpdateThreadClrData(context, dnThread1);
|
||||
UpdateThreadClrData(context, dnThread2);
|
||||
result = PhCompareStringWithNull(dnThread1->AppDomainText, dnThread2->AppDomainText, TRUE);
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
Reference in New Issue
Block a user