681 lines
28 KiB
C#
681 lines
28 KiB
C#
|
// dnlib: See LICENSE.txt for more info
|
||
|
|
||
|
using System;
|
||
|
using System.Collections.Generic;
|
||
|
using System.IO;
|
||
|
using dnlib.DotNet.MD;
|
||
|
using dnlib.IO;
|
||
|
|
||
|
namespace dnlib.DotNet {
|
||
|
/// <summary>
|
||
|
/// Helps <see cref="SignatureReader"/> resolve types
|
||
|
/// </summary>
|
||
|
public interface ISignatureReaderHelper {
|
||
|
/// <summary>
|
||
|
/// Resolves a <see cref="ITypeDefOrRef"/>
|
||
|
/// </summary>
|
||
|
/// <param name="codedToken">A <c>TypeDefOrRef</c> coded token</param>
|
||
|
/// <param name="gpContext">Generic parameter context</param>
|
||
|
/// <returns>A <see cref="ITypeDefOrRef"/> or <c>null</c> if <paramref name="codedToken"/>
|
||
|
/// is invalid</returns>
|
||
|
ITypeDefOrRef ResolveTypeDefOrRef(uint codedToken, GenericParamContext gpContext);
|
||
|
|
||
|
/// <summary>
|
||
|
/// Converts the address of a <see cref="Type"/> to a <see cref="TypeSig"/>
|
||
|
/// </summary>
|
||
|
/// <seealso cref="Emit.MethodTableToTypeConverter"/>
|
||
|
/// <param name="address">Address of <see cref="Type"/>. This is also known as the
|
||
|
/// method table and has the same value as <see cref="RuntimeTypeHandle.Value"/></param>
|
||
|
/// <returns>A <see cref="TypeSig"/> or <c>null</c> if not supported</returns>
|
||
|
TypeSig ConvertRTInternalAddress(IntPtr address);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Reads signatures from the #Blob stream
|
||
|
/// </summary>
|
||
|
public struct SignatureReader {
|
||
|
// .NET Core and .NET Framework limit arrays to 32 dimensions. Use a bigger limit
|
||
|
// so it's possible to read some bad MD, but not big enough to allocate a ton of mem.
|
||
|
const uint MaxArrayRank = 64;
|
||
|
|
||
|
readonly ISignatureReaderHelper helper;
|
||
|
readonly ICorLibTypes corLibTypes;
|
||
|
DataReader reader;
|
||
|
readonly GenericParamContext gpContext;
|
||
|
RecursionCounter recursionCounter;
|
||
|
|
||
|
/// <summary>
|
||
|
/// Reads a signature from the #Blob stream
|
||
|
/// </summary>
|
||
|
/// <param name="readerModule">Reader module</param>
|
||
|
/// <param name="sig">#Blob stream offset of signature</param>
|
||
|
/// <returns>A new <see cref="CallingConventionSig"/> instance or <c>null</c> if
|
||
|
/// <paramref name="sig"/> is invalid.</returns>
|
||
|
public static CallingConventionSig ReadSig(ModuleDefMD readerModule, uint sig) =>
|
||
|
ReadSig(readerModule, sig, new GenericParamContext());
|
||
|
|
||
|
/// <summary>
|
||
|
/// Reads a signature from the #Blob stream
|
||
|
/// </summary>
|
||
|
/// <param name="readerModule">Reader module</param>
|
||
|
/// <param name="sig">#Blob stream offset of signature</param>
|
||
|
/// <param name="gpContext">Generic parameter context</param>
|
||
|
/// <returns>A new <see cref="CallingConventionSig"/> instance or <c>null</c> if
|
||
|
/// <paramref name="sig"/> is invalid.</returns>
|
||
|
public static CallingConventionSig ReadSig(ModuleDefMD readerModule, uint sig, GenericParamContext gpContext) {
|
||
|
try {
|
||
|
var reader = new SignatureReader(readerModule, sig, gpContext);
|
||
|
if (reader.reader.Length == 0)
|
||
|
return null;
|
||
|
var csig = reader.ReadSig();
|
||
|
if (csig is not null)
|
||
|
csig.ExtraData = reader.GetExtraData();
|
||
|
return csig;
|
||
|
}
|
||
|
catch {
|
||
|
return null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Reads a <see cref="CallingConventionSig"/> signature
|
||
|
/// </summary>
|
||
|
/// <param name="module">The module where the signature is located in</param>
|
||
|
/// <param name="signature">The signature data</param>
|
||
|
/// <returns>A new <see cref="CallingConventionSig"/> instance or <c>null</c> if
|
||
|
/// <paramref name="signature"/> is invalid.</returns>
|
||
|
public static CallingConventionSig ReadSig(ModuleDefMD module, byte[] signature) =>
|
||
|
ReadSig(module, module.CorLibTypes, ByteArrayDataReaderFactory.CreateReader(signature), new GenericParamContext());
|
||
|
|
||
|
/// <summary>
|
||
|
/// Reads a <see cref="CallingConventionSig"/> signature
|
||
|
/// </summary>
|
||
|
/// <param name="module">The module where the signature is located in</param>
|
||
|
/// <param name="signature">The signature data</param>
|
||
|
/// <param name="gpContext">Generic parameter context</param>
|
||
|
/// <returns>A new <see cref="CallingConventionSig"/> instance or <c>null</c> if
|
||
|
/// <paramref name="signature"/> is invalid.</returns>
|
||
|
public static CallingConventionSig ReadSig(ModuleDefMD module, byte[] signature, GenericParamContext gpContext) =>
|
||
|
ReadSig(module, module.CorLibTypes, ByteArrayDataReaderFactory.CreateReader(signature), gpContext);
|
||
|
|
||
|
/// <summary>
|
||
|
/// Reads a <see cref="CallingConventionSig"/> signature
|
||
|
/// </summary>
|
||
|
/// <param name="module">The module where the signature is located in</param>
|
||
|
/// <param name="signature">The signature reader</param>
|
||
|
/// <returns>A new <see cref="CallingConventionSig"/> instance or <c>null</c> if
|
||
|
/// <paramref name="signature"/> is invalid.</returns>
|
||
|
public static CallingConventionSig ReadSig(ModuleDefMD module, DataReader signature) =>
|
||
|
ReadSig(module, module.CorLibTypes, signature, new GenericParamContext());
|
||
|
|
||
|
/// <summary>
|
||
|
/// Reads a <see cref="CallingConventionSig"/> signature
|
||
|
/// </summary>
|
||
|
/// <param name="module">The module where the signature is located in</param>
|
||
|
/// <param name="signature">The signature reader</param>
|
||
|
/// <param name="gpContext">Generic parameter context</param>
|
||
|
/// <returns>A new <see cref="CallingConventionSig"/> instance or <c>null</c> if
|
||
|
/// <paramref name="signature"/> is invalid.</returns>
|
||
|
public static CallingConventionSig ReadSig(ModuleDefMD module, DataReader signature, GenericParamContext gpContext) =>
|
||
|
ReadSig(module, module.CorLibTypes, signature, gpContext);
|
||
|
|
||
|
/// <summary>
|
||
|
/// Reads a <see cref="CallingConventionSig"/> signature
|
||
|
/// </summary>
|
||
|
/// <param name="helper">Token resolver</param>
|
||
|
/// <param name="corLibTypes">A <see cref="ICorLibTypes"/> instance</param>
|
||
|
/// <param name="signature">The signature data</param>
|
||
|
/// <returns>A new <see cref="CallingConventionSig"/> instance or <c>null</c> if
|
||
|
/// <paramref name="signature"/> is invalid.</returns>
|
||
|
public static CallingConventionSig ReadSig(ISignatureReaderHelper helper, ICorLibTypes corLibTypes, byte[] signature) =>
|
||
|
ReadSig(helper, corLibTypes, ByteArrayDataReaderFactory.CreateReader(signature), new GenericParamContext());
|
||
|
|
||
|
/// <summary>
|
||
|
/// Reads a <see cref="CallingConventionSig"/> signature
|
||
|
/// </summary>
|
||
|
/// <param name="helper">Token resolver</param>
|
||
|
/// <param name="corLibTypes">A <see cref="ICorLibTypes"/> instance</param>
|
||
|
/// <param name="signature">The signature data</param>
|
||
|
/// <param name="gpContext">Generic parameter context</param>
|
||
|
/// <returns>A new <see cref="CallingConventionSig"/> instance or <c>null</c> if
|
||
|
/// <paramref name="signature"/> is invalid.</returns>
|
||
|
public static CallingConventionSig ReadSig(ISignatureReaderHelper helper, ICorLibTypes corLibTypes, byte[] signature, GenericParamContext gpContext) =>
|
||
|
ReadSig(helper, corLibTypes, ByteArrayDataReaderFactory.CreateReader(signature), gpContext);
|
||
|
|
||
|
/// <summary>
|
||
|
/// Reads a <see cref="CallingConventionSig"/> signature
|
||
|
/// </summary>
|
||
|
/// <param name="helper">Token resolver</param>
|
||
|
/// <param name="corLibTypes">A <see cref="ICorLibTypes"/> instance</param>
|
||
|
/// <param name="signature">The signature reader</param>
|
||
|
/// <returns>A new <see cref="CallingConventionSig"/> instance or <c>null</c> if
|
||
|
/// <paramref name="signature"/> is invalid.</returns>
|
||
|
public static CallingConventionSig ReadSig(ISignatureReaderHelper helper, ICorLibTypes corLibTypes, DataReader signature) =>
|
||
|
ReadSig(helper, corLibTypes, signature, new GenericParamContext());
|
||
|
|
||
|
/// <summary>
|
||
|
/// Reads a <see cref="CallingConventionSig"/> signature
|
||
|
/// </summary>
|
||
|
/// <param name="helper">Token resolver</param>
|
||
|
/// <param name="corLibTypes">A <see cref="ICorLibTypes"/> instance</param>
|
||
|
/// <param name="signature">The signature reader</param>
|
||
|
/// <param name="gpContext">Generic parameter context</param>
|
||
|
/// <returns>A new <see cref="CallingConventionSig"/> instance or <c>null</c> if
|
||
|
/// <paramref name="signature"/> is invalid.</returns>
|
||
|
public static CallingConventionSig ReadSig(ISignatureReaderHelper helper, ICorLibTypes corLibTypes, DataReader signature, GenericParamContext gpContext) {
|
||
|
try {
|
||
|
var reader = new SignatureReader(helper, corLibTypes, ref signature, gpContext);
|
||
|
if (reader.reader.Length == 0)
|
||
|
return null;
|
||
|
return reader.ReadSig();
|
||
|
}
|
||
|
catch {
|
||
|
return null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Reads a type signature from the #Blob stream
|
||
|
/// </summary>
|
||
|
/// <param name="readerModule">Reader module</param>
|
||
|
/// <param name="sig">#Blob stream offset of signature</param>
|
||
|
/// <returns>A new <see cref="TypeSig"/> instance or <c>null</c> if
|
||
|
/// <paramref name="sig"/> is invalid.</returns>
|
||
|
public static TypeSig ReadTypeSig(ModuleDefMD readerModule, uint sig) =>
|
||
|
ReadTypeSig(readerModule, sig, new GenericParamContext());
|
||
|
|
||
|
/// <summary>
|
||
|
/// Reads a type signature from the #Blob stream
|
||
|
/// </summary>
|
||
|
/// <param name="readerModule">Reader module</param>
|
||
|
/// <param name="sig">#Blob stream offset of signature</param>
|
||
|
/// <param name="gpContext">Generic parameter context</param>
|
||
|
/// <returns>A new <see cref="TypeSig"/> instance or <c>null</c> if
|
||
|
/// <paramref name="sig"/> is invalid.</returns>
|
||
|
public static TypeSig ReadTypeSig(ModuleDefMD readerModule, uint sig, GenericParamContext gpContext) {
|
||
|
try {
|
||
|
var reader = new SignatureReader(readerModule, sig, gpContext);
|
||
|
return reader.ReadType();
|
||
|
}
|
||
|
catch {
|
||
|
return null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Reads a type signature from the #Blob stream
|
||
|
/// </summary>
|
||
|
/// <param name="readerModule">Reader module</param>
|
||
|
/// <param name="sig">#Blob stream offset of signature</param>
|
||
|
/// <param name="extraData">If there's any extra data after the signature, it's saved
|
||
|
/// here, else this will be <c>null</c></param>
|
||
|
/// <returns>A new <see cref="TypeSig"/> instance or <c>null</c> if
|
||
|
/// <paramref name="sig"/> is invalid.</returns>
|
||
|
public static TypeSig ReadTypeSig(ModuleDefMD readerModule, uint sig, out byte[] extraData) =>
|
||
|
ReadTypeSig(readerModule, sig, new GenericParamContext(), out extraData);
|
||
|
|
||
|
/// <summary>
|
||
|
/// Reads a type signature from the #Blob stream
|
||
|
/// </summary>
|
||
|
/// <param name="readerModule">Reader module</param>
|
||
|
/// <param name="sig">#Blob stream offset of signature</param>
|
||
|
/// <param name="gpContext">Generic parameter context</param>
|
||
|
/// <param name="extraData">If there's any extra data after the signature, it's saved
|
||
|
/// here, else this will be <c>null</c></param>
|
||
|
/// <returns>A new <see cref="TypeSig"/> instance or <c>null</c> if
|
||
|
/// <paramref name="sig"/> is invalid.</returns>
|
||
|
public static TypeSig ReadTypeSig(ModuleDefMD readerModule, uint sig, GenericParamContext gpContext, out byte[] extraData) {
|
||
|
try {
|
||
|
var reader = new SignatureReader(readerModule, sig, gpContext);
|
||
|
TypeSig ts;
|
||
|
try {
|
||
|
ts = reader.ReadType();
|
||
|
}
|
||
|
catch (IOException) {
|
||
|
reader.reader.Position = 0;
|
||
|
ts = null;
|
||
|
}
|
||
|
extraData = reader.GetExtraData();
|
||
|
return ts;
|
||
|
}
|
||
|
catch {
|
||
|
extraData = null;
|
||
|
return null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Reads a <see cref="TypeSig"/> signature
|
||
|
/// </summary>
|
||
|
/// <param name="module">The module where the signature is located in</param>
|
||
|
/// <param name="signature">The signature data</param>
|
||
|
/// <returns>A new <see cref="TypeSig"/> instance or <c>null</c> if
|
||
|
/// <paramref name="signature"/> is invalid.</returns>
|
||
|
public static TypeSig ReadTypeSig(ModuleDefMD module, byte[] signature) =>
|
||
|
ReadTypeSig(module, module.CorLibTypes, ByteArrayDataReaderFactory.CreateReader(signature), new GenericParamContext());
|
||
|
|
||
|
/// <summary>
|
||
|
/// Reads a <see cref="TypeSig"/> signature
|
||
|
/// </summary>
|
||
|
/// <param name="module">The module where the signature is located in</param>
|
||
|
/// <param name="signature">The signature data</param>
|
||
|
/// <param name="gpContext">Generic parameter context</param>
|
||
|
/// <returns>A new <see cref="TypeSig"/> instance or <c>null</c> if
|
||
|
/// <paramref name="signature"/> is invalid.</returns>
|
||
|
public static TypeSig ReadTypeSig(ModuleDefMD module, byte[] signature, GenericParamContext gpContext) =>
|
||
|
ReadTypeSig(module, module.CorLibTypes, ByteArrayDataReaderFactory.CreateReader(signature), gpContext);
|
||
|
|
||
|
/// <summary>
|
||
|
/// Reads a <see cref="TypeSig"/> signature
|
||
|
/// </summary>
|
||
|
/// <param name="module">The module where the signature is located in</param>
|
||
|
/// <param name="signature">The signature reader</param>
|
||
|
/// <returns>A new <see cref="TypeSig"/> instance or <c>null</c> if
|
||
|
/// <paramref name="signature"/> is invalid.</returns>
|
||
|
public static TypeSig ReadTypeSig(ModuleDefMD module, DataReader signature) =>
|
||
|
ReadTypeSig(module, module.CorLibTypes, signature, new GenericParamContext());
|
||
|
|
||
|
/// <summary>
|
||
|
/// Reads a <see cref="TypeSig"/> signature
|
||
|
/// </summary>
|
||
|
/// <param name="module">The module where the signature is located in</param>
|
||
|
/// <param name="signature">The signature reader</param>
|
||
|
/// <param name="gpContext">Generic parameter context</param>
|
||
|
/// <returns>A new <see cref="TypeSig"/> instance or <c>null</c> if
|
||
|
/// <paramref name="signature"/> is invalid.</returns>
|
||
|
public static TypeSig ReadTypeSig(ModuleDefMD module, DataReader signature, GenericParamContext gpContext) =>
|
||
|
ReadTypeSig(module, module.CorLibTypes, signature, gpContext);
|
||
|
|
||
|
/// <summary>
|
||
|
/// Reads a <see cref="TypeSig"/> signature
|
||
|
/// </summary>
|
||
|
/// <param name="helper">Token resolver</param>
|
||
|
/// <param name="corLibTypes">A <see cref="ICorLibTypes"/> instance</param>
|
||
|
/// <param name="signature">The signature data</param>
|
||
|
/// <returns>A new <see cref="TypeSig"/> instance or <c>null</c> if
|
||
|
/// <paramref name="signature"/> is invalid.</returns>
|
||
|
public static TypeSig ReadTypeSig(ISignatureReaderHelper helper, ICorLibTypes corLibTypes, byte[] signature) =>
|
||
|
ReadTypeSig(helper, corLibTypes, ByteArrayDataReaderFactory.CreateReader(signature), new GenericParamContext());
|
||
|
|
||
|
/// <summary>
|
||
|
/// Reads a <see cref="TypeSig"/> signature
|
||
|
/// </summary>
|
||
|
/// <param name="helper">Token resolver</param>
|
||
|
/// <param name="corLibTypes">A <see cref="ICorLibTypes"/> instance</param>
|
||
|
/// <param name="signature">The signature data</param>
|
||
|
/// <param name="gpContext">Generic parameter context</param>
|
||
|
/// <returns>A new <see cref="TypeSig"/> instance or <c>null</c> if
|
||
|
/// <paramref name="signature"/> is invalid.</returns>
|
||
|
public static TypeSig ReadTypeSig(ISignatureReaderHelper helper, ICorLibTypes corLibTypes, byte[] signature, GenericParamContext gpContext) =>
|
||
|
ReadTypeSig(helper, corLibTypes, ByteArrayDataReaderFactory.CreateReader(signature), gpContext);
|
||
|
|
||
|
/// <summary>
|
||
|
/// Reads a <see cref="TypeSig"/> signature
|
||
|
/// </summary>
|
||
|
/// <param name="helper">Token resolver</param>
|
||
|
/// <param name="corLibTypes">A <see cref="ICorLibTypes"/> instance</param>
|
||
|
/// <param name="signature">The signature reader</param>
|
||
|
/// <returns>A new <see cref="TypeSig"/> instance or <c>null</c> if
|
||
|
/// <paramref name="signature"/> is invalid.</returns>
|
||
|
public static TypeSig ReadTypeSig(ISignatureReaderHelper helper, ICorLibTypes corLibTypes, DataReader signature) =>
|
||
|
ReadTypeSig(helper, corLibTypes, signature, new GenericParamContext());
|
||
|
|
||
|
/// <summary>
|
||
|
/// Reads a <see cref="TypeSig"/> signature
|
||
|
/// </summary>
|
||
|
/// <param name="helper">Token resolver</param>
|
||
|
/// <param name="corLibTypes">A <see cref="ICorLibTypes"/> instance</param>
|
||
|
/// <param name="signature">The signature reader</param>
|
||
|
/// <param name="gpContext">Generic parameter context</param>
|
||
|
/// <returns>A new <see cref="TypeSig"/> instance or <c>null</c> if
|
||
|
/// <paramref name="signature"/> is invalid.</returns>
|
||
|
public static TypeSig ReadTypeSig(ISignatureReaderHelper helper, ICorLibTypes corLibTypes, DataReader signature, GenericParamContext gpContext) =>
|
||
|
ReadTypeSig(helper, corLibTypes, signature, gpContext, out var extraData);
|
||
|
|
||
|
/// <summary>
|
||
|
/// Reads a <see cref="TypeSig"/> signature
|
||
|
/// </summary>
|
||
|
/// <param name="helper">Token resolver</param>
|
||
|
/// <param name="corLibTypes">A <see cref="ICorLibTypes"/> instance</param>
|
||
|
/// <param name="signature">The signature data</param>
|
||
|
/// <param name="gpContext">Generic parameter context</param>
|
||
|
/// <param name="extraData">If there's any extra data after the signature, it's saved
|
||
|
/// here, else this will be <c>null</c></param>
|
||
|
/// <returns>A new <see cref="TypeSig"/> instance or <c>null</c> if
|
||
|
/// <paramref name="signature"/> is invalid.</returns>
|
||
|
public static TypeSig ReadTypeSig(ISignatureReaderHelper helper, ICorLibTypes corLibTypes, byte[] signature, GenericParamContext gpContext, out byte[] extraData) =>
|
||
|
ReadTypeSig(helper, corLibTypes, ByteArrayDataReaderFactory.CreateReader(signature), gpContext, out extraData);
|
||
|
|
||
|
/// <summary>
|
||
|
/// Reads a <see cref="TypeSig"/> signature
|
||
|
/// </summary>
|
||
|
/// <param name="helper">Token resolver</param>
|
||
|
/// <param name="corLibTypes">A <see cref="ICorLibTypes"/> instance</param>
|
||
|
/// <param name="signature">The signature reader</param>
|
||
|
/// <param name="gpContext">Generic parameter context</param>
|
||
|
/// <param name="extraData">If there's any extra data after the signature, it's saved
|
||
|
/// here, else this will be <c>null</c></param>
|
||
|
/// <returns>A new <see cref="TypeSig"/> instance or <c>null</c> if
|
||
|
/// <paramref name="signature"/> is invalid.</returns>
|
||
|
public static TypeSig ReadTypeSig(ISignatureReaderHelper helper, ICorLibTypes corLibTypes, DataReader signature, GenericParamContext gpContext, out byte[] extraData) {
|
||
|
try {
|
||
|
var reader = new SignatureReader(helper, corLibTypes, ref signature, gpContext);
|
||
|
TypeSig ts;
|
||
|
try {
|
||
|
ts = reader.ReadType();
|
||
|
}
|
||
|
catch (IOException) {
|
||
|
reader.reader.Position = 0;
|
||
|
ts = null;
|
||
|
}
|
||
|
extraData = reader.GetExtraData();
|
||
|
return ts;
|
||
|
}
|
||
|
catch {
|
||
|
extraData = null;
|
||
|
return null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Constructor
|
||
|
/// </summary>
|
||
|
/// <param name="readerModule">Reader module</param>
|
||
|
/// <param name="sig">#Blob stream offset of signature</param>
|
||
|
/// <param name="gpContext">Generic parameter context</param>
|
||
|
SignatureReader(ModuleDefMD readerModule, uint sig, GenericParamContext gpContext) {
|
||
|
helper = readerModule;
|
||
|
corLibTypes = readerModule.CorLibTypes;
|
||
|
reader = readerModule.BlobStream.CreateReader(sig);
|
||
|
this.gpContext = gpContext;
|
||
|
recursionCounter = new RecursionCounter();
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Constructor
|
||
|
/// </summary>
|
||
|
/// <param name="helper">Token resolver</param>
|
||
|
/// <param name="corLibTypes">A <see cref="ICorLibTypes"/> instance</param>
|
||
|
/// <param name="reader">The signature data</param>
|
||
|
/// <param name="gpContext">Generic parameter context</param>
|
||
|
SignatureReader(ISignatureReaderHelper helper, ICorLibTypes corLibTypes, ref DataReader reader, GenericParamContext gpContext) {
|
||
|
this.helper = helper;
|
||
|
this.corLibTypes = corLibTypes;
|
||
|
this.reader = reader;
|
||
|
this.gpContext = gpContext;
|
||
|
recursionCounter = new RecursionCounter();
|
||
|
}
|
||
|
|
||
|
byte[] GetExtraData() {
|
||
|
if (reader.Position == reader.Length)
|
||
|
return null;
|
||
|
return reader.ReadRemainingBytes();
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Reads the signature
|
||
|
/// </summary>
|
||
|
/// <returns>A new <see cref="CallingConventionSig"/> instance or <c>null</c> if invalid signature</returns>
|
||
|
CallingConventionSig ReadSig() {
|
||
|
if (!recursionCounter.Increment())
|
||
|
return null;
|
||
|
|
||
|
CallingConventionSig result;
|
||
|
var callingConvention = (CallingConvention)reader.ReadByte();
|
||
|
switch (callingConvention & CallingConvention.Mask) {
|
||
|
case CallingConvention.Default:
|
||
|
case CallingConvention.C:
|
||
|
case CallingConvention.StdCall:
|
||
|
case CallingConvention.ThisCall:
|
||
|
case CallingConvention.FastCall:
|
||
|
case CallingConvention.VarArg:
|
||
|
case CallingConvention.Unmanaged:
|
||
|
case CallingConvention.NativeVarArg:
|
||
|
result = ReadMethod(callingConvention);
|
||
|
break;
|
||
|
|
||
|
case CallingConvention.Field:
|
||
|
result = ReadField(callingConvention);
|
||
|
break;
|
||
|
|
||
|
case CallingConvention.LocalSig:
|
||
|
result = ReadLocalSig(callingConvention);
|
||
|
break;
|
||
|
|
||
|
case CallingConvention.Property:
|
||
|
result = ReadProperty(callingConvention);
|
||
|
break;
|
||
|
|
||
|
case CallingConvention.GenericInst:
|
||
|
result = ReadGenericInstMethod(callingConvention);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
result = null;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
recursionCounter.Decrement();
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Reads a <see cref="FieldSig"/>
|
||
|
/// </summary>
|
||
|
/// <param name="callingConvention">First byte of signature</param>
|
||
|
/// <returns>A new <see cref="FieldSig"/> instance</returns>
|
||
|
FieldSig ReadField(CallingConvention callingConvention) => new FieldSig(callingConvention, ReadType());
|
||
|
|
||
|
/// <summary>
|
||
|
/// Reads a <see cref="MethodSig"/>
|
||
|
/// </summary>
|
||
|
/// <param name="callingConvention">First byte of signature</param>
|
||
|
/// <returns>A new <see cref="MethodSig"/> instance</returns>
|
||
|
MethodSig ReadMethod(CallingConvention callingConvention) => ReadSig(new MethodSig(callingConvention));
|
||
|
|
||
|
/// <summary>
|
||
|
/// Reads a <see cref="PropertySig"/>
|
||
|
/// </summary>
|
||
|
/// <param name="callingConvention">First byte of signature</param>
|
||
|
/// <returns>A new <see cref="PropertySig"/> instance</returns>
|
||
|
PropertySig ReadProperty(CallingConvention callingConvention) => ReadSig(new PropertySig(callingConvention));
|
||
|
|
||
|
T ReadSig<T>(T methodSig) where T : MethodBaseSig {
|
||
|
if (methodSig.Generic) {
|
||
|
if (!reader.TryReadCompressedUInt32(out uint count) || count > 0x10000)
|
||
|
return null;
|
||
|
methodSig.GenParamCount = count;
|
||
|
}
|
||
|
|
||
|
if (!reader.TryReadCompressedUInt32(out uint numParams) || numParams > 0x10000 || numParams > reader.BytesLeft)
|
||
|
return null;
|
||
|
|
||
|
methodSig.RetType = ReadType();
|
||
|
|
||
|
var parameters = methodSig.Params;
|
||
|
for (uint i = 0; i < numParams; i++) {
|
||
|
var type = ReadType();
|
||
|
if (type is SentinelSig) {
|
||
|
if (methodSig.ParamsAfterSentinel is null)
|
||
|
methodSig.ParamsAfterSentinel = parameters = new List<TypeSig>((int)(numParams - i));
|
||
|
i--;
|
||
|
}
|
||
|
else
|
||
|
parameters.Add(type);
|
||
|
}
|
||
|
|
||
|
return methodSig;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Reads a <see cref="LocalSig"/>
|
||
|
/// </summary>
|
||
|
/// <param name="callingConvention">First byte of signature</param>
|
||
|
/// <returns>A new <see cref="LocalSig"/> instance</returns>
|
||
|
LocalSig ReadLocalSig(CallingConvention callingConvention) {
|
||
|
if (!reader.TryReadCompressedUInt32(out uint count) || count > 0x10000 || count > reader.BytesLeft)
|
||
|
return null;
|
||
|
var sig = new LocalSig(callingConvention, count);
|
||
|
var locals = sig.Locals;
|
||
|
for (uint i = 0; i < count; i++)
|
||
|
locals.Add(ReadType());
|
||
|
return sig;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Reads a <see cref="GenericInstMethodSig"/>
|
||
|
/// </summary>
|
||
|
/// <param name="callingConvention">First byte of signature</param>
|
||
|
/// <returns>A new <see cref="GenericInstMethodSig"/> instance</returns>
|
||
|
GenericInstMethodSig ReadGenericInstMethod(CallingConvention callingConvention) {
|
||
|
if (!reader.TryReadCompressedUInt32(out uint count) || count > 0x10000 || count > reader.BytesLeft)
|
||
|
return null;
|
||
|
var sig = new GenericInstMethodSig(callingConvention, count);
|
||
|
var args = sig.GenericArguments;
|
||
|
for (uint i = 0; i < count; i++)
|
||
|
args.Add(ReadType());
|
||
|
return sig;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Reads the next type
|
||
|
/// </summary>
|
||
|
/// <param name="allowTypeSpec"><c>true</c> if a <c>TypeSpec</c> is allowed if the next type is a class/value-type</param>
|
||
|
/// <returns>A new <see cref="TypeSig"/> instance or <c>null</c> if invalid element type</returns>
|
||
|
TypeSig ReadType(bool allowTypeSpec = false) {
|
||
|
if (!recursionCounter.Increment())
|
||
|
return null;
|
||
|
|
||
|
uint num, i;
|
||
|
TypeSig nextType, result = null;
|
||
|
switch ((ElementType)reader.ReadByte()) {
|
||
|
case ElementType.Void: result = corLibTypes.Void; break;
|
||
|
case ElementType.Boolean: result = corLibTypes.Boolean; break;
|
||
|
case ElementType.Char: result = corLibTypes.Char; break;
|
||
|
case ElementType.I1: result = corLibTypes.SByte; break;
|
||
|
case ElementType.U1: result = corLibTypes.Byte; break;
|
||
|
case ElementType.I2: result = corLibTypes.Int16; break;
|
||
|
case ElementType.U2: result = corLibTypes.UInt16; break;
|
||
|
case ElementType.I4: result = corLibTypes.Int32; break;
|
||
|
case ElementType.U4: result = corLibTypes.UInt32; break;
|
||
|
case ElementType.I8: result = corLibTypes.Int64; break;
|
||
|
case ElementType.U8: result = corLibTypes.UInt64; break;
|
||
|
case ElementType.R4: result = corLibTypes.Single; break;
|
||
|
case ElementType.R8: result = corLibTypes.Double; break;
|
||
|
case ElementType.String: result = corLibTypes.String; break;
|
||
|
case ElementType.TypedByRef:result = corLibTypes.TypedReference; break;
|
||
|
case ElementType.I: result = corLibTypes.IntPtr; break;
|
||
|
case ElementType.U: result = corLibTypes.UIntPtr; break;
|
||
|
case ElementType.Object: result = corLibTypes.Object; break;
|
||
|
|
||
|
case ElementType.Ptr: result = new PtrSig(ReadType()); break;
|
||
|
case ElementType.ByRef: result = new ByRefSig(ReadType()); break;
|
||
|
case ElementType.ValueType: result = new ValueTypeSig(ReadTypeDefOrRef(allowTypeSpec)); break;
|
||
|
case ElementType.Class: result = new ClassSig(ReadTypeDefOrRef(allowTypeSpec)); break;
|
||
|
case ElementType.FnPtr: result = new FnPtrSig(ReadSig()); break;
|
||
|
case ElementType.SZArray: result = new SZArraySig(ReadType()); break;
|
||
|
case ElementType.CModReqd: result = new CModReqdSig(ReadTypeDefOrRef(true), ReadType()); break;
|
||
|
case ElementType.CModOpt: result = new CModOptSig(ReadTypeDefOrRef(true), ReadType()); break;
|
||
|
case ElementType.Sentinel: result = new SentinelSig(); break;
|
||
|
case ElementType.Pinned: result = new PinnedSig(ReadType()); break;
|
||
|
|
||
|
case ElementType.Var:
|
||
|
if (!reader.TryReadCompressedUInt32(out num))
|
||
|
break;
|
||
|
result = new GenericVar(num, gpContext.Type);
|
||
|
break;
|
||
|
|
||
|
case ElementType.MVar:
|
||
|
if (!reader.TryReadCompressedUInt32(out num))
|
||
|
break;
|
||
|
result = new GenericMVar(num, gpContext.Method);
|
||
|
break;
|
||
|
|
||
|
case ElementType.ValueArray:
|
||
|
nextType = ReadType();
|
||
|
if (!reader.TryReadCompressedUInt32(out num))
|
||
|
break;
|
||
|
result = new ValueArraySig(nextType, num);
|
||
|
break;
|
||
|
|
||
|
case ElementType.Module:
|
||
|
if (!reader.TryReadCompressedUInt32(out num))
|
||
|
break;
|
||
|
result = new ModuleSig(num, ReadType());
|
||
|
break;
|
||
|
|
||
|
case ElementType.GenericInst:
|
||
|
nextType = ReadType();
|
||
|
if (!reader.TryReadCompressedUInt32(out num) || num > 0x10000 || num > reader.BytesLeft)
|
||
|
break;
|
||
|
var genericInstSig = new GenericInstSig(nextType as ClassOrValueTypeSig, num);
|
||
|
var args = genericInstSig.GenericArguments;
|
||
|
for (i = 0; i < num; i++)
|
||
|
args.Add(ReadType());
|
||
|
result = genericInstSig;
|
||
|
break;
|
||
|
|
||
|
case ElementType.Array:
|
||
|
nextType = ReadType();
|
||
|
uint rank;
|
||
|
if (!reader.TryReadCompressedUInt32(out rank))
|
||
|
break;
|
||
|
if (rank > MaxArrayRank)
|
||
|
break;
|
||
|
if (rank == 0) {
|
||
|
result = new ArraySig(nextType, rank);
|
||
|
break;
|
||
|
}
|
||
|
if (!reader.TryReadCompressedUInt32(out num))
|
||
|
break;
|
||
|
if (num > rank)
|
||
|
break;
|
||
|
var sizes = new List<uint>((int)num);
|
||
|
for (i = 0; i < num; i++) {
|
||
|
if (!reader.TryReadCompressedUInt32(out uint size))
|
||
|
goto exit;
|
||
|
sizes.Add(size);
|
||
|
}
|
||
|
if (!reader.TryReadCompressedUInt32(out num))
|
||
|
break;
|
||
|
if (num > rank)
|
||
|
break;
|
||
|
var lowerBounds = new List<int>((int)num);
|
||
|
for (i = 0; i < num; i++) {
|
||
|
if (!reader.TryReadCompressedInt32(out int size))
|
||
|
goto exit;
|
||
|
lowerBounds.Add(size);
|
||
|
}
|
||
|
result = new ArraySig(nextType, rank, sizes, lowerBounds);
|
||
|
break;
|
||
|
|
||
|
case ElementType.Internal:
|
||
|
IntPtr address;
|
||
|
if (IntPtr.Size == 4)
|
||
|
address = new IntPtr(reader.ReadInt32());
|
||
|
else
|
||
|
address = new IntPtr(reader.ReadInt64());
|
||
|
result = helper.ConvertRTInternalAddress(address);
|
||
|
break;
|
||
|
|
||
|
case ElementType.End:
|
||
|
case ElementType.R:
|
||
|
default:
|
||
|
result = null;
|
||
|
break;
|
||
|
}
|
||
|
exit:
|
||
|
recursionCounter.Decrement();
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
ITypeDefOrRef ReadTypeDefOrRef(bool allowTypeSpec) {
|
||
|
if (!reader.TryReadCompressedUInt32(out uint codedToken))
|
||
|
return null;
|
||
|
if (!allowTypeSpec && CodedToken.TypeDefOrRef.Decode2(codedToken).Table == Table.TypeSpec)
|
||
|
return null;
|
||
|
return helper.ResolveTypeDefOrRef(codedToken, default);
|
||
|
}
|
||
|
}
|
||
|
}
|