Decyphering methods signature with .NET profiling APIs


After introducing the CLR profiling API by tracing managed methods calls, then dealing with assemblies and types, it is time to look at methods signatures. Remember that the starting point is the FunctionID received by the Enter callback each time a method is executed.

The question answered by this post is how to build the signature of the method given a FunctionID.

A method signature is built from its return value (or void), its name and a list of parameters. All these details are stored in the module metadata generated by the C# compiler. So the first step is to get the metadata token corresponding to a FunctionID thanks to ICorProfilerInfo::GetFunctionInfo:

Next, use the IMetaDataImport corresponding to the module to call GetMethodProps and pass the function metadata token:

The return type and parameters type of the function are encoded in a binary format defined in the ECMA-335 specification. This binary blob is pointed to by the pSig parameter. Hopefully, you don’t have to implement a blob signature parser yourself. This has been done my Rico Mariani or Peter Sollich and it relies on low level helpers from cor.h such as CorSigUncompressData.

Here is an example of a signature blob for a non-static method returning void and accepting a float and a double as parameters:

The well-known types are encoded and available as ELEMENT_TYPE_xxx constants from corhdr.h.

For custom types identified as ELEMENT_TYPE_CLASS for reference types or ELEMENT_TYPE_VALUETYPE for value types, the metadata token of the type is “compressed” as part of the signature (see CorSigUncompressToken in cor.h for implementation details). If the type is defined in the same assembly as the method, you get a TypeDef token (starting with 02) used to call IMetaDataImport::GetTypeDefProps. If not, it will be a TypeRef token (starting with 01) used to call IMetaDataImport::GetTypeRefProps.

More on typeRef and typeDef later.

This is nice but since the parameter name is not encoded in the signature blob, you have to work more to get it. First, you have to call IMetaDataImport::EnumParams, to get the metadata token mdParamDef for each parameter:

Generic methods have more complicated signatures to compute

The following figure shows how to handle generic methods:

The main change for such a generic method is that, in the signature blob, you will get the number of generic arguments just after the total parameters count and the first “calling convention” data will be IMAGE_CEE_CS_CALLCONV_GENERIC. The other difference is how to deal with generic parameters in the blob that will all share the same ELEMENT_TYPE_MVAR value followed by a position (starting from 0). This is the position in the array returned by ICorProfilerInfo2::GetFunctionInfo2 for the ClassID.

The final code should look like the following:

One last detail before looking for the parameters value in the next post: for ALL reference types, the same implementation is generated by the JIT compiler. If you think about it, there is no need to implement a List<string> in a different way than a List of any other reference type: they all deal with references (i.e. addresses). The name picked by the CLR team to identify this “generic reference type” is System.__Canon that stands for “canonical”. So expect to receive that type name a lot!





Loves to understand how things work (MVP Developer Technologies)

Love podcasts or audiobooks? Learn on the go with our new app.

Postman opens in 14 seconds. What went wrong?

How to Build a Fully Automated Web Scraping Pipeline for Analytics Dashboard

What is Interpreter? Explain How python interpreter works.

Reduce size of docker image with spring boot application

Do You want to create your own OS

Securing access to Traefik v2 Dashboard on Kubernetes using Basic Authentication

Example of one of the internal routes used by Traefik.

Writing Code

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Christophe Nasarre

Christophe Nasarre

Loves to understand how things work (MVP Developer Technologies)

More from Medium

Release the limits of Github Actions with self-hosted runners

Unix Domain Sockets in .NET 6 — Basics and Real-World Examples

Hands-On: Distributed cache using Redis + Minimal API with .NET Core 6

dotnet retrieve JSON (nested object) + file without using a customer model binder