Silhouette 3.2.0
dotnet add package Silhouette --version 3.2.0
NuGet\Install-Package Silhouette -Version 3.2.0
<PackageReference Include="Silhouette" Version="3.2.0" />
<PackageVersion Include="Silhouette" Version="3.2.0" />
<PackageReference Include="Silhouette" />
paket add Silhouette --version 3.2.0
#r "nuget: Silhouette, 3.2.0"
#:package Silhouette@3.2.0
#addin nuget:?package=Silhouette&version=3.2.0
#tool nuget:?package=Silhouette&version=3.2.0
Silhouette - A library to build .NET profilers in .NET
Quick start
Create a new C# NativeAOT project. Reference the Silhouette nuget package and add a class inheriting from Silhouette.CorProfilerCallback11Base (you can use a different version of CorProfilerCallbackBase depending on the version of .NET you're targeting). Override the Initialize method. It will be called with the highest version number of ICorProfilerInfo supported by the target runtime.
using Silhouette;
internal partial class CorProfiler : CorProfilerCallback11Base
{
protected override HResult Initialize(int iCorProfilerInfoVersion)
{
if (iCorProfilerInfoVersion < 11)
{
return HResult.E_FAIL;
}
var result = ICorProfilerInfo11.SetEventMask(COR_PRF_MONITOR.COR_PRF_ENABLE_STACK_SNAPSHOT | COR_PRF_MONITOR.COR_PRF_MONITOR_THREADS);
return result;
}
}
You also need to expose a DllGetClassObject method that will be called by the .NET runtime when initializing the profiler. Use the built-in ClassFactory implementation and give it an instance of your CorProfiler class.
using Silhouette;
using System.Runtime.InteropServices;
internal class DllMain
{
[UnmanagedCallersOnly(EntryPoint = "DllGetClassObject")]
public static unsafe HResult DllGetClassObject(Guid* rclsid, Guid* riid, nint* ppv)
{
// Use your own profiler GUID here
if (*rclsid != new Guid("0A96F866-D763-4099-8E4E-ED1801BE9FBC"))
{
return HResult.E_NOINTERFACE;
}
*ppv = ClassFactory.For(new CorProfiler());
return 0;
}
}
CorProfilerXxBase offers base virtual methods for all ICorProfilerCallback methods, so override the ones you're interested in:
protected override HResult ThreadCreated(ThreadId threadId)
{
Console.WriteLine($"Thread created: {threadId.Value}");
return HResult.S_OK;
}
Use the ICorProfilerInfoXx fields to access the ICorProfilerInfo APIs:
private unsafe string ResolveMethodName(nint ip)
{
try
{
var functionId = ICorProfilerInfo11.GetFunctionFromIP(ip).ThrowIfFailed();
var functionInfo = ICorProfilerInfo2.GetFunctionInfo(functionId).ThrowIfFailed();
using var metaDataImport = ICorProfilerInfo2.GetModuleMetaDataImport(functionInfo.ModuleId, CorOpenFlags.ofRead).ThrowIfFailed().Wrap();
var methodProperties = metaDataImport.Value.GetMethodProps(new MdMethodDef(functionInfo.Token)).ThrowIfFailed();
var typeDefProps = metaDataImport.Value.GetTypeDefProps(methodProperties.Class).ThrowIfFailed();
return $"{typeDefProps.TypeName}.{methodProperties.Name}";
}
catch (Win32Exception)
{
return "<unknown>";
}
}
Most methods return an instance of HResult<T>. You can deconstruct it into a (HResult error, T result) and manually check the error code. You can also use the ThrowIfFailed() method that will return only the result and throw a Win32Exception if the error code is not S_OK.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net9.0
- NativeObjects (>= 1.4.0)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Silhouette:
| Package | Downloads |
|---|---|
|
Silhouette.IL
IL Rewriter for Silhouette. |
GitHub repositories
This package is not used by any popular GitHub repositories.
- Add ProfilerAttribute to source-generate the DllGetClassObject export