Skip to content

Commit ee2ab3d

Browse files
Added WTComTrace.wprp and updated COM troubleshooting guide
1 parent 268fbb6 commit ee2ab3d

File tree

4 files changed

+136
-10
lines changed

4 files changed

+136
-10
lines changed

assets/other/WTComTrace.wprp

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<WindowsPerformanceRecorder Version="1.0" Author="Sebastian Solnica (https://wtrace.net)" Comments="Profile based on TSS scripts by Microsoft">
3+
<Profiles>
4+
<SystemCollector Id="SystemCollector" Name="NT Kernel Logger">
5+
<BufferSize Value="1024"/>
6+
<Buffers Value="32"/>
7+
</SystemCollector>
8+
9+
<EventCollector Id="EventCollector_MicrosoftWindowsCOMTrace" Name="MicrosoftWindowsCOMTraceCollector">
10+
<BufferSize Value="1024" />
11+
<Buffers Value="32" />
12+
</EventCollector>
13+
14+
<SystemProvider Id="SystemProviderBasic">
15+
<Keywords>
16+
<Keyword Value="ProcessThread" />
17+
<Keyword Value="Loader" />
18+
<Keyword Value="Registry" />
19+
</Keywords>
20+
</SystemProvider>
21+
22+
<EventProvider Id="EventProvider_CombaseTraceLoggingProvider" Name="1AFF6089-E863-4D36-BDFD-3581F07440BE" NonPagedMemory="true"></EventProvider>
23+
<EventProvider Id="EventProvider_COMSVCS-COMPlus" Name="B46FA1AD-B22D-4362-B072-9F5BA07B046D" NonPagedMemory="true"></EventProvider>
24+
<EventProvider Id="EventProvider_COMADMIN-COMPlus" Name="A0C4702B-51F7-4ea9-9C74-E39952C694B8" NonPagedMemory="true"></EventProvider>
25+
<EventProvider Id="EventProvider_COMPlus-Services" Name="53201895-60E8-4fb0-9643-3F80762D658F" NonPagedMemory="true"></EventProvider>
26+
<EventProvider Id="EventProvider_MicrosoftWindowsComBaseWpp" Name="bda92ae8-9f11-4d49-ba1d-a4c2abca692e" NonPagedMemory="true"></EventProvider>
27+
<EventProvider Id="EventProvider_MicrosoftWindowsDcomScmWpp" Name="9474a749-a98d-4f52-9f45-5b20247e4f01" NonPagedMemory="true"></EventProvider>
28+
<EventProvider Id="EventProvider_Microsoft-Windows-COM" Name="d4263c98-310c-4d97-ba39-b55354f08584" NonPagedMemory="true"></EventProvider>
29+
<EventProvider Id="EventProvider_Microsoft-Windows-Complus" Name="0f177893-4a9c-4709-b921-f432d67f43d5" NonPagedMemory="true"></EventProvider>
30+
<EventProvider Id="EventProvider_Microsoft-Windows-DistributedCOM" Name="1B562E86-B7AA-4131-BADC-B6F3A001407E" NonPagedMemory="true"></EventProvider>
31+
<EventProvider Id="EventProvider_CLBCATQ" Name="097d1686-4038-46be-b551-10fda0387165" NonPagedMemory="true"></EventProvider>
32+
<EventProvider Id="EventProvider_Microsoft-Windows-COMRuntime" Name="bf406804-6afa-46e7-8a48-6c357e1d6d61" NonPagedMemory="true"></EventProvider>
33+
<EventProvider Id="EventProvider_Microsoft-Windows-WinRT-Error" Name="A86F8471-C31D-4FBC-A035-665D06047B03" NonPagedMemory="true"></EventProvider>
34+
<EventProvider Id="EventProvider_Microsoft-Windows-WinTypes-Perf" Name="7913ac64-a5cd-40cd-b096-4e8c4028eaab" NonPagedMemory="true"></EventProvider>
35+
<EventProvider Id="EventProvider_Microsoft-Windows-WinRtClassActivation" Name="f0558438-f56a-5987-47da-040ca757ef05" NonPagedMemory="true"></EventProvider>
36+
<EventProvider Id="EventProvider_Microsoft-Windows-RPC" Name="6AD52B32-D609-4BE9-AE07-CE8DAE937E39" NonPagedMemory="true"></EventProvider>
37+
<EventProvider Id="EventProvider_Microsoft-Windows-RPCSS" Name="d8975f88-7ddb-4ed0-91bf-3adf48c48e0c" NonPagedMemory="true"></EventProvider>
38+
<EventProvider Id="EventProvider_Microsoft-Windows-RPC-Events" Name="F4AED7C7-A898-4627-B053-44A7CAA12FCD" NonPagedMemory="true"></EventProvider>
39+
<EventProvider Id="EventProvider_Microsoft-Windows-RPC-Proxy-LBS" Name="272A979B-34B5-48EC-94F5-7225A59C85A0" NonPagedMemory="true"></EventProvider>
40+
<EventProvider Id="EventProvider_Microsoft-Windows-RPC-Proxy" Name="879b2576-39d1-4c0f-80a4-cc086e02548c" NonPagedMemory="true"></EventProvider>
41+
<EventProvider Id="EventProvider_Microsoft-Windows-RPC-LBS" Name="536caa1f-798d-4cdb-a987-05f79a9f457e" NonPagedMemory="true"></EventProvider>
42+
43+
<Profile Id="COMTrace.Verbose.File" Name="COMTrace" Description="COM events trace" LoggingMode="File" DetailLevel="Verbose">
44+
<Collectors>
45+
<SystemCollectorId Value="SystemCollector">
46+
<SystemProviderId Value="SystemProviderBasic"/>
47+
</SystemCollectorId>
48+
<EventCollectorId Value="EventCollector_MicrosoftWindowsCOMTrace">
49+
<EventProviders>
50+
<EventProviderId Value="EventProvider_CombaseTraceLoggingProvider" />
51+
<EventProviderId Value="EventProvider_COMSVCS-COMPlus" />
52+
<EventProviderId Value="EventProvider_COMADMIN-COMPlus" />
53+
<EventProviderId Value="EventProvider_COMPlus-Services" />
54+
<EventProviderId Value="EventProvider_MicrosoftWindowsComBaseWpp" />
55+
<EventProviderId Value="EventProvider_MicrosoftWindowsDcomScmWpp" />
56+
<EventProviderId Value="EventProvider_Microsoft-Windows-COM" />
57+
<EventProviderId Value="EventProvider_Microsoft-Windows-Complus" />
58+
<EventProviderId Value="EventProvider_Microsoft-Windows-DistributedCOM" />
59+
<EventProviderId Value="EventProvider_CLBCATQ" />
60+
<EventProviderId Value="EventProvider_Microsoft-Windows-COMRuntime" />
61+
<EventProviderId Value="EventProvider_Microsoft-Windows-WinRT-Error" />
62+
<EventProviderId Value="EventProvider_Microsoft-Windows-WinTypes-Perf" />
63+
<EventProviderId Value="EventProvider_Microsoft-Windows-WinRtClassActivation" />
64+
<EventProviderId Value="EventProvider_Microsoft-Windows-RPC" />
65+
<EventProviderId Value="EventProvider_Microsoft-Windows-RPCSS" />
66+
<EventProviderId Value="EventProvider_Microsoft-Windows-RPC-Events" />
67+
<EventProviderId Value="EventProvider_Microsoft-Windows-RPC-Proxy-LBS" />
68+
<EventProviderId Value="EventProvider_Microsoft-Windows-RPC-Proxy" />
69+
<EventProviderId Value="EventProvider_Microsoft-Windows-RPC-LBS" />
70+
</EventProviders>
71+
</EventCollectorId>
72+
</Collectors>
73+
74+
<TraceMergeProperties>
75+
<TraceMergeProperty Id="BaseVerboseTraceMergeProperties" Name="BaseTraceMergeProperties">
76+
<DeletePreMergedTraceFiles Value="true" />
77+
<FileCompression Value="false" />
78+
<InjectOnly Value="false" />
79+
<SkipMerge Value="false" />
80+
<CustomEvents>
81+
<CustomEvent Value="ImageId" />
82+
<CustomEvent Value="BuildInfo" />
83+
<CustomEvent Value="VolumeMapping" />
84+
<CustomEvent Value="EventMetadata" />
85+
<CustomEvent Value="PerfTrackMetadata" />
86+
<CustomEvent Value="WinSAT" />
87+
<CustomEvent Value="NetworkInterface" />
88+
</CustomEvents>
89+
</TraceMergeProperty>
90+
</TraceMergeProperties>
91+
</Profile>
92+
93+
</Profiles>
94+
</WindowsPerformanceRecorder>

guides/com-troubleshooting.md

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,16 @@ redirect_from:
2020
- [Tracing COM methods](#tracing-com-methods)
2121
- [Stopping the COM monitor](#stopping-the-com-monitor)
2222
- [Observing COM interactions outside WinDbg](#observing-com-interactions-outside-windbg)
23+
- [Windows Performance Recorder \(wpr.exe\)](#windows-performance-recorder-wprexe)
24+
- [Process Monitor](#process-monitor)
25+
- [wtrace](#wtrace)
2326
- [Troubleshooting .NET COM interop](#troubleshooting-net-com-interop)
2427
- [Links](#links)
2528

2629
<!-- /MarkdownTOC -->
2730

28-
## Quick introduction to COM
31+
Quick introduction to COM
32+
-------------------------
2933

3034
In COM, everything is about interfaces. In old times, when various compiler vendors were fighting over whose "standard" was better, the only reliable way to call C++ class methods contained in third-party libraries was to use virtual tables. As its name suggests virtual table is a table, to be precise, a table of addresses (pointers). The "virtual" adjective relates to the fact that our table's addresses point to virtual methods. If you're familiar with object programming (you plan to debug COM, so you should!), you probably thought of inheritance and abstract classes. And that's correct! The abstract class is how we implement interfaces in C++ (to be more precise [an abstract class with pure virtual methods](https://en.cppreference.com/w/cpp/language/abstract_class)). Now, COM is all about passing pointers to those various virtual tables which happen to have GUID identifiers. The most important interface (parent of all interfaces) is `IUnkown`. Every COM interface must inherit from this interface. Why? For two reasons: to manage the object lifetime and to access all the other interfaces that our object may implement (or, in other words, to find all virtual tables our object is aware of). As this interface is so important, let's have a quick look at its definition:
3135

@@ -122,7 +126,8 @@ Registered VTables for IID:
122126
- Module: protoss, CLSID: {F5353C58-CFD9-4204-8D92-D274C7578B53} (Nexus), VTable offset: 0x37710
123127
```
124128
125-
## Troubleshooting COM in WinDbg
129+
Troubleshooting COM in WinDbg
130+
-----------------------------
126131
127132
### Monitoring COM objects in a process
128133
@@ -253,25 +258,51 @@ If comon can't decode a given parameter, you may use the **dx** command with com
253258
254259
Run the **!comon detach** command to stop the COM monitor. This command will remove all the comon breakpoints and debugging session data, but you can still examine COM metadata with the cometa command.
255260
256-
## Observing COM interactions outside WinDbg
261+
Observing COM interactions outside WinDbg
262+
-----------------------------------------
263+
264+
Sometimes we only need basic information about COM interactions, such as which objects are used and how they are launched. While WinDbg can be overkill for such scenarios, there are several simpler tools we can use to collect this additional information.
265+
266+
### Windows Performance Recorder (wpr.exe)
267+
268+
Let's begin with wpr.exe, a powerful tool that's likely already installed on your system. WPR requires profile files to configure tracing sessions. For basic COM event collection, you can use [the ComTrace.wprp profile](https://raw.githubusercontent.com/microsoft/winget-cli/refs/heads/master/tools/COMTrace/ComTrace.wprp) from [the winget-cli repository](https://github.com/microsoft/winget-cli). I've also created an enhanced profile, adding providers found in the [TSS scripts](https://learn.microsoft.com/en-us/troubleshoot/windows-client/windows-tss/introduction-to-troubleshootingscript-toolset-tss), which you can download **[here](/assets/other/WTComTrace.wprp)**. You can use those profiles either solely or in combination with other profiles, as shown in the examples below.
269+
270+
```shell
271+
# Collect only COM events
272+
wpr.exe -start .\WTComTrace.wprp -filemode
273+
# Run COM apps ...
274+
# Stop the trace when done
275+
wpr -stop C:\temp\comtrace.etl
257276
258-
Sometimes we require only basic information about COM interactions, for example, which objects are used and how they are launched. Using WinDbg for such scenarios could be too much burden. Fortunately, it is pretty straightforward to extract this information by looking at registry and process system events. And tools that may help here are [Process Monitor](https://learn.microsoft.com/en-us/sysinternals/downloads/procmon) or [wtrace](https://github.com/lowleveldesign/wtrace).
277+
# Collect COM events with CPU sampling
278+
wpr.exe -start CPU -start .\WTComTrace.wprp -filemode
279+
# Run COM apps ...
280+
# Stop the trace when done
281+
wpr -stop C:\temp\comtrace.etl
282+
```
283+
284+
Some providers are the [legacy WPP providers](https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/wpp-software-tracing), which require TMF files to read the collected events. Fortunately, the PDB file for compbase.dll contains the required TMF data and we can decode those events. To view the collected data, open the ETL file in **[Windows Performance Analyzer (WPA)](https://learn.microsoft.com/en-us/windows-hardware/test/wpt/windows-performance-analyzer)**. Remember to load symbols first (check [the Windows configuration guide](guides/configuring-windows-for-effective-troubleshooting/#configuring-debug-symbols) how to configure symbols globally in the system), then navigate to the **Generic Events** category and open the **WPP Trace** view.
285+
286+
### Process Monitor
259287

260-
In **Process Monitor**, we can include Registry and Process events and events where Path contains `\CLSID\` or `\AppID` strings or ends with `.dll`, as in the image below:
288+
In **[Process Monitor](https://learn.microsoft.com/en-us/sysinternals/downloads/procmon)**, we can include Registry and Process events and events where Path contains `\CLSID\` or `\AppID` strings or ends with `.dll`, as in the image below:
261289

262290
![](/assets/img/procmon-filters.png)
263291

264292
The collected events should tell us which COM objects the application initiated and in which way. For example, if procmon shows a DLL path read from the `InprocServer32` and then we see this dll loaded, we may assume that the application created a given COM object (the event call stack may be an additional proof). If the COM server runs in a standalone process or a remote machine, other keys will be queried. We may then check the Process Tree or Network events for more details. [COM registry keys official documentation](https://learn.microsoft.com/en-us/windows/win32/com/com-registry-keys) is thorough, so please consult it to learn more.
265293

266-
In **wtrace**, we need to pick the proper handlers and define filters. An example command line might look as follows:
294+
### wtrace
267295

268-
```
296+
In **[wtrace](https://github.com/lowleveldesign/wtrace)**, we need to pick the proper handlers and define filters. An example command line might look as follows:
297+
298+
```shell
269299
wtrace --handlers registry,process,rpc -f 'path ~ \CLSID\' -f 'path ~ \AppID\' -f 'path ~ rpc' -f 'pname = ProtossComClient'
270300
```
271301

272302
As you can see, wtrace may additionally show information about RPC (Remote Procedure Call) events.
273303

274-
## Troubleshooting .NET COM interop
304+
Troubleshooting .NET COM interop
305+
--------------------------------
275306

276307
A native COM object must be wrapped into a Runtime Callable Wrapper (RCW) to be accessible to managed code. RCW binds a managed object (for example, `System.__Com`) and a native COM class instance. COM Callable Wrappers (CCW) work in the opposite direction - thanks to them, we may expose .NET objects to the COM world. Interestingly, the object interop usage is saved in the object's SyncBlock. Therefore, it should not come as a surprise that the **!syncblk** command from [the SOS extension](https://learn.microsoft.com/en-us/dotnet/core/diagnostics/sos-debugging-extension) presents information about RCWs and CCWs:
277308

@@ -402,7 +433,8 @@ Finally, to find who is keeping our managed object alive, we could use the **!gc
402433
.foreach (addr { !DumpHeap -short -type System.__ComObject }) { !gcroot addr }
403434
```
404435

405-
## Links
436+
Links
437+
-----
406438

407439
- ["Essential COM"](https://archive.org/details/essentialcom00boxd) by Don Box
408440
- ["Inside OLE"](https://github.com/kraigb/InsideOLE) by Kraig Brockschmidt (Kraig published the whole book with source code on GitHub!)

guides/windbg.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ Installing WinDbg
7676

7777
### WinDbgX (WinDbgNext, formely WinDbg Preview)
7878

79-
On modern systems download the [appinstaller](https://learn.microsoft.com/en-us/windows-hardware/drivers/debugger/) file and choose Install in the context menu. If you are on Windows Server 2019 and you don't see the Install option in the context menu, there is a big chance you're missing the App Installer package on your system. In that case, you may use **[this PowerShell script](/assets/windbg-install.ps1.txt)** ([created by @Izybkr](https://github.com/microsoftfeedback/WinDbg-Feedback/issues/19#issuecomment-1513926394) with my minor updates to make it work with latest WinDbg releases).
79+
On modern systems download the [appinstaller](https://learn.microsoft.com/en-us/windows-hardware/drivers/debugger/) file and choose Install in the context menu. If you are on Windows Server 2019 and you don't see the Install option in the context menu, there is a big chance you're missing the App Installer package on your system. In that case, you may download and run **[this PowerShell script](/assets/other/windbg-install.ps1.txt)** ([created by @Izybkr](https://github.com/microsoftfeedback/WinDbg-Feedback/issues/19#issuecomment-1513926394) with my minor updates to make it work with latest WinDbg releases).
8080

8181
### Classic WinDbg
8282

0 commit comments

Comments
 (0)