dnlib回滚使用预编译好的dll文件

backup
walon 2025-05-16 17:44:07 +08:00
parent 6d7c86da32
commit 2921f83fb8
421 changed files with 0 additions and 96093 deletions

BIN
Plugins/dnlib.dll Normal file

Binary file not shown.

View File

@ -1,23 +0,0 @@
// dnlib: See LICENSE.txt for more info
#if NET35
namespace System.Runtime.InteropServices {
[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Method, AllowMultiple = false)]
sealed class DefaultDllImportSearchPathsAttribute : Attribute {
public DefaultDllImportSearchPathsAttribute(DllImportSearchPath paths) => _paths = paths;
public DllImportSearchPath Paths => _paths;
internal DllImportSearchPath _paths;
}
[Flags]
enum DllImportSearchPath {
LegacyBehavior = 0,
AssemblyDirectory = 2,
UseDllDirectoryForDependencies = 0x100,
ApplicationDirectory = 0x200,
UserDirectories = 0x400,
System32 = 0x800,
SafeDirectories = 0x1000,
}
}
#endif

View File

@ -1,35 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System.Collections.Generic;
namespace dnlib.DotNet {
/// <summary>
/// Returns types without getting stuck in an infinite loop
/// </summary>
readonly struct AllTypesHelper {
/// <summary>
/// Gets a list of all types and nested types
/// </summary>
/// <param name="types">A list of types</param>
public static IEnumerable<TypeDef> Types(IEnumerable<TypeDef> types) {
var visited = new Dictionary<TypeDef, bool>();
var stack = new Stack<IEnumerator<TypeDef>>();
if (types is not null)
stack.Push(types.GetEnumerator());
while (stack.Count > 0) {
var enumerator = stack.Pop();
while (enumerator.MoveNext()) {
var type = enumerator.Current;
if (visited.ContainsKey(type))
continue;
visited[type] = true;
yield return type;
if (type.NestedTypes.Count > 0) {
stack.Push(enumerator);
enumerator = type.NestedTypes.GetEnumerator();
}
}
}
}
}
}

View File

@ -1,58 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System;
namespace dnlib.DotNet {
/// <summary>
/// Assembly flags from Assembly.Flags column.
/// </summary>
/// <remarks>See CorHdr.h/CorAssemblyFlags</remarks>
[Flags]
public enum AssemblyAttributes : uint {
/// <summary>No flags set</summary>
None = 0,
/// <summary>The assembly ref holds the full (unhashed) public key.</summary>
PublicKey = 1,
/// <summary>Processor Architecture unspecified</summary>
PA_None = 0x0000,
/// <summary>Processor Architecture: neutral (PE32)</summary>
PA_MSIL = 0x0010,
/// <summary>Processor Architecture: x86 (PE32)</summary>
PA_x86 = 0x0020,
/// <summary>Processor Architecture: Itanium (PE32+)</summary>
PA_IA64 = 0x0030,
/// <summary>Processor Architecture: AMD X64 (PE32+)</summary>
PA_AMD64 = 0x0040,
/// <summary>Processor Architecture: ARM (PE32)</summary>
PA_ARM = 0x0050,
/// <summary>Processor Architecture: ARM64 (PE32+)</summary>
PA_ARM64 = 0x0060,
/// <summary>applies to any platform but cannot run on any (e.g. reference assembly), should not have "specified" set</summary>
PA_NoPlatform = 0x0070,
/// <summary>Propagate PA flags to AssemblyRef record</summary>
PA_Specified = 0x0080,
/// <summary>Bits describing the processor architecture</summary>
PA_Mask = 0x0070,
/// <summary>Bits describing the PA incl. Specified</summary>
PA_FullMask = 0x00F0,
/// <summary>NOT A FLAG, shift count in PA flags &lt;--&gt; index conversion</summary>
PA_Shift = 0x0004,
/// <summary>From "DebuggableAttribute".</summary>
EnableJITcompileTracking = 0x8000,
/// <summary>From "DebuggableAttribute".</summary>
DisableJITcompileOptimizer = 0x4000,
/// <summary>The assembly can be retargeted (at runtime) to an assembly from a different publisher.</summary>
Retargetable = 0x0100,
/// <summary/>
ContentType_Default = 0x0000,
/// <summary/>
ContentType_WindowsRuntime = 0x0200,
/// <summary>Bits describing ContentType</summary>
ContentType_Mask = 0x0E00,
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,111 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System;
using System.IO;
using System.Security.Cryptography;
namespace dnlib.DotNet {
/// <summary>
/// Hashes some data according to a <see cref="AssemblyHashAlgorithm"/>
/// </summary>
readonly struct AssemblyHash : IDisposable {
readonly HashAlgorithm hasher;
/// <summary>
/// Constructor
/// </summary>
/// <remarks>If <paramref name="hashAlgo"/> is an unsupported hash algorithm, then
/// <see cref="AssemblyHashAlgorithm.SHA1"/> will be used as the hash algorithm.</remarks>
/// <param name="hashAlgo">The algorithm to use</param>
public AssemblyHash(AssemblyHashAlgorithm hashAlgo) =>
hasher = hashAlgo switch {
AssemblyHashAlgorithm.MD5 => MD5.Create(),
AssemblyHashAlgorithm.SHA_256 => SHA256.Create(),
AssemblyHashAlgorithm.SHA_384 => SHA384.Create(),
AssemblyHashAlgorithm.SHA_512 => SHA512.Create(),
_ => SHA1.Create(),
};
/// <inheritdoc/>
public void Dispose() {
if (hasher is not null)
((IDisposable)hasher).Dispose();
}
/// <summary>
/// Hash data
/// </summary>
/// <remarks>If <paramref name="hashAlgo"/> is an unsupported hash algorithm, then
/// <see cref="AssemblyHashAlgorithm.SHA1"/> will be used as the hash algorithm.</remarks>
/// <param name="data">The data</param>
/// <param name="hashAlgo">The algorithm to use</param>
/// <returns>Hashed data or null if <paramref name="data"/> was <c>null</c></returns>
public static byte[] Hash(byte[] data, AssemblyHashAlgorithm hashAlgo) {
if (data is null)
return null;
using (var asmHash = new AssemblyHash(hashAlgo)) {
asmHash.Hash(data);
return asmHash.ComputeHash();
}
}
/// <summary>
/// Hash data
/// </summary>
/// <param name="data">Data</param>
public void Hash(byte[] data) => Hash(data, 0, data.Length);
/// <summary>
/// Hash data
/// </summary>
/// <param name="data">Data</param>
/// <param name="offset">Offset</param>
/// <param name="length">Length</param>
public void Hash(byte[] data, int offset, int length) {
if (hasher.TransformBlock(data, offset, length, data, offset) != length)
throw new IOException("Could not calculate hash");
}
/// <summary>
/// Hash stream data
/// </summary>
/// <param name="stream">Stream</param>
/// <param name="length">Number of bytes to hash</param>
/// <param name="buffer">Temp buffer</param>
public void Hash(Stream stream, uint length, byte[] buffer) {
while (length > 0) {
int len = length > (uint)buffer.Length ? buffer.Length : (int)length;
if (stream.Read(buffer, 0, len) != len)
throw new IOException("Could not read data");
Hash(buffer, 0, len);
length -= (uint)len;
}
}
/// <summary>
/// Computes the hash
/// </summary>
public byte[] ComputeHash() {
hasher.TransformFinalBlock(Array2.Empty<byte>(), 0, 0);
return hasher.Hash;
}
/// <summary>
/// Creates a public key token from the hash of some <paramref name="publicKeyData"/>
/// </summary>
/// <remarks>A public key is hashed, and the last 8 bytes of the hash, in reverse
/// order, is used as the public key token</remarks>
/// <param name="publicKeyData">The data</param>
/// <returns>A new <see cref="PublicKeyToken"/> instance</returns>
public static PublicKeyToken CreatePublicKeyToken(byte[] publicKeyData) {
if (publicKeyData is null)
return new PublicKeyToken();
var hash = Hash(publicKeyData, AssemblyHashAlgorithm.SHA1);
var pkt = new byte[8];
for (int i = 0; i < pkt.Length && i < hash.Length; i++)
pkt[i] = hash[hash.Length - i - 1];
return new PublicKeyToken(pkt);
}
}
}

View File

@ -1,54 +0,0 @@
// dnlib: See LICENSE.txt for more info
namespace dnlib.DotNet {
/// <summary>
/// Any ALG_CLASS_HASH type in WinCrypt.h can be used by Microsoft's CLI implementation
/// </summary>
public enum AssemblyHashAlgorithm : uint {
/// <summary/>
None = 0,
/// <summary/>
MD2 = 0x8001,
/// <summary/>
MD4 = 0x8002,
/// <summary>This is a reserved value in the CLI</summary>
MD5 = 0x8003,
/// <summary>The only algorithm supported by the CLI</summary>
SHA1 = 0x8004,
/// <summary/>
MAC = 0x8005,
/// <summary/>
SSL3_SHAMD5 = 0x8008,
/// <summary/>
HMAC = 0x8009,
/// <summary/>
TLS1PRF = 0x800A,
/// <summary/>
HASH_REPLACE_OWF = 0x800B,
/// <summary/>
SHA_256 = 0x800C,
/// <summary/>
SHA_384 = 0x800D,
/// <summary/>
SHA_512 = 0x800E,
}
public static partial class Extensions {
internal static string GetName(this AssemblyHashAlgorithm hashAlg) =>
hashAlg switch {
AssemblyHashAlgorithm.MD2 => null,
AssemblyHashAlgorithm.MD4 => null,
AssemblyHashAlgorithm.MD5 => "MD5",
AssemblyHashAlgorithm.SHA1 => "SHA1",
AssemblyHashAlgorithm.MAC => null,
AssemblyHashAlgorithm.SSL3_SHAMD5 => null,
AssemblyHashAlgorithm.HMAC => null,
AssemblyHashAlgorithm.TLS1PRF => null,
AssemblyHashAlgorithm.HASH_REPLACE_OWF => null,
AssemblyHashAlgorithm.SHA_256 => "SHA256",
AssemblyHashAlgorithm.SHA_384 => "SHA384",
AssemblyHashAlgorithm.SHA_512 => "SHA512",
_ => null,
};
}
}

View File

@ -1,259 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System;
using System.Collections.Generic;
namespace dnlib.DotNet {
/// <summary>
/// Flags used by <see cref="AssemblyNameComparer"/>
/// </summary>
[Flags]
public enum AssemblyNameComparerFlags {
/// <summary>
/// Compare assembly simple name
/// </summary>
Name = 1,
/// <summary>
/// Compare assembly version
/// </summary>
Version = 2,
/// <summary>
/// Compare assembly public key token
/// </summary>
PublicKeyToken = 4,
/// <summary>
/// Compare assembly culture
/// </summary>
Culture = 8,
/// <summary>
/// Compare content type
/// </summary>
ContentType = 0x10,
/// <summary>
/// Compare assembly simple name, version, public key token, locale and content type
/// </summary>
All = Name | Version | PublicKeyToken | Culture | ContentType,
}
/// <summary>
/// Compares two assembly names
/// </summary>
public readonly struct AssemblyNameComparer : IEqualityComparer<IAssembly> {
/// <summary>
/// Compares the name, version, public key token, culture and content type
/// </summary>
public static readonly AssemblyNameComparer CompareAll = new AssemblyNameComparer(AssemblyNameComparerFlags.All);
/// <summary>
/// Compares only the name and the public key token
/// </summary>
public static readonly AssemblyNameComparer NameAndPublicKeyTokenOnly = new AssemblyNameComparer(AssemblyNameComparerFlags.Name | AssemblyNameComparerFlags.PublicKeyToken);
/// <summary>
/// Compares only the name
/// </summary>
public static readonly AssemblyNameComparer NameOnly = new AssemblyNameComparer(AssemblyNameComparerFlags.Name);
readonly AssemblyNameComparerFlags flags;
/// <summary>
/// Gets the <see cref="AssemblyNameComparerFlags.Name"/> bit
/// </summary>
public bool CompareName => (flags & AssemblyNameComparerFlags.Name) != 0;
/// <summary>
/// Gets the <see cref="AssemblyNameComparerFlags.Version"/> bit
/// </summary>
public bool CompareVersion => (flags & AssemblyNameComparerFlags.Version) != 0;
/// <summary>
/// Gets the <see cref="AssemblyNameComparerFlags.PublicKeyToken"/> bit
/// </summary>
public bool ComparePublicKeyToken => (flags & AssemblyNameComparerFlags.PublicKeyToken) != 0;
/// <summary>
/// Gets the <see cref="AssemblyNameComparerFlags.Culture"/> bit
/// </summary>
public bool CompareCulture => (flags & AssemblyNameComparerFlags.Culture) != 0;
/// <summary>
/// Gets the <see cref="AssemblyNameComparerFlags.ContentType"/> bit
/// </summary>
public bool CompareContentType => (flags & AssemblyNameComparerFlags.ContentType) != 0;
/// <summary>
/// Constructor
/// </summary>
/// <param name="flags">Comparison flags</param>
public AssemblyNameComparer(AssemblyNameComparerFlags flags) => this.flags = flags;
/// <summary>
/// Compares two assembly names
/// </summary>
/// <param name="a">First</param>
/// <param name="b">Second</param>
/// <returns>&lt; 0 if a &lt; b, 0 if a == b, &gt; 0 if a &gt; b</returns>
public int CompareTo(IAssembly a, IAssembly b) {
if (a == b)
return 0;
if (a is null)
return -1;
if (b is null)
return 1;
int v;
if (CompareName && (v = UTF8String.CaseInsensitiveCompareTo(a.Name, b.Name)) != 0)
return v;
if (CompareVersion && (v = Utils.CompareTo(a.Version, b.Version)) != 0)
return v;
if (ComparePublicKeyToken && (v = PublicKeyBase.TokenCompareTo(a.PublicKeyOrToken, b.PublicKeyOrToken)) != 0)
return v;
if (CompareCulture && (v = Utils.LocaleCompareTo(a.Culture, b.Culture)) != 0)
return v;
if (CompareContentType && (v = a.ContentType.CompareTo(b.ContentType)) != 0)
return v;
return 0;
}
/// <summary>
/// Compares two assembly names
/// </summary>
/// <param name="a">First</param>
/// <param name="b">Second</param>
/// <returns><c>true</c> if equal, <c>false</c> otherwise</returns>
public bool Equals(IAssembly a, IAssembly b) => CompareTo(a, b) == 0;
/// <summary>
/// Figures out which of two assembly names is closer to another assembly name
/// </summary>
/// <param name="requested">Requested assembly name</param>
/// <param name="a">First</param>
/// <param name="b">Second</param>
/// <returns>-1 if both are equally close, 0 if <paramref name="a"/> is closest, 1 if
/// <paramref name="b"/> is closest</returns>
public int CompareClosest(IAssembly requested, IAssembly a, IAssembly b) {
if (a == b)
return 0;
if (a is null)
return !CompareName ? 1 : UTF8String.CaseInsensitiveEquals(requested.Name, b.Name) ? 1 : 0;
if (b is null)
return !CompareName ? 0 : UTF8String.CaseInsensitiveEquals(requested.Name, a.Name) ? 0 : 1;
// Compare the most important parts first:
// 1. Assembly simple name
// 2. Public key token
// 3. Version
// 4. Locale
// 5. Content type
if (CompareName) {
// If the name only matches one of a or b, return that one.
bool na = UTF8String.CaseInsensitiveEquals(requested.Name, a.Name);
bool nb = UTF8String.CaseInsensitiveEquals(requested.Name, b.Name);
if (na && !nb)
return 0;
if (!na && nb)
return 1;
if (!na && !nb)
return -1;
}
if (ComparePublicKeyToken) {
bool pa, pb;
if (PublicKeyBase.IsNullOrEmpty2(requested.PublicKeyOrToken)) {
// If one of them has a pkt but the other one hasn't, return the one with
// no pkt.
pa = PublicKeyBase.IsNullOrEmpty2(a.PublicKeyOrToken);
pb = PublicKeyBase.IsNullOrEmpty2(b.PublicKeyOrToken);
}
else {
// If one of them has the correct pkt, but the other one has an incorrect
// pkt, return the one with the correct pkt.
pa = PublicKeyBase.TokenEquals(requested.PublicKeyOrToken, a.PublicKeyOrToken);
pb = PublicKeyBase.TokenEquals(requested.PublicKeyOrToken, b.PublicKeyOrToken);
}
if (pa && !pb)
return 0;
if (!pa && pb)
return 1;
}
if (CompareVersion && !Utils.Equals(a.Version, b.Version)) {
var rv = Utils.CreateVersionWithNoUndefinedValues(requested.Version);
if (rv == new Version(0, 0, 0, 0))
rv = new Version(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue);
int va = Utils.CompareTo(a.Version, rv);
int vb = Utils.CompareTo(b.Version, rv);
if (va == 0)
return 0; // vb != 0 so return 0
if (vb == 0)
return 1; // va != 0 so return 1
if (va > 0 && vb < 0)
return 0;
if (va < 0 && vb > 0)
return 1;
// Now either both a and b's version > req version or both are < req version
if (va > 0) {
// a.Version and b.Version > req.Version. Pick the one that is closest.
return Utils.CompareTo(a.Version, b.Version) < 0 ? 0 : 1;
}
else {
// a.Version and b.Version < req.Version. Pick the one that is closest.
return Utils.CompareTo(a.Version, b.Version) > 0 ? 0 : 1;
}
}
if (CompareCulture) {
bool la = Utils.LocaleEquals(requested.Culture, a.Culture);
bool lb = Utils.LocaleEquals(requested.Culture, b.Culture);
if (la && !lb)
return 0;
if (!la && lb)
return 1;
}
if (CompareContentType) {
bool ca = requested.ContentType == a.ContentType;
bool cb = requested.ContentType == b.ContentType;
if (ca && !cb)
return 0;
if (!ca && cb)
return 1;
}
return -1;
}
/// <summary>
/// Gets the hash code of an assembly name
/// </summary>
/// <param name="a">Assembly name</param>
/// <returns>The hash code</returns>
public int GetHashCode(IAssembly a) {
if (a is null)
return 0;
int hash = 0;
if (CompareName)
hash += UTF8String.GetHashCode(a.Name);
if (CompareVersion)
hash += Utils.CreateVersionWithNoUndefinedValues(a.Version).GetHashCode();
if (ComparePublicKeyToken)
hash += PublicKeyBase.GetHashCodeToken(a.PublicKeyOrToken);
if (CompareCulture)
hash += Utils.GetHashCodeLocale(a.Culture);
if (CompareContentType)
hash += (int)a.ContentType;
return hash;
}
}
}

View File

@ -1,255 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System;
using System.Reflection;
namespace dnlib.DotNet {
/// <summary>
/// Stores assembly name information
/// </summary>
public sealed class AssemblyNameInfo : IAssembly {
AssemblyHashAlgorithm hashAlgId;
Version version;
AssemblyAttributes flags;
PublicKeyBase publicKeyOrToken;
UTF8String name;
UTF8String culture;
/// <summary>
/// Gets/sets the <see cref="AssemblyHashAlgorithm"/>
/// </summary>
public AssemblyHashAlgorithm HashAlgId {
get => hashAlgId;
set => hashAlgId = value;
}
/// <summary>
/// Gets/sets the <see cref="Version"/> or <c>null</c> if none specified
/// </summary>
public Version Version {
get => version;
set => version = value;
}
/// <summary>
/// Gets/sets the <see cref="AssemblyAttributes"/>
/// </summary>
public AssemblyAttributes Attributes {
get => flags;
set => flags = value;
}
/// <summary>
/// Gets/sets the public key or token
/// </summary>
public PublicKeyBase PublicKeyOrToken {
get => publicKeyOrToken;
set => publicKeyOrToken = value;
}
/// <summary>
/// Gets/sets the name
/// </summary>
public UTF8String Name {
get => name;
set => name = value;
}
/// <summary>
/// Gets/sets the culture or <c>null</c> if none specified
/// </summary>
public UTF8String Culture {
get => culture;
set => culture = value;
}
/// <summary>
/// Gets the full name of the assembly
/// </summary>
public string FullName => FullNameToken;
/// <summary>
/// Gets the full name of the assembly but use a public key token
/// </summary>
public string FullNameToken => FullNameFactory.AssemblyFullName(this, true);
/// <summary>
/// Modify <see cref="Attributes"/> property: <see cref="Attributes"/> =
/// (<see cref="Attributes"/> &amp; <paramref name="andMask"/>) | <paramref name="orMask"/>.
/// </summary>
/// <param name="andMask">Value to <c>AND</c></param>
/// <param name="orMask">Value to OR</param>
void ModifyAttributes(AssemblyAttributes andMask, AssemblyAttributes orMask) => Attributes = (Attributes & andMask) | orMask;
/// <summary>
/// Set or clear flags in <see cref="Attributes"/>
/// </summary>
/// <param name="set"><c>true</c> if flags should be set, <c>false</c> if flags should
/// be cleared</param>
/// <param name="flags">Flags to set or clear</param>
void ModifyAttributes(bool set, AssemblyAttributes flags) {
if (set)
Attributes |= flags;
else
Attributes &= ~flags;
}
/// <summary>
/// Gets/sets the <see cref="AssemblyAttributes.PublicKey"/> bit
/// </summary>
public bool HasPublicKey {
get => (Attributes & AssemblyAttributes.PublicKey) != 0;
set => ModifyAttributes(value, AssemblyAttributes.PublicKey);
}
/// <summary>
/// Gets/sets the processor architecture
/// </summary>
public AssemblyAttributes ProcessorArchitecture {
get => Attributes & AssemblyAttributes.PA_Mask;
set => ModifyAttributes(~AssemblyAttributes.PA_Mask, value & AssemblyAttributes.PA_Mask);
}
/// <summary>
/// Gets/sets the processor architecture
/// </summary>
public AssemblyAttributes ProcessorArchitectureFull {
get => Attributes & AssemblyAttributes.PA_FullMask;
set => ModifyAttributes(~AssemblyAttributes.PA_FullMask, value & AssemblyAttributes.PA_FullMask);
}
/// <summary>
/// <c>true</c> if unspecified processor architecture
/// </summary>
public bool IsProcessorArchitectureNone => (Attributes & AssemblyAttributes.PA_Mask) == AssemblyAttributes.PA_None;
/// <summary>
/// <c>true</c> if neutral (PE32) architecture
/// </summary>
public bool IsProcessorArchitectureMSIL => (Attributes & AssemblyAttributes.PA_Mask) == AssemblyAttributes.PA_MSIL;
/// <summary>
/// <c>true</c> if x86 (PE32) architecture
/// </summary>
public bool IsProcessorArchitectureX86 => (Attributes & AssemblyAttributes.PA_Mask) == AssemblyAttributes.PA_x86;
/// <summary>
/// <c>true</c> if IA-64 (PE32+) architecture
/// </summary>
public bool IsProcessorArchitectureIA64 => (Attributes & AssemblyAttributes.PA_Mask) == AssemblyAttributes.PA_IA64;
/// <summary>
/// <c>true</c> if x64 (PE32+) architecture
/// </summary>
public bool IsProcessorArchitectureX64 => (Attributes & AssemblyAttributes.PA_Mask) == AssemblyAttributes.PA_AMD64;
/// <summary>
/// <c>true</c> if ARM (PE32) architecture
/// </summary>
public bool IsProcessorArchitectureARM => (Attributes & AssemblyAttributes.PA_Mask) == AssemblyAttributes.PA_ARM;
/// <summary>
/// <c>true</c> if eg. reference assembly (not runnable)
/// </summary>
public bool IsProcessorArchitectureNoPlatform => (Attributes & AssemblyAttributes.PA_Mask) == AssemblyAttributes.PA_NoPlatform;
/// <summary>
/// Gets/sets the <see cref="AssemblyAttributes.PA_Specified"/> bit
/// </summary>
public bool IsProcessorArchitectureSpecified {
get => (Attributes & AssemblyAttributes.PA_Specified) != 0;
set => ModifyAttributes(value, AssemblyAttributes.PA_Specified);
}
/// <summary>
/// Gets/sets the <see cref="AssemblyAttributes.EnableJITcompileTracking"/> bit
/// </summary>
public bool EnableJITcompileTracking {
get => (Attributes & AssemblyAttributes.EnableJITcompileTracking) != 0;
set => ModifyAttributes(value, AssemblyAttributes.EnableJITcompileTracking);
}
/// <summary>
/// Gets/sets the <see cref="AssemblyAttributes.DisableJITcompileOptimizer"/> bit
/// </summary>
public bool DisableJITcompileOptimizer {
get => (Attributes & AssemblyAttributes.DisableJITcompileOptimizer) != 0;
set => ModifyAttributes(value, AssemblyAttributes.DisableJITcompileOptimizer);
}
/// <summary>
/// Gets/sets the <see cref="AssemblyAttributes.Retargetable"/> bit
/// </summary>
public bool IsRetargetable {
get => (Attributes & AssemblyAttributes.Retargetable) != 0;
set => ModifyAttributes(value, AssemblyAttributes.Retargetable);
}
/// <summary>
/// Gets/sets the content type
/// </summary>
public AssemblyAttributes ContentType {
get => Attributes & AssemblyAttributes.ContentType_Mask;
set => ModifyAttributes(~AssemblyAttributes.ContentType_Mask, value & AssemblyAttributes.ContentType_Mask);
}
/// <summary>
/// <c>true</c> if content type is <c>Default</c>
/// </summary>
public bool IsContentTypeDefault => (Attributes & AssemblyAttributes.ContentType_Mask) == AssemblyAttributes.ContentType_Default;
/// <summary>
/// <c>true</c> if content type is <c>WindowsRuntime</c>
/// </summary>
public bool IsContentTypeWindowsRuntime => (Attributes & AssemblyAttributes.ContentType_Mask) == AssemblyAttributes.ContentType_WindowsRuntime;
/// <summary>
/// Default constructor
/// </summary>
public AssemblyNameInfo() {
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="asmFullName">An assembly name</param>
public AssemblyNameInfo(string asmFullName)
: this(ReflectionTypeNameParser.ParseAssemblyRef(asmFullName)) {
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="asm">The assembly</param>
public AssemblyNameInfo(IAssembly asm) {
if (asm is null)
return;
var asmDef = asm as AssemblyDef;
hashAlgId = asmDef is null ? 0 : asmDef.HashAlgorithm;
version = asm.Version ?? new Version(0, 0, 0, 0);
flags = asm.Attributes;
publicKeyOrToken = asm.PublicKeyOrToken;
name = UTF8String.IsNullOrEmpty(asm.Name) ? UTF8String.Empty : asm.Name;
culture = UTF8String.IsNullOrEmpty(asm.Culture) ? UTF8String.Empty : asm.Culture;
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="asmName">Assembly name info</param>
public AssemblyNameInfo(AssemblyName asmName) {
if (asmName is null)
return;
hashAlgId = (AssemblyHashAlgorithm)asmName.HashAlgorithm;
version = asmName.Version ?? new Version(0, 0, 0, 0);
flags = (AssemblyAttributes)asmName.Flags;
publicKeyOrToken = (PublicKeyBase)PublicKeyBase.CreatePublicKey(asmName.GetPublicKey()) ??
PublicKeyBase.CreatePublicKeyToken(asmName.GetPublicKeyToken());
name = asmName.Name ?? string.Empty;
culture = asmName.CultureInfo is not null && asmName.CultureInfo.Name is not null ? asmName.CultureInfo.Name : string.Empty;
}
/// <inhertidoc/>
public override string ToString() => FullName;
}
}

View File

@ -1,466 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Threading;
using dnlib.DotNet.MD;
using dnlib.DotNet.Pdb;
namespace dnlib.DotNet {
/// <summary>
/// A high-level representation of a row in the AssemblyRef table
/// </summary>
public abstract class AssemblyRef : IHasCustomAttribute, IImplementation, IResolutionScope, IHasCustomDebugInformation, IAssembly, IScope {
/// <summary>
/// An assembly ref that can be used to indicate that it references the current assembly
/// when the current assembly is not known (eg. a type string without any assembly info
/// when it references a type in the current assembly).
/// </summary>
public static readonly AssemblyRef CurrentAssembly = new AssemblyRefUser("<<<CURRENT_ASSEMBLY>>>");
/// <summary>
/// The row id in its table
/// </summary>
protected uint rid;
/// <inheritdoc/>
public MDToken MDToken => new MDToken(Table.AssemblyRef, rid);
/// <inheritdoc/>
public uint Rid {
get => rid;
set => rid = value;
}
/// <inheritdoc/>
public int HasCustomAttributeTag => 15;
/// <inheritdoc/>
public int ImplementationTag => 1;
/// <inheritdoc/>
public int ResolutionScopeTag => 2;
/// <inheritdoc/>
public ScopeType ScopeType => ScopeType.AssemblyRef;
/// <inheritdoc/>
public string ScopeName => FullName;
/// <summary>
/// From columns AssemblyRef.MajorVersion, AssemblyRef.MinorVersion,
/// AssemblyRef.BuildNumber, AssemblyRef.RevisionNumber
/// </summary>
/// <exception cref="ArgumentNullException">If <paramref name="value"/> is <c>null</c></exception>
public Version Version {
get => version;
set => version = value ?? throw new ArgumentNullException(nameof(value));
}
/// <summary/>
protected Version version;
/// <summary>
/// From column AssemblyRef.Flags
/// </summary>
public AssemblyAttributes Attributes {
get => (AssemblyAttributes)attributes;
set => attributes = (int)value;
}
/// <summary>Attributes</summary>
protected int attributes;
/// <summary>
/// From column AssemblyRef.PublicKeyOrToken
/// </summary>
/// <exception cref="ArgumentNullException">If <paramref name="value"/> is <c>null</c></exception>
public PublicKeyBase PublicKeyOrToken {
get => publicKeyOrToken;
set => publicKeyOrToken = value ?? throw new ArgumentNullException(nameof(value));
}
/// <summary/>
protected PublicKeyBase publicKeyOrToken;
/// <summary>
/// From column AssemblyRef.Name
/// </summary>
public UTF8String Name {
get => name;
set => name = value;
}
/// <summary>Name</summary>
protected UTF8String name;
/// <summary>
/// From column AssemblyRef.Locale
/// </summary>
public UTF8String Culture {
get => culture;
set => culture = value;
}
/// <summary>Culture</summary>
protected UTF8String culture;
/// <summary>
/// From column AssemblyRef.HashValue
/// </summary>
public byte[] Hash {
get => hashValue;
set => hashValue = value;
}
/// <summary/>
protected byte[] hashValue;
/// <summary>
/// Gets all custom attributes
/// </summary>
public CustomAttributeCollection CustomAttributes {
get {
if (customAttributes is null)
InitializeCustomAttributes();
return customAttributes;
}
}
/// <summary/>
protected CustomAttributeCollection customAttributes;
/// <summary>Initializes <see cref="customAttributes"/></summary>
protected virtual void InitializeCustomAttributes() =>
Interlocked.CompareExchange(ref customAttributes, new CustomAttributeCollection(), null);
/// <inheritdoc/>
public bool HasCustomAttributes => CustomAttributes.Count > 0;
/// <inheritdoc/>
public int HasCustomDebugInformationTag => 15;
/// <inheritdoc/>
public bool HasCustomDebugInfos => CustomDebugInfos.Count > 0;
/// <summary>
/// Gets all custom debug infos
/// </summary>
public IList<PdbCustomDebugInfo> CustomDebugInfos {
get {
if (customDebugInfos is null)
InitializeCustomDebugInfos();
return customDebugInfos;
}
}
/// <summary/>
protected IList<PdbCustomDebugInfo> customDebugInfos;
/// <summary>Initializes <see cref="customDebugInfos"/></summary>
protected virtual void InitializeCustomDebugInfos() =>
Interlocked.CompareExchange(ref customDebugInfos, new List<PdbCustomDebugInfo>(), null);
/// <inheritdoc/>
public string FullName => FullNameToken;
/// <summary>
/// Same as <see cref="FullName"/>, except that it uses the <c>PublicKey</c> if available.
/// </summary>
public string RealFullName => FullNameFactory.AssemblyFullName(this, false);
/// <summary>
/// Gets the full name of the assembly but use a public key token
/// </summary>
public string FullNameToken => FullNameFactory.AssemblyFullName(this, true);
/// <summary>
/// Modify <see cref="attributes"/> property: <see cref="attributes"/> =
/// (<see cref="attributes"/> &amp; <paramref name="andMask"/>) | <paramref name="orMask"/>.
/// </summary>
/// <param name="andMask">Value to <c>AND</c></param>
/// <param name="orMask">Value to OR</param>
void ModifyAttributes(AssemblyAttributes andMask, AssemblyAttributes orMask) =>
attributes = (attributes & (int)andMask) | (int)orMask;
/// <summary>
/// Set or clear flags in <see cref="attributes"/>
/// </summary>
/// <param name="set"><c>true</c> if flags should be set, <c>false</c> if flags should
/// be cleared</param>
/// <param name="flags">Flags to set or clear</param>
void ModifyAttributes(bool set, AssemblyAttributes flags) {
if (set)
attributes |= (int)flags;
else
attributes &= ~(int)flags;
}
/// <summary>
/// Gets/sets the <see cref="AssemblyAttributes.PublicKey"/> bit
/// </summary>
public bool HasPublicKey {
get => ((AssemblyAttributes)attributes & AssemblyAttributes.PublicKey) != 0;
set => ModifyAttributes(value, AssemblyAttributes.PublicKey);
}
/// <summary>
/// Gets/sets the processor architecture
/// </summary>
public AssemblyAttributes ProcessorArchitecture {
get => (AssemblyAttributes)attributes & AssemblyAttributes.PA_Mask;
set => ModifyAttributes(~AssemblyAttributes.PA_Mask, value & AssemblyAttributes.PA_Mask);
}
/// <summary>
/// Gets/sets the processor architecture
/// </summary>
public AssemblyAttributes ProcessorArchitectureFull {
get => (AssemblyAttributes)attributes & AssemblyAttributes.PA_FullMask;
set => ModifyAttributes(~AssemblyAttributes.PA_FullMask, value & AssemblyAttributes.PA_FullMask);
}
/// <summary>
/// <c>true</c> if unspecified processor architecture
/// </summary>
public bool IsProcessorArchitectureNone => ((AssemblyAttributes)attributes & AssemblyAttributes.PA_Mask) == AssemblyAttributes.PA_None;
/// <summary>
/// <c>true</c> if neutral (PE32) architecture
/// </summary>
public bool IsProcessorArchitectureMSIL => ((AssemblyAttributes)attributes & AssemblyAttributes.PA_Mask) == AssemblyAttributes.PA_MSIL;
/// <summary>
/// <c>true</c> if x86 (PE32) architecture
/// </summary>
public bool IsProcessorArchitectureX86 => ((AssemblyAttributes)attributes & AssemblyAttributes.PA_Mask) == AssemblyAttributes.PA_x86;
/// <summary>
/// <c>true</c> if IA-64 (PE32+) architecture
/// </summary>
public bool IsProcessorArchitectureIA64 => ((AssemblyAttributes)attributes & AssemblyAttributes.PA_Mask) == AssemblyAttributes.PA_IA64;
/// <summary>
/// <c>true</c> if x64 (PE32+) architecture
/// </summary>
public bool IsProcessorArchitectureX64 => ((AssemblyAttributes)attributes & AssemblyAttributes.PA_Mask) == AssemblyAttributes.PA_AMD64;
/// <summary>
/// <c>true</c> if ARM (PE32) architecture
/// </summary>
public bool IsProcessorArchitectureARM => ((AssemblyAttributes)attributes & AssemblyAttributes.PA_Mask) == AssemblyAttributes.PA_ARM;
/// <summary>
/// <c>true</c> if eg. reference assembly (not runnable)
/// </summary>
public bool IsProcessorArchitectureNoPlatform => ((AssemblyAttributes)attributes & AssemblyAttributes.PA_Mask) == AssemblyAttributes.PA_NoPlatform;
/// <summary>
/// Gets/sets the <see cref="AssemblyAttributes.PA_Specified"/> bit
/// </summary>
public bool IsProcessorArchitectureSpecified {
get => ((AssemblyAttributes)attributes & AssemblyAttributes.PA_Specified) != 0;
set => ModifyAttributes(value, AssemblyAttributes.PA_Specified);
}
/// <summary>
/// Gets/sets the <see cref="AssemblyAttributes.EnableJITcompileTracking"/> bit
/// </summary>
public bool EnableJITcompileTracking {
get => ((AssemblyAttributes)attributes & AssemblyAttributes.EnableJITcompileTracking) != 0;
set => ModifyAttributes(value, AssemblyAttributes.EnableJITcompileTracking);
}
/// <summary>
/// Gets/sets the <see cref="AssemblyAttributes.DisableJITcompileOptimizer"/> bit
/// </summary>
public bool DisableJITcompileOptimizer {
get => ((AssemblyAttributes)attributes & AssemblyAttributes.DisableJITcompileOptimizer) != 0;
set => ModifyAttributes(value, AssemblyAttributes.DisableJITcompileOptimizer);
}
/// <summary>
/// Gets/sets the <see cref="AssemblyAttributes.Retargetable"/> bit
/// </summary>
public bool IsRetargetable {
get => ((AssemblyAttributes)attributes & AssemblyAttributes.Retargetable) != 0;
set => ModifyAttributes(value, AssemblyAttributes.Retargetable);
}
/// <summary>
/// Gets/sets the content type
/// </summary>
public AssemblyAttributes ContentType {
get => (AssemblyAttributes)attributes & AssemblyAttributes.ContentType_Mask;
set => ModifyAttributes(~AssemblyAttributes.ContentType_Mask, value & AssemblyAttributes.ContentType_Mask);
}
/// <summary>
/// <c>true</c> if content type is <c>Default</c>
/// </summary>
public bool IsContentTypeDefault => ((AssemblyAttributes)attributes & AssemblyAttributes.ContentType_Mask) == AssemblyAttributes.ContentType_Default;
/// <summary>
/// <c>true</c> if content type is <c>WindowsRuntime</c>
/// </summary>
public bool IsContentTypeWindowsRuntime => ((AssemblyAttributes)attributes & AssemblyAttributes.ContentType_Mask) == AssemblyAttributes.ContentType_WindowsRuntime;
/// <inheritdoc/>
public override string ToString() => FullName;
}
/// <summary>
/// An AssemblyRef row created by the user and not present in the original .NET file
/// </summary>
public class AssemblyRefUser : AssemblyRef {
/// <summary>
/// Creates a reference to CLR 1.0's mscorlib
/// </summary>
public static AssemblyRefUser CreateMscorlibReferenceCLR10() => new AssemblyRefUser("mscorlib", new Version(1, 0, 3300, 0), new PublicKeyToken("b77a5c561934e089"));
/// <summary>
/// Creates a reference to CLR 1.1's mscorlib
/// </summary>
public static AssemblyRefUser CreateMscorlibReferenceCLR11() => new AssemblyRefUser("mscorlib", new Version(1, 0, 5000, 0), new PublicKeyToken("b77a5c561934e089"));
/// <summary>
/// Creates a reference to CLR 2.0's mscorlib
/// </summary>
public static AssemblyRefUser CreateMscorlibReferenceCLR20() => new AssemblyRefUser("mscorlib", new Version(2, 0, 0, 0), new PublicKeyToken("b77a5c561934e089"));
/// <summary>
/// Creates a reference to CLR 4.0's mscorlib
/// </summary>
public static AssemblyRefUser CreateMscorlibReferenceCLR40() => new AssemblyRefUser("mscorlib", new Version(4, 0, 0, 0), new PublicKeyToken("b77a5c561934e089"));
/// <summary>
/// Default constructor
/// </summary>
public AssemblyRefUser()
: this(UTF8String.Empty) {
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="name">Simple name</param>
/// <exception cref="ArgumentNullException">If any of the args is invalid</exception>
public AssemblyRefUser(UTF8String name)
: this(name, new Version(0, 0, 0, 0)) {
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="name">Simple name</param>
/// <param name="version">Version</param>
/// <exception cref="ArgumentNullException">If any of the args is invalid</exception>
public AssemblyRefUser(UTF8String name, Version version)
: this(name, version, new PublicKey()) {
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="name">Simple name</param>
/// <param name="version">Version</param>
/// <param name="publicKey">Public key or public key token</param>
/// <exception cref="ArgumentNullException">If any of the args is invalid</exception>
public AssemblyRefUser(UTF8String name, Version version, PublicKeyBase publicKey)
: this(name, version, publicKey, UTF8String.Empty) {
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="name">Simple name</param>
/// <param name="version">Version</param>
/// <param name="publicKey">Public key or public key token</param>
/// <param name="locale">Locale</param>
/// <exception cref="ArgumentNullException">If any of the args is invalid</exception>
public AssemblyRefUser(UTF8String name, Version version, PublicKeyBase publicKey, UTF8String locale) {
if (name is null)
throw new ArgumentNullException(nameof(name));
if (locale is null)
throw new ArgumentNullException(nameof(locale));
this.name = name;
this.version = version ?? throw new ArgumentNullException(nameof(version));
publicKeyOrToken = publicKey;
culture = locale;
attributes = (int)(publicKey is PublicKey ? AssemblyAttributes.PublicKey : AssemblyAttributes.None);
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="asmName">Assembly name info</param>
/// <exception cref="ArgumentNullException">If <paramref name="asmName"/> is <c>null</c></exception>
public AssemblyRefUser(AssemblyName asmName)
: this(new AssemblyNameInfo(asmName)) => attributes = (int)asmName.Flags;
/// <summary>
/// Constructor
/// </summary>
/// <param name="assembly">Assembly</param>
public AssemblyRefUser(IAssembly assembly) {
if (assembly is null)
throw new ArgumentNullException("asmName");
version = assembly.Version ?? new Version(0, 0, 0, 0);
publicKeyOrToken = assembly.PublicKeyOrToken;
name = UTF8String.IsNullOrEmpty(assembly.Name) ? UTF8String.Empty : assembly.Name;
culture = assembly.Culture;
attributes = (int)((publicKeyOrToken is PublicKey ? AssemblyAttributes.PublicKey : AssemblyAttributes.None) | assembly.ContentType);
}
}
/// <summary>
/// Created from a row in the AssemblyRef table
/// </summary>
sealed class AssemblyRefMD : AssemblyRef, IMDTokenProviderMD {
/// <summary>The module where this instance is located</summary>
readonly ModuleDefMD readerModule;
readonly uint origRid;
/// <inheritdoc/>
public uint OrigRid => origRid;
/// <inheritdoc/>
protected override void InitializeCustomAttributes() {
var list = readerModule.Metadata.GetCustomAttributeRidList(Table.AssemblyRef, origRid);
var tmp = new CustomAttributeCollection(list.Count, list, (list2, index) => readerModule.ReadCustomAttribute(list[index]));
Interlocked.CompareExchange(ref customAttributes, tmp, null);
}
/// <inheritdoc/>
protected override void InitializeCustomDebugInfos() {
var list = new List<PdbCustomDebugInfo>();
readerModule.InitializeCustomDebugInfos(new MDToken(MDToken.Table, origRid), new GenericParamContext(), list);
Interlocked.CompareExchange(ref customDebugInfos, list, null);
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="readerModule">The module which contains this <c>AssemblyRef</c> row</param>
/// <param name="rid">Row ID</param>
/// <exception cref="ArgumentNullException">If <paramref name="readerModule"/> is <c>null</c></exception>
/// <exception cref="ArgumentException">If <paramref name="rid"/> is invalid</exception>
public AssemblyRefMD(ModuleDefMD readerModule, uint rid) {
#if DEBUG
if (readerModule is null)
throw new ArgumentNullException("readerModule");
if (readerModule.TablesStream.AssemblyRefTable.IsInvalidRID(rid))
throw new BadImageFormatException($"AssemblyRef rid {rid} does not exist");
#endif
origRid = rid;
this.rid = rid;
this.readerModule = readerModule;
bool b = readerModule.TablesStream.TryReadAssemblyRefRow(origRid, out var row);
Debug.Assert(b);
version = new Version(row.MajorVersion, row.MinorVersion, row.BuildNumber, row.RevisionNumber);
attributes = (int)row.Flags;
var pkData = readerModule.BlobStream.Read(row.PublicKeyOrToken);
if ((attributes & (uint)AssemblyAttributes.PublicKey) != 0)
publicKeyOrToken = new PublicKey(pkData);
else
publicKeyOrToken = new PublicKeyToken(pkData);
name = readerModule.StringsStream.ReadNoNull(row.Name);
culture = readerModule.StringsStream.ReadNoNull(row.Locale);
hashValue = readerModule.BlobStream.Read(row.HashValue);
}
}
}

View File

@ -1,832 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml;
using dnlib.Threading;
namespace dnlib.DotNet {
/// <summary>
/// Resolves assemblies
/// </summary>
public class AssemblyResolver : IAssemblyResolver {
static readonly ModuleDef nullModule = new ModuleDefUser();
// DLL files are searched before EXE files
static readonly string[] assemblyExtensions = new string[] { ".dll", ".exe" };
static readonly string[] winMDAssemblyExtensions = new string[] { ".winmd" };
static readonly List<GacInfo> gacInfos;
static readonly string[] extraMonoPaths;
static readonly string[] monoVerDirs = new string[] {
// The "-api" dirs are reference assembly dirs.
"4.5", @"4.5\Facades", "4.5-api", @"4.5-api\Facades", "4.0", "4.0-api",
"3.5", "3.5-api", "3.0", "3.0-api", "2.0", "2.0-api",
"1.1", "1.0",
};
ModuleContext defaultModuleContext;
readonly Dictionary<ModuleDef, List<string>> moduleSearchPaths = new Dictionary<ModuleDef, List<string>>();
readonly Dictionary<string, AssemblyDef> cachedAssemblies = new Dictionary<string, AssemblyDef>(StringComparer.OrdinalIgnoreCase);
readonly List<string> preSearchPaths = new List<string>();
readonly List<string> postSearchPaths = new List<string>();
bool findExactMatch;
bool enableFrameworkRedirect;
bool enableTypeDefCache = true;
bool useGac = true;
#if THREAD_SAFE
readonly Lock theLock = Lock.Create();
#endif
sealed class GacInfo {
public readonly int Version;
public readonly string Path;
public readonly string Prefix;
public readonly string[] SubDirs;
public GacInfo(int version, string prefix, string path, string[] subDirs) {
Version = version;
Prefix = prefix;
Path = path;
SubDirs = subDirs;
}
}
static AssemblyResolver() {
gacInfos = new List<GacInfo>();
if (Type.GetType("Mono.Runtime") is not null) {
var dirs = new Dictionary<string, bool>(StringComparer.OrdinalIgnoreCase);
var extraMonoPathsList = new List<string>();
foreach (var prefix in FindMonoPrefixes()) {
var dir = Path.Combine(Path.Combine(Path.Combine(prefix, "lib"), "mono"), "gac");
if (dirs.ContainsKey(dir))
continue;
dirs[dir] = true;
if (Directory.Exists(dir)) {
gacInfos.Add(new GacInfo(-1, "", Path.GetDirectoryName(dir), new string[] {
Path.GetFileName(dir)
}));
}
dir = Path.GetDirectoryName(dir);
foreach (var verDir in monoVerDirs) {
var dir2 = dir;
foreach (var d in verDir.Split(new char[] { '\\' }))
dir2 = Path.Combine(dir2, d);
if (Directory.Exists(dir2))
extraMonoPathsList.Add(dir2);
}
}
var paths = Environment.GetEnvironmentVariable("MONO_PATH");
if (paths is not null) {
foreach (var tmp in paths.Split(Path.PathSeparator)) {
var path = tmp.Trim();
if (path != string.Empty && Directory.Exists(path))
extraMonoPathsList.Add(path);
}
}
extraMonoPaths = extraMonoPathsList.ToArray();
}
else {
var windir = Environment.GetEnvironmentVariable("WINDIR");
if (!string.IsNullOrEmpty(windir)) {
string path;
// .NET Framework 1.x and 2.x
path = Path.Combine(windir, "assembly");
if (Directory.Exists(path)) {
gacInfos.Add(new GacInfo(2, "", path, new string[] {
"GAC_32", "GAC_64", "GAC_MSIL", "GAC"
}));
}
// .NET Framework 4.x
path = Path.Combine(Path.Combine(windir, "Microsoft.NET"), "assembly");
if (Directory.Exists(path)) {
gacInfos.Add(new GacInfo(4, "v4.0_", path, new string[] {
"GAC_32", "GAC_64", "GAC_MSIL"
}));
}
}
}
}
static string GetCurrentMonoPrefix() {
var path = typeof(object).Module.FullyQualifiedName;
for (int i = 0; i < 4; i++)
path = Path.GetDirectoryName(path);
return path;
}
static IEnumerable<string> FindMonoPrefixes() {
yield return GetCurrentMonoPrefix();
var prefixes = Environment.GetEnvironmentVariable("MONO_GAC_PREFIX");
if (!string.IsNullOrEmpty(prefixes)) {
foreach (var tmp in prefixes.Split(Path.PathSeparator)) {
var prefix = tmp.Trim();
if (prefix != string.Empty)
yield return prefix;
}
}
}
/// <summary>
/// Gets/sets the default <see cref="ModuleContext"/>
/// </summary>
public ModuleContext DefaultModuleContext {
get => defaultModuleContext;
set => defaultModuleContext = value;
}
/// <summary>
/// <c>true</c> if <see cref="Resolve"/> should find an assembly that matches exactly.
/// <c>false</c> if it first tries to match exactly, and if that fails, it picks an
/// assembly that is closest to the requested assembly.
/// </summary>
public bool FindExactMatch {
get => findExactMatch;
set => findExactMatch = value;
}
/// <summary>
/// <c>true</c> if resolved .NET framework assemblies can be redirected to the source
/// module's framework assembly version. Eg. if a resolved .NET Framework 3.5 assembly can be
/// redirected to a .NET Framework 4.0 assembly if the source module is a .NET Framework 4.0 assembly. This is
/// ignored if <see cref="FindExactMatch"/> is <c>true</c>.
/// </summary>
public bool EnableFrameworkRedirect {
get => enableFrameworkRedirect;
set => enableFrameworkRedirect = value;
}
/// <summary>
/// If <c>true</c>, all modules in newly resolved assemblies will have their
/// <see cref="ModuleDef.EnableTypeDefFindCache"/> property set to <c>true</c>. This is
/// enabled by default since these modules shouldn't be modified by the user.
/// </summary>
public bool EnableTypeDefCache {
get => enableTypeDefCache;
set => enableTypeDefCache = value;
}
/// <summary>
/// true to search the Global Assembly Cache. Default value is true.
/// </summary>
public bool UseGAC {
get => useGac;
set => useGac = value;
}
/// <summary>
/// Gets paths searched before trying the standard locations
/// </summary>
public IList<string> PreSearchPaths => preSearchPaths;
/// <summary>
/// Gets paths searched after trying the standard locations
/// </summary>
public IList<string> PostSearchPaths => postSearchPaths;
/// <summary>
/// Default constructor
/// </summary>
public AssemblyResolver()
: this(null) {
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="defaultModuleContext">Module context for all resolved assemblies</param>
public AssemblyResolver(ModuleContext defaultModuleContext) {
this.defaultModuleContext = defaultModuleContext;
enableFrameworkRedirect = true;
}
/// <inheritdoc/>
public AssemblyDef Resolve(IAssembly assembly, ModuleDef sourceModule) {
if (assembly is null)
return null;
if (EnableFrameworkRedirect && !FindExactMatch)
FrameworkRedirect.ApplyFrameworkRedirect(ref assembly, sourceModule);
#if THREAD_SAFE
theLock.EnterWriteLock(); try {
#endif
var resolvedAssembly = Resolve2(assembly, sourceModule);
if (resolvedAssembly is null) {
string asmName = UTF8String.ToSystemStringOrEmpty(assembly.Name);
string asmNameTrimmed = asmName.Trim();
if (asmName != asmNameTrimmed) {
assembly = new AssemblyNameInfo {
Name = asmNameTrimmed,
Version = assembly.Version,
PublicKeyOrToken = assembly.PublicKeyOrToken,
Culture = assembly.Culture,
};
resolvedAssembly = Resolve2(assembly, sourceModule);
}
}
if (resolvedAssembly is null) {
// Make sure we don't search for this assembly again. This speeds up callers who
// keep asking for this assembly when trying to resolve many different TypeRefs
cachedAssemblies[GetAssemblyNameKey(assembly)] = null;
return null;
}
var key1 = GetAssemblyNameKey(resolvedAssembly);
var key2 = GetAssemblyNameKey(assembly);
cachedAssemblies.TryGetValue(key1, out var asm1);
cachedAssemblies.TryGetValue(key2, out var asm2);
if (asm1 != resolvedAssembly && asm2 != resolvedAssembly) {
// This assembly was just resolved
if (enableTypeDefCache) {
var modules = resolvedAssembly.Modules;
int count = modules.Count;
for (int i = 0; i < count; i++) {
var module = modules[i];
if (module is not null)
module.EnableTypeDefFindCache = true;
}
}
}
bool inserted = false;
if (!cachedAssemblies.ContainsKey(key1)) {
cachedAssemblies.Add(key1, resolvedAssembly);
inserted = true;
}
if (!cachedAssemblies.ContainsKey(key2)) {
cachedAssemblies.Add(key2, resolvedAssembly);
inserted = true;
}
if (inserted || asm1 == resolvedAssembly || asm2 == resolvedAssembly)
return resolvedAssembly;
// Dupe assembly. Don't insert it.
var dupeModule = resolvedAssembly.ManifestModule;
if (dupeModule is not null)
dupeModule.Dispose();
return asm1 ?? asm2;
#if THREAD_SAFE
} finally { theLock.ExitWriteLock(); }
#endif
}
/// <summary>
/// Add a module's assembly to the assembly cache
/// </summary>
/// <param name="module">The module whose assembly should be cached</param>
/// <returns><c>true</c> if <paramref name="module"/>'s assembly is cached, <c>false</c>
/// if it's not cached because some other assembly with the exact same full name has
/// already been cached or if <paramref name="module"/> or its assembly is <c>null</c>.</returns>
public bool AddToCache(ModuleDef module) => module is not null && AddToCache(module.Assembly);
/// <summary>
/// Add an assembly to the assembly cache
/// </summary>
/// <param name="asm">The assembly</param>
/// <returns><c>true</c> if <paramref name="asm"/> is cached, <c>false</c> if it's not
/// cached because some other assembly with the exact same full name has already been
/// cached or if <paramref name="asm"/> is <c>null</c>.</returns>
public bool AddToCache(AssemblyDef asm) {
if (asm is null)
return false;
var asmKey = GetAssemblyNameKey(asm);
#if THREAD_SAFE
theLock.EnterWriteLock(); try {
#endif
if (cachedAssemblies.TryGetValue(asmKey, out var cachedAsm) && cachedAsm is not null)
return asm == cachedAsm;
if (enableTypeDefCache)
{
var modules = asm.Modules;
int count = modules.Count;
for (int i = 0; i < count; i++)
{
var module = modules[i];
if (module is not null)
module.EnableTypeDefFindCache = true;
}
}
cachedAssemblies[asmKey] = asm;
return true;
#if THREAD_SAFE
} finally { theLock.ExitWriteLock(); }
#endif
}
/// <summary>
/// Removes a module's assembly from the cache
/// </summary>
/// <param name="module">The module</param>
/// <returns><c>true</c> if its assembly was removed, <c>false</c> if it wasn't removed
/// since it wasn't in the cache, it has no assembly, or <paramref name="module"/> was
/// <c>null</c></returns>
public bool Remove(ModuleDef module) => module is not null && Remove(module.Assembly);
/// <summary>
/// Removes the assembly from the cache
/// </summary>
/// <param name="asm">The assembly</param>
/// <returns><c>true</c> if it was removed, <c>false</c> if it wasn't removed since it
/// wasn't in the cache or if <paramref name="asm"/> was <c>null</c></returns>
public bool Remove(AssemblyDef asm) {
if (asm is null)
return false;
var asmKey = GetAssemblyNameKey(asm);
#if THREAD_SAFE
theLock.EnterWriteLock(); try {
#endif
return cachedAssemblies.Remove(asmKey);
#if THREAD_SAFE
} finally { theLock.ExitWriteLock(); }
#endif
}
/// <summary>
/// Clears the cache and calls <see cref="IDisposable.Dispose()"/> on each cached module.
/// Use <see cref="Remove(AssemblyDef)"/> to remove any assemblies you added yourself
/// using <see cref="AddToCache(AssemblyDef)"/> before calling this method if you don't want
/// them disposed.
/// </summary>
public void Clear() {
List<AssemblyDef> asms;
#if THREAD_SAFE
theLock.EnterWriteLock(); try {
#endif
asms = new List<AssemblyDef>(cachedAssemblies.Values);
cachedAssemblies.Clear();
#if THREAD_SAFE
} finally { theLock.ExitWriteLock(); }
#endif
foreach (var asm in asms) {
if (asm is null)
continue;
foreach (var mod in asm.Modules)
mod.Dispose();
}
}
/// <summary>
/// Gets the cached assemblies in this resolver.
/// </summary>
/// <returns>The cached assemblies.</returns>
public IEnumerable<AssemblyDef> GetCachedAssemblies() {
AssemblyDef[] assemblies;
#if THREAD_SAFE
theLock.EnterReadLock(); try {
#endif
assemblies = cachedAssemblies.Values.ToArray();
#if THREAD_SAFE
} finally { theLock.ExitReadLock(); }
#endif
return assemblies;
}
static string GetAssemblyNameKey(IAssembly asmName) {
// Make sure the name contains PublicKeyToken= and not PublicKey=
return asmName.FullNameToken;
}
AssemblyDef Resolve2(IAssembly assembly, ModuleDef sourceModule) {
if (cachedAssemblies.TryGetValue(GetAssemblyNameKey(assembly), out var resolvedAssembly))
return resolvedAssembly;
var moduleContext = defaultModuleContext;
if (moduleContext is null && sourceModule is not null)
moduleContext = sourceModule.Context;
resolvedAssembly = FindExactAssembly(assembly, PreFindAssemblies(assembly, sourceModule, true), moduleContext) ??
FindExactAssembly(assembly, FindAssemblies(assembly, sourceModule, true), moduleContext) ??
FindExactAssembly(assembly, PostFindAssemblies(assembly, sourceModule, true), moduleContext);
if (resolvedAssembly is not null)
return resolvedAssembly;
if (!findExactMatch) {
resolvedAssembly = FindClosestAssembly(assembly);
resolvedAssembly = FindClosestAssembly(assembly, resolvedAssembly, PreFindAssemblies(assembly, sourceModule, false), moduleContext);
resolvedAssembly = FindClosestAssembly(assembly, resolvedAssembly, FindAssemblies(assembly, sourceModule, false), moduleContext);
resolvedAssembly = FindClosestAssembly(assembly, resolvedAssembly, PostFindAssemblies(assembly, sourceModule, false), moduleContext);
}
return resolvedAssembly;
}
/// <summary>
/// Finds an assembly that exactly matches the requested assembly
/// </summary>
/// <param name="assembly">Assembly to find</param>
/// <param name="paths">Search paths or <c>null</c> if none</param>
/// <param name="moduleContext">Module context</param>
/// <returns>An <see cref="AssemblyDef"/> instance or <c>null</c> if an exact match
/// couldn't be found.</returns>
AssemblyDef FindExactAssembly(IAssembly assembly, IEnumerable<string> paths, ModuleContext moduleContext) {
if (paths is null)
return null;
var asmComparer = AssemblyNameComparer.CompareAll;
foreach (var path in paths) {
ModuleDefMD mod = null;
try {
mod = ModuleDefMD.Load(path, moduleContext);
var asm = mod.Assembly;
if (asm is not null && asmComparer.Equals(assembly, asm)) {
mod = null;
return asm;
}
}
catch {
}
finally {
if (mod is not null)
mod.Dispose();
}
}
return null;
}
/// <summary>
/// Finds the closest assembly from the already cached assemblies
/// </summary>
/// <param name="assembly">Assembly to find</param>
/// <returns>The closest <see cref="AssemblyDef"/> or <c>null</c> if none found</returns>
AssemblyDef FindClosestAssembly(IAssembly assembly) {
AssemblyDef closest = null;
var asmComparer = AssemblyNameComparer.CompareAll;
foreach (var kv in cachedAssemblies) {
var asm = kv.Value;
if (asm is null)
continue;
if (asmComparer.CompareClosest(assembly, closest, asm) == 1)
closest = asm;
}
return closest;
}
AssemblyDef FindClosestAssembly(IAssembly assembly, AssemblyDef closest, IEnumerable<string> paths, ModuleContext moduleContext) {
if (paths is null)
return closest;
var asmComparer = AssemblyNameComparer.CompareAll;
foreach (var path in paths) {
ModuleDefMD mod = null;
try {
mod = ModuleDefMD.Load(path, moduleContext);
var asm = mod.Assembly;
if (asm is not null && asmComparer.CompareClosest(assembly, closest, asm) == 1) {
if (!IsCached(closest) && closest is not null) {
var closeMod = closest.ManifestModule;
if (closeMod is not null)
closeMod.Dispose();
}
closest = asm;
mod = null;
}
}
catch {
}
finally {
if (mod is not null)
mod.Dispose();
}
}
return closest;
}
/// <summary>
/// Returns <c>true</c> if <paramref name="asm"/> is inserted in <see cref="cachedAssemblies"/>
/// </summary>
/// <param name="asm">Assembly to check</param>
bool IsCached(AssemblyDef asm) {
if (asm is null)
return false;
return cachedAssemblies.TryGetValue(GetAssemblyNameKey(asm), out var cachedAsm) &&
cachedAsm == asm;
}
IEnumerable<string> FindAssemblies2(IAssembly assembly, IEnumerable<string> paths) {
if (paths is not null) {
var asmSimpleName = UTF8String.ToSystemStringOrEmpty(assembly.Name);
var exts = assembly.IsContentTypeWindowsRuntime ? winMDAssemblyExtensions : assemblyExtensions;
foreach (var ext in exts) {
foreach (var path in paths) {
string fullPath;
try {
fullPath = Path.Combine(path, asmSimpleName + ext);
}
catch (ArgumentException) {
// Invalid path chars
yield break;
}
if (File.Exists(fullPath))
yield return fullPath;
}
}
}
}
/// <summary>
/// Called before <see cref="FindAssemblies"/>
/// </summary>
/// <param name="assembly">Assembly to find</param>
/// <param name="sourceModule">The module that needs to resolve an assembly or <c>null</c></param>
/// <param name="matchExactly">We're trying to find an exact match</param>
/// <returns><c>null</c> or an enumerable of full paths to try</returns>
protected virtual IEnumerable<string> PreFindAssemblies(IAssembly assembly, ModuleDef sourceModule, bool matchExactly) {
foreach (var path in FindAssemblies2(assembly, preSearchPaths))
yield return path;
}
/// <summary>
/// Called after <see cref="FindAssemblies"/> (if it fails)
/// </summary>
/// <param name="assembly">Assembly to find</param>
/// <param name="sourceModule">The module that needs to resolve an assembly or <c>null</c></param>
/// <param name="matchExactly">We're trying to find an exact match</param>
/// <returns><c>null</c> or an enumerable of full paths to try</returns>
protected virtual IEnumerable<string> PostFindAssemblies(IAssembly assembly, ModuleDef sourceModule, bool matchExactly) {
foreach (var path in FindAssemblies2(assembly, postSearchPaths))
yield return path;
}
/// <summary>
/// Called after <see cref="PreFindAssemblies"/> (if it fails)
/// </summary>
/// <param name="assembly">Assembly to find</param>
/// <param name="sourceModule">The module that needs to resolve an assembly or <c>null</c></param>
/// <param name="matchExactly">We're trying to find an exact match</param>
/// <returns><c>null</c> or an enumerable of full paths to try</returns>
protected virtual IEnumerable<string> FindAssemblies(IAssembly assembly, ModuleDef sourceModule, bool matchExactly) {
if (assembly.IsContentTypeWindowsRuntime) {
string path;
try {
path = Path.Combine(Path.Combine(Environment.SystemDirectory, "WinMetadata"), assembly.Name + ".winmd");
}
catch (ArgumentException) {
// Invalid path chars
path = null;
}
if (File.Exists(path))
yield return path;
}
else {
if (UseGAC) {
foreach (var path in FindAssembliesGac(assembly, sourceModule, matchExactly))
yield return path;
}
}
foreach (var path in FindAssembliesModuleSearchPaths(assembly, sourceModule, matchExactly))
yield return path;
}
IEnumerable<string> FindAssembliesGac(IAssembly assembly, ModuleDef sourceModule, bool matchExactly) {
if (matchExactly)
return FindAssembliesGacExactly(assembly, sourceModule);
return FindAssembliesGacAny(assembly, sourceModule);
}
IEnumerable<GacInfo> GetGacInfos(ModuleDef sourceModule) {
int version = sourceModule is null ? int.MinValue : sourceModule.IsClr40 ? 4 : 2;
// Try the correct GAC first (eg. GAC4 if it's a .NET Framework 4 assembly)
foreach (var gacInfo in gacInfos) {
if (gacInfo.Version == version)
yield return gacInfo;
}
foreach (var gacInfo in gacInfos) {
if (gacInfo.Version != version)
yield return gacInfo;
}
}
IEnumerable<string> FindAssembliesGacExactly(IAssembly assembly, ModuleDef sourceModule) {
foreach (var gacInfo in GetGacInfos(sourceModule)) {
foreach (var path in FindAssembliesGacExactly(gacInfo, assembly, sourceModule))
yield return path;
}
if (extraMonoPaths is not null) {
foreach (var path in GetExtraMonoPaths(assembly, sourceModule))
yield return path;
}
}
static IEnumerable<string> GetExtraMonoPaths(IAssembly assembly, ModuleDef sourceModule) {
if (extraMonoPaths is not null) {
foreach (var dir in extraMonoPaths) {
string file;
try {
file = Path.Combine(dir, assembly.Name + ".dll");
}
catch (ArgumentException) {
// Invalid path chars
break;
}
if (File.Exists(file))
yield return file;
}
}
}
IEnumerable<string> FindAssembliesGacExactly(GacInfo gacInfo, IAssembly assembly, ModuleDef sourceModule) {
var pkt = PublicKeyBase.ToPublicKeyToken(assembly.PublicKeyOrToken);
if (gacInfo is not null && pkt is not null) {
string pktString = pkt.ToString();
string verString = Utils.CreateVersionWithNoUndefinedValues(assembly.Version).ToString();
var cultureString = UTF8String.ToSystemStringOrEmpty(assembly.Culture);
if (cultureString.Equals("neutral", StringComparison.OrdinalIgnoreCase))
cultureString = string.Empty;
var asmSimpleName = UTF8String.ToSystemStringOrEmpty(assembly.Name);
foreach (var subDir in gacInfo.SubDirs) {
var baseDir = Path.Combine(gacInfo.Path, subDir);
try {
baseDir = Path.Combine(baseDir, asmSimpleName);
}
catch (ArgumentException) {
// Invalid path chars
break;
}
baseDir = Path.Combine(baseDir, $"{gacInfo.Prefix}{verString}_{cultureString}_{pktString}");
var pathName = Path.Combine(baseDir, asmSimpleName + ".dll");
if (File.Exists(pathName))
yield return pathName;
}
}
}
IEnumerable<string> FindAssembliesGacAny(IAssembly assembly, ModuleDef sourceModule) {
foreach (var gacInfo in GetGacInfos(sourceModule)) {
foreach (var path in FindAssembliesGacAny(gacInfo, assembly, sourceModule))
yield return path;
}
if (extraMonoPaths is not null) {
foreach (var path in GetExtraMonoPaths(assembly, sourceModule))
yield return path;
}
}
IEnumerable<string> FindAssembliesGacAny(GacInfo gacInfo, IAssembly assembly, ModuleDef sourceModule) {
if (gacInfo is not null) {
var asmSimpleName = UTF8String.ToSystemStringOrEmpty(assembly.Name);
foreach (var subDir in gacInfo.SubDirs) {
var baseDir = Path.Combine(gacInfo.Path, subDir);
try {
baseDir = Path.Combine(baseDir, asmSimpleName);
}
catch (ArgumentException) {
// Invalid path chars
break;
}
foreach (var dir in GetDirs(baseDir)) {
var pathName = Path.Combine(dir, asmSimpleName + ".dll");
if (File.Exists(pathName))
yield return pathName;
}
}
}
}
IEnumerable<string> GetDirs(string baseDir) {
if (!Directory.Exists(baseDir))
return Array2.Empty<string>();
var dirs = new List<string>();
try {
foreach (var di in new DirectoryInfo(baseDir).GetDirectories())
dirs.Add(di.FullName);
}
catch {
}
return dirs;
}
IEnumerable<string> FindAssembliesModuleSearchPaths(IAssembly assembly, ModuleDef sourceModule, bool matchExactly) {
string asmSimpleName = UTF8String.ToSystemStringOrEmpty(assembly.Name);
var searchPaths = GetSearchPaths(sourceModule);
var exts = assembly.IsContentTypeWindowsRuntime ? winMDAssemblyExtensions : assemblyExtensions;
foreach (var ext in exts) {
foreach (var path in searchPaths) {
for (int i = 0; i < 2; i++) {
string path2;
try {
if (i == 0)
path2 = Path.Combine(path, asmSimpleName + ext);
else
path2 = Path.Combine(Path.Combine(path, asmSimpleName), asmSimpleName + ext);
}
catch (ArgumentException) {
// Invalid path chars
yield break;
}
if (File.Exists(path2))
yield return path2;
}
}
}
}
/// <summary>
/// Gets all search paths to use for this module
/// </summary>
/// <param name="module">The module or <c>null</c> if unknown</param>
/// <returns>A list of all search paths to use for this module</returns>
IEnumerable<string> GetSearchPaths(ModuleDef module) {
var keyModule = module;
if (keyModule is null)
keyModule = nullModule;
if (moduleSearchPaths.TryGetValue(keyModule, out var searchPaths))
return searchPaths;
moduleSearchPaths[keyModule] = searchPaths = new List<string>(GetModuleSearchPaths(module));
return searchPaths;
}
/// <summary>
/// Gets all module search paths. This is usually empty unless its assembly has
/// a <c>.config</c> file specifying any additional private search paths in a
/// &lt;probing/&gt; element.
/// </summary>
/// <param name="module">The module or <c>null</c> if unknown</param>
/// <returns>A list of search paths</returns>
protected virtual IEnumerable<string> GetModuleSearchPaths(ModuleDef module) => GetModulePrivateSearchPaths(module);
/// <summary>
/// Gets all private assembly search paths as found in the module's <c>.config</c> file.
/// </summary>
/// <param name="module">The module or <c>null</c> if unknown</param>
/// <returns>A list of search paths</returns>
protected IEnumerable<string> GetModulePrivateSearchPaths(ModuleDef module) {
if (module is null)
return Array2.Empty<string>();
var asm = module.Assembly;
if (asm is null)
return Array2.Empty<string>();
module = asm.ManifestModule;
if (module is null)
return Array2.Empty<string>(); // Should never happen
string baseDir = null;
try {
var imageName = module.Location;
if (imageName != string.Empty) {
var directoryInfo = Directory.GetParent(imageName);
if (directoryInfo is not null) {
baseDir = directoryInfo.FullName;
var configName = imageName + ".config";
if (File.Exists(configName))
return GetPrivatePaths(baseDir, configName);
}
}
}
catch {
}
if (baseDir is not null)
return new List<string> { baseDir };
return Array2.Empty<string>();
}
IEnumerable<string> GetPrivatePaths(string baseDir, string configFileName) {
var searchPaths = new List<string>();
try {
var dirName = Path.GetDirectoryName(Path.GetFullPath(configFileName));
searchPaths.Add(dirName);
using (var xmlStream = new FileStream(configFileName, FileMode.Open, FileAccess.Read, FileShare.Read)) {
var doc = new XmlDocument();
doc.Load(XmlReader.Create(xmlStream));
foreach (var tmp in doc.GetElementsByTagName("probing")) {
var probingElem = tmp as XmlElement;
if (probingElem is null)
continue;
var privatePath = probingElem.GetAttribute("privatePath");
if (string.IsNullOrEmpty(privatePath))
continue;
foreach (var tmp2 in privatePath.Split(';')) {
var path = tmp2.Trim();
if (path == "")
continue;
var newPath = Path.GetFullPath(Path.Combine(dirName, path.Replace('\\', Path.DirectorySeparatorChar)));
if (Directory.Exists(newPath) && newPath.StartsWith(baseDir + Path.DirectorySeparatorChar))
searchPaths.Add(newPath);
}
}
}
}
catch (ArgumentException) {
}
catch (IOException) {
}
catch (XmlException) {
}
return searchPaths;
}
}
}

View File

@ -1,48 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System;
namespace dnlib.DotNet {
/// <summary>
/// See CorHdr.h/CorCallingConvention
/// </summary>
[Flags]
public enum CallingConvention : byte {
/// <summary>The managed calling convention</summary>
Default = 0x0,
/// <summary/>
C = 0x1,
/// <summary/>
StdCall = 0x2,
/// <summary/>
ThisCall = 0x3,
/// <summary/>
FastCall = 0x4,
/// <summary/>
VarArg = 0x5,
/// <summary/>
Field = 0x6,
/// <summary/>
LocalSig = 0x7,
/// <summary/>
Property = 0x8,
/// <summary>Unmanaged calling convention encoded as modopts</summary>
Unmanaged = 0x9,
/// <summary>generic method instantiation</summary>
GenericInst = 0xA,
/// <summary>used ONLY for 64bit vararg PInvoke calls</summary>
NativeVarArg = 0xB,
/// <summary>Calling convention is bottom 4 bits</summary>
Mask = 0x0F,
/// <summary>Generic method</summary>
Generic = 0x10,
/// <summary>Method needs a 'this' parameter</summary>
HasThis = 0x20,
/// <summary>'this' parameter is the first arg if set (else it's hidden)</summary>
ExplicitThis = 0x40,
/// <summary>Used internally by the CLR</summary>
ReservedByCLR = 0x80,
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,99 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System;
using System.Diagnostics;
using dnlib.DotNet.MD;
namespace dnlib.DotNet {
/// <summary>
/// A high-level representation of a row in the ClassLayout table
/// </summary>
public abstract class ClassLayout : IMDTokenProvider {
/// <summary>
/// The row id in its table
/// </summary>
protected uint rid;
/// <inheritdoc/>
public MDToken MDToken => new MDToken(Table.ClassLayout, rid);
/// <inheritdoc/>
public uint Rid {
get => rid;
set => rid = value;
}
/// <summary>
/// From column ClassLayout.PackingSize
/// </summary>
public ushort PackingSize {
get => packingSize;
set => packingSize = value;
}
/// <summary/>
protected ushort packingSize;
/// <summary>
/// From column ClassLayout.ClassSize
/// </summary>
public uint ClassSize {
get => classSize;
set => classSize = value;
}
/// <summary/>
protected uint classSize;
}
/// <summary>
/// A ClassLayout row created by the user and not present in the original .NET file
/// </summary>
public class ClassLayoutUser : ClassLayout {
/// <summary>
/// Default constructor
/// </summary>
public ClassLayoutUser() {
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="packingSize">PackingSize</param>
/// <param name="classSize">ClassSize</param>
public ClassLayoutUser(ushort packingSize, uint classSize) {
this.packingSize = packingSize;
this.classSize = classSize;
}
}
/// <summary>
/// Created from a row in the ClassLayout table
/// </summary>
sealed class ClassLayoutMD : ClassLayout, IMDTokenProviderMD {
readonly uint origRid;
/// <inheritdoc/>
public uint OrigRid => origRid;
/// <summary>
/// Constructor
/// </summary>
/// <param name="readerModule">The module which contains this <c>ClassLayout</c> row</param>
/// <param name="rid">Row ID</param>
/// <exception cref="ArgumentNullException">If <paramref name="readerModule"/> is <c>null</c></exception>
/// <exception cref="ArgumentException">If <paramref name="rid"/> is invalid</exception>
public ClassLayoutMD(ModuleDefMD readerModule, uint rid) {
#if DEBUG
if (readerModule is null)
throw new ArgumentNullException("readerModule");
if (readerModule.TablesStream.ClassLayoutTable.IsInvalidRID(rid))
throw new BadImageFormatException($"ClassLayout rid {rid} does not exist");
#endif
origRid = rid;
this.rid = rid;
bool b = readerModule.TablesStream.TryReadClassLayoutRow(origRid, out var row);
Debug.Assert(b);
classSize = row.ClassSize;
packingSize = row.PackingSize;
}
}
}

View File

@ -1,204 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System;
using System.Diagnostics;
using dnlib.DotNet.MD;
using dnlib.IO;
namespace dnlib.DotNet {
/// <summary>
/// A high-level representation of a row in the Constant table
/// </summary>
public abstract class Constant : IMDTokenProvider {
/// <summary>
/// The row id in its table
/// </summary>
protected uint rid;
/// <inheritdoc/>
public MDToken MDToken => new MDToken(Table.Constant, rid);
/// <inheritdoc/>
public uint Rid {
get => rid;
set => rid = value;
}
/// <summary>
/// From column Constant.Type
/// </summary>
public ElementType Type {
get => type;
set => type = value;
}
/// <summary/>
protected ElementType type;
/// <summary>
/// From column Constant.Value
/// </summary>
public object Value {
get => value;
set => this.value = value;
}
/// <summary/>
protected object value;
}
/// <summary>
/// A Constant row created by the user and not present in the original .NET file
/// </summary>
public class ConstantUser : Constant {
/// <summary>
/// Default constructor
/// </summary>
public ConstantUser() {
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="value">Value</param>
public ConstantUser(object value) {
type = GetElementType(value);
this.value = value;
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="value">Value</param>
/// <param name="type">Type</param>
public ConstantUser(object value, ElementType type) {
this.type = type;
this.value = value;
}
static ElementType GetElementType(object value) {
if (value is null)
return ElementType.Class;
return System.Type.GetTypeCode(value.GetType()) switch {
TypeCode.Boolean => ElementType.Boolean,
TypeCode.Char => ElementType.Char,
TypeCode.SByte => ElementType.I1,
TypeCode.Byte => ElementType.U1,
TypeCode.Int16 => ElementType.I2,
TypeCode.UInt16 => ElementType.U2,
TypeCode.Int32 => ElementType.I4,
TypeCode.UInt32 => ElementType.U4,
TypeCode.Int64 => ElementType.I8,
TypeCode.UInt64 => ElementType.U8,
TypeCode.Single => ElementType.R4,
TypeCode.Double => ElementType.R8,
TypeCode.String => ElementType.String,
_ => ElementType.Void,
};
}
}
/// <summary>
/// Created from a row in the Constant table
/// </summary>
sealed class ConstantMD : Constant, IMDTokenProviderMD {
readonly uint origRid;
/// <inheritdoc/>
public uint OrigRid => origRid;
/// <summary>
/// Constructor
/// </summary>
/// <param name="readerModule">The module which contains this <c>Constant</c> row</param>
/// <param name="rid">Row ID</param>
/// <exception cref="ArgumentNullException">If <paramref name="readerModule"/> is <c>null</c></exception>
/// <exception cref="ArgumentException">If <paramref name="rid"/> is invalid</exception>
public ConstantMD(ModuleDefMD readerModule, uint rid) {
#if DEBUG
if (readerModule is null)
throw new ArgumentNullException("readerModule");
if (readerModule.TablesStream.ConstantTable.IsInvalidRID(rid))
throw new BadImageFormatException($"Constant rid {rid} does not exist");
#endif
origRid = rid;
this.rid = rid;
bool b = readerModule.TablesStream.TryReadConstantRow(origRid, out var row);
Debug.Assert(b);
type = (ElementType)row.Type;
var reader = readerModule.BlobStream.CreateReader(row.Value);
value = GetValue(type, ref reader);
}
static object GetValue(ElementType etype, ref DataReader reader) {
switch (etype) {
case ElementType.Boolean:
if (reader.Length < 1)
return false;
return reader.ReadBoolean();
case ElementType.Char:
if (reader.Length < 2)
return (char)0;
return reader.ReadChar();
case ElementType.I1:
if (reader.Length < 1)
return (sbyte)0;
return reader.ReadSByte();
case ElementType.U1:
if (reader.Length < 1)
return (byte)0;
return reader.ReadByte();
case ElementType.I2:
if (reader.Length < 2)
return (short)0;
return reader.ReadInt16();
case ElementType.U2:
if (reader.Length < 2)
return (ushort)0;
return reader.ReadUInt16();
case ElementType.I4:
if (reader.Length < 4)
return (int)0;
return reader.ReadInt32();
case ElementType.U4:
if (reader.Length < 4)
return (uint)0;
return reader.ReadUInt32();
case ElementType.I8:
if (reader.Length < 8)
return (long)0;
return reader.ReadInt64();
case ElementType.U8:
if (reader.Length < 8)
return (ulong)0;
return reader.ReadUInt64();
case ElementType.R4:
if (reader.Length < 4)
return (float)0;
return reader.ReadSingle();
case ElementType.R8:
if (reader.Length < 8)
return (double)0;
return reader.ReadDouble();
case ElementType.String:
return reader.ReadUtf16String((int)(reader.BytesLeft / 2));
case ElementType.Class:
return null;
default:
return null;
}
}
}
}

View File

@ -1,143 +0,0 @@
// dnlib: See LICENSE.txt for more info
namespace dnlib.DotNet {
/// <summary>
/// Default implementation of <see cref="ICorLibTypes"/>
/// </summary>
public sealed class CorLibTypes : ICorLibTypes {
readonly ModuleDef module;
CorLibTypeSig typeVoid;
CorLibTypeSig typeBoolean;
CorLibTypeSig typeChar;
CorLibTypeSig typeSByte;
CorLibTypeSig typeByte;
CorLibTypeSig typeInt16;
CorLibTypeSig typeUInt16;
CorLibTypeSig typeInt32;
CorLibTypeSig typeUInt32;
CorLibTypeSig typeInt64;
CorLibTypeSig typeUInt64;
CorLibTypeSig typeSingle;
CorLibTypeSig typeDouble;
CorLibTypeSig typeString;
CorLibTypeSig typeTypedReference;
CorLibTypeSig typeIntPtr;
CorLibTypeSig typeUIntPtr;
CorLibTypeSig typeObject;
readonly AssemblyRef corLibAssemblyRef;
/// <inheritdoc/>
public CorLibTypeSig Void => typeVoid;
/// <inheritdoc/>
public CorLibTypeSig Boolean => typeBoolean;
/// <inheritdoc/>
public CorLibTypeSig Char => typeChar;
/// <inheritdoc/>
public CorLibTypeSig SByte => typeSByte;
/// <inheritdoc/>
public CorLibTypeSig Byte => typeByte;
/// <inheritdoc/>
public CorLibTypeSig Int16 => typeInt16;
/// <inheritdoc/>
public CorLibTypeSig UInt16 => typeUInt16;
/// <inheritdoc/>
public CorLibTypeSig Int32 => typeInt32;
/// <inheritdoc/>
public CorLibTypeSig UInt32 => typeUInt32;
/// <inheritdoc/>
public CorLibTypeSig Int64 => typeInt64;
/// <inheritdoc/>
public CorLibTypeSig UInt64 => typeUInt64;
/// <inheritdoc/>
public CorLibTypeSig Single => typeSingle;
/// <inheritdoc/>
public CorLibTypeSig Double => typeDouble;
/// <inheritdoc/>
public CorLibTypeSig String => typeString;
/// <inheritdoc/>
public CorLibTypeSig TypedReference => typeTypedReference;
/// <inheritdoc/>
public CorLibTypeSig IntPtr => typeIntPtr;
/// <inheritdoc/>
public CorLibTypeSig UIntPtr => typeUIntPtr;
/// <inheritdoc/>
public CorLibTypeSig Object => typeObject;
/// <inheritdoc/>
public AssemblyRef AssemblyRef => corLibAssemblyRef;
/// <summary>
/// Constructor
/// </summary>
/// <param name="module">The owner module</param>
public CorLibTypes(ModuleDef module)
: this(module, null) {
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="module">The owner module</param>
/// <param name="corLibAssemblyRef">Corlib assembly reference or <c>null</c> if a default
/// assembly reference should be created</param>
public CorLibTypes(ModuleDef module, AssemblyRef corLibAssemblyRef) {
this.module = module;
this.corLibAssemblyRef = corLibAssemblyRef ?? CreateCorLibAssemblyRef();
Initialize();
}
AssemblyRef CreateCorLibAssemblyRef() => module.UpdateRowId(AssemblyRefUser.CreateMscorlibReferenceCLR20());
void Initialize() {
bool isCorLib = module.Assembly.IsCorLib();
typeVoid = new CorLibTypeSig(CreateCorLibTypeRef(isCorLib, "Void"), ElementType.Void);
typeBoolean = new CorLibTypeSig(CreateCorLibTypeRef(isCorLib, "Boolean"), ElementType.Boolean);
typeChar = new CorLibTypeSig(CreateCorLibTypeRef(isCorLib, "Char"), ElementType.Char);
typeSByte = new CorLibTypeSig(CreateCorLibTypeRef(isCorLib, "SByte"), ElementType.I1);
typeByte = new CorLibTypeSig(CreateCorLibTypeRef(isCorLib, "Byte"), ElementType.U1);
typeInt16 = new CorLibTypeSig(CreateCorLibTypeRef(isCorLib, "Int16"), ElementType.I2);
typeUInt16 = new CorLibTypeSig(CreateCorLibTypeRef(isCorLib, "UInt16"), ElementType.U2);
typeInt32 = new CorLibTypeSig(CreateCorLibTypeRef(isCorLib, "Int32"), ElementType.I4);
typeUInt32 = new CorLibTypeSig(CreateCorLibTypeRef(isCorLib, "UInt32"), ElementType.U4);
typeInt64 = new CorLibTypeSig(CreateCorLibTypeRef(isCorLib, "Int64"), ElementType.I8);
typeUInt64 = new CorLibTypeSig(CreateCorLibTypeRef(isCorLib, "UInt64"), ElementType.U8);
typeSingle = new CorLibTypeSig(CreateCorLibTypeRef(isCorLib, "Single"), ElementType.R4);
typeDouble = new CorLibTypeSig(CreateCorLibTypeRef(isCorLib, "Double"), ElementType.R8);
typeString = new CorLibTypeSig(CreateCorLibTypeRef(isCorLib, "String"), ElementType.String);
typeTypedReference = new CorLibTypeSig(CreateCorLibTypeRef(isCorLib, "TypedReference"), ElementType.TypedByRef);
typeIntPtr = new CorLibTypeSig(CreateCorLibTypeRef(isCorLib, "IntPtr"), ElementType.I);
typeUIntPtr = new CorLibTypeSig(CreateCorLibTypeRef(isCorLib, "UIntPtr"), ElementType.U);
typeObject = new CorLibTypeSig(CreateCorLibTypeRef(isCorLib, "Object"), ElementType.Object);
}
ITypeDefOrRef CreateCorLibTypeRef(bool isCorLib, string name) {
var tr = new TypeRefUser(module, "System", name, corLibAssemblyRef);
if (isCorLib) {
var td = module.Find(tr);
if (td is not null)
return td;
}
return module.UpdateRowId(tr);
}
/// <inheritdoc/>
public TypeRef GetTypeRef(string @namespace, string name) => module.UpdateRowId(new TypeRefUser(module, @namespace, name, corLibAssemblyRef));
}
}

View File

@ -1,427 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System;
using dnlib.DotNet.Writer;
using dnlib.IO;
using dnlib.PE;
namespace dnlib.DotNet {
enum StubType {
Export,
EntryPoint,
}
abstract class CpuArch {
// To support a new CPU arch, the easiest way is to check coreclr/src/ilasm/writer.cpp or
// coreclr/src/dlls/mscorpe/stubs.h, eg. ExportStubAMD64Template, ExportStubX86Template,
// ExportStubARMTemplate, ExportStubIA64Template, or use ilasm to generate a file with
// exports and check the stub
static readonly X86CpuArch x86CpuArch = new X86CpuArch();
static readonly X64CpuArch x64CpuArch = new X64CpuArch();
static readonly ItaniumCpuArch itaniumCpuArch = new ItaniumCpuArch();
static readonly ArmCpuArch armCpuArch = new ArmCpuArch();
/// <summary>
/// Gets the required alignment for the stubs, must be a power of 2
/// </summary>
/// <param name="stubType">Stub type</param>
/// <returns></returns>
public abstract uint GetStubAlignment(StubType stubType);
/// <summary>
/// Gets the size of a stub, it doesn't have to be a multiple of <see cref="GetStubAlignment(StubType)"/>
/// </summary>
/// <param name="stubType">Stub type</param>
/// <returns></returns>
public abstract uint GetStubSize(StubType stubType);
/// <summary>
/// Gets the offset of the code (entry point) relative to the start of the stub
/// </summary>
/// <param name="stubType">Stub type</param>
/// <returns></returns>
public abstract uint GetStubCodeOffset(StubType stubType);
public static bool TryGetCpuArch(Machine machine, out CpuArch cpuArch) {
switch (machine) {
case Machine.I386:
case Machine.I386_Native_Apple:
case Machine.I386_Native_FreeBSD:
case Machine.I386_Native_Linux:
case Machine.I386_Native_NetBSD:
case Machine.I386_Native_Sun:
cpuArch = x86CpuArch;
return true;
case Machine.AMD64:
case Machine.AMD64_Native_Apple:
case Machine.AMD64_Native_FreeBSD:
case Machine.AMD64_Native_Linux:
case Machine.AMD64_Native_NetBSD:
case Machine.AMD64_Native_Sun:
cpuArch = x64CpuArch;
return true;
case Machine.IA64:
cpuArch = itaniumCpuArch;
return true;
case Machine.ARMNT:
case Machine.ARMNT_Native_Apple:
case Machine.ARMNT_Native_FreeBSD:
case Machine.ARMNT_Native_Linux:
case Machine.ARMNT_Native_NetBSD:
case Machine.ARMNT_Native_Sun:
cpuArch = armCpuArch;
return true;
case Machine.ARM64:
case Machine.ARM64_Native_Apple:
case Machine.ARM64_Native_FreeBSD:
case Machine.ARM64_Native_Linux:
case Machine.ARM64_Native_NetBSD:
case Machine.ARM64_Native_Sun:
//TODO: Support ARM64
goto default;
default:
cpuArch = null;
return false;
}
}
/// <summary>
/// Gets the RVA of the func field that the stub jumps to
/// </summary>
/// <param name="reader">Reader, positioned at the stub func</param>
/// <param name="peImage">PE image</param>
/// <param name="funcRva">Updated with RVA of func field</param>
/// <returns></returns>
public bool TryGetExportedRvaFromStub(ref DataReader reader, IPEImage peImage, out uint funcRva) =>
TryGetExportedRvaFromStubCore(ref reader, peImage, out funcRva);
protected abstract bool TryGetExportedRvaFromStubCore(ref DataReader reader, IPEImage peImage, out uint funcRva);
/// <summary>
/// Writes stub relocs, if needed
/// </summary>
/// <param name="stubType">Stub type</param>
/// <param name="relocDirectory">Reloc directory</param>
/// <param name="chunk">The chunk where this stub will be written to</param>
/// <param name="stubOffset">Offset of this stub in <paramref name="chunk"/></param>
public abstract void WriteStubRelocs(StubType stubType, RelocDirectory relocDirectory, IChunk chunk, uint stubOffset);
/// <summary>
/// Writes the stub that jumps to the managed function
/// </summary>
/// <param name="stubType">Stub type</param>
/// <param name="writer">Writer</param>
/// <param name="imageBase">Image base</param>
/// <param name="stubRva">RVA of this stub</param>
/// <param name="managedFuncRva">RVA of a pointer-sized field that contains the absolute address of the managed function</param>
public abstract void WriteStub(StubType stubType, DataWriter writer, ulong imageBase, uint stubRva, uint managedFuncRva);
}
sealed class X86CpuArch : CpuArch {
public override uint GetStubAlignment(StubType stubType) {
switch (stubType) {
case StubType.Export:
case StubType.EntryPoint:
return 4;
default:
throw new ArgumentOutOfRangeException();
}
}
public override uint GetStubSize(StubType stubType) {
switch (stubType) {
case StubType.Export:
case StubType.EntryPoint:
return 2/*padding*/ + 6;
default:
throw new ArgumentOutOfRangeException();
}
}
public override uint GetStubCodeOffset(StubType stubType) {
switch (stubType) {
case StubType.Export:
case StubType.EntryPoint:
return 2/*padding*/;
default:
throw new ArgumentOutOfRangeException();
}
}
protected override bool TryGetExportedRvaFromStubCore(ref DataReader reader, IPEImage peImage, out uint funcRva) {
funcRva = 0;
// FF25xxxxxxxx jmp DWORD PTR [xxxxxxxx]
if (reader.ReadUInt16() != 0x25FF)
return false;
funcRva = reader.ReadUInt32() - (uint)peImage.ImageNTHeaders.OptionalHeader.ImageBase;
return true;
}
public override void WriteStubRelocs(StubType stubType, RelocDirectory relocDirectory, IChunk chunk, uint stubOffset) {
switch (stubType) {
case StubType.Export:
case StubType.EntryPoint:
relocDirectory.Add(chunk, stubOffset + 4);
break;
default:
throw new ArgumentOutOfRangeException();
}
}
public override void WriteStub(StubType stubType, DataWriter writer, ulong imageBase, uint stubRva, uint managedFuncRva) {
switch (stubType) {
case StubType.Export:
case StubType.EntryPoint:
writer.WriteUInt16(0);// padding
writer.WriteUInt16(0x25FF);
writer.WriteUInt32((uint)imageBase + managedFuncRva);
break;
default:
throw new ArgumentOutOfRangeException();
}
}
}
sealed class X64CpuArch : CpuArch {
public override uint GetStubAlignment(StubType stubType) {
switch (stubType) {
case StubType.Export:
case StubType.EntryPoint:
return 4;
default:
throw new ArgumentOutOfRangeException();
}
}
public override uint GetStubSize(StubType stubType) {
switch (stubType) {
case StubType.Export:
case StubType.EntryPoint:
return 2/*padding*/ + 12;
default:
throw new ArgumentOutOfRangeException();
}
}
public override uint GetStubCodeOffset(StubType stubType) {
switch (stubType) {
case StubType.Export:
case StubType.EntryPoint:
return 2/*padding*/;
default:
throw new ArgumentOutOfRangeException();
}
}
protected override bool TryGetExportedRvaFromStubCore(ref DataReader reader, IPEImage peImage, out uint funcRva) {
funcRva = 0;
// 48A1xxxxxxxxxxxxxxxx movabs rax,[xxxxxxxxxxxxxxxx]
// FFE0 jmp rax
if (reader.ReadUInt16() != 0xA148)
return false;
ulong absAddr = reader.ReadUInt64();
if (reader.ReadUInt16() != 0xE0FF)
return false;
ulong rva = absAddr - peImage.ImageNTHeaders.OptionalHeader.ImageBase;
if (rva > uint.MaxValue)
return false;
funcRva = (uint)rva;
return true;
}
public override void WriteStubRelocs(StubType stubType, RelocDirectory relocDirectory, IChunk chunk, uint stubOffset) {
switch (stubType) {
case StubType.Export:
case StubType.EntryPoint:
relocDirectory.Add(chunk, stubOffset + 4);
break;
default:
throw new ArgumentOutOfRangeException();
}
}
public override void WriteStub(StubType stubType, DataWriter writer, ulong imageBase, uint stubRva, uint managedFuncRva) {
switch (stubType) {
case StubType.Export:
case StubType.EntryPoint:
writer.WriteUInt16(0);// padding
writer.WriteUInt16(0xA148);
writer.WriteUInt64(imageBase + managedFuncRva);
writer.WriteUInt16(0xE0FF);
break;
default:
throw new ArgumentOutOfRangeException();
}
}
}
sealed class ItaniumCpuArch : CpuArch {
public override uint GetStubAlignment(StubType stubType) {
switch (stubType) {
case StubType.Export:
case StubType.EntryPoint:
return 16;
default:
throw new ArgumentOutOfRangeException();
}
}
public override uint GetStubSize(StubType stubType) {
switch (stubType) {
case StubType.Export:
case StubType.EntryPoint:
return 0x30;
default:
throw new ArgumentOutOfRangeException();
}
}
public override uint GetStubCodeOffset(StubType stubType) {
switch (stubType) {
case StubType.Export:
case StubType.EntryPoint:
return 0x20;
default:
throw new ArgumentOutOfRangeException();
}
}
protected override bool TryGetExportedRvaFromStubCore(ref DataReader reader, IPEImage peImage, out uint funcRva) {
funcRva = 0;
// From ExportStubIA64Template in coreclr/src/ilasm/writer.cpp
//
// ld8 r9 = [gp] ;;
// ld8 r10 = [r9],8
// nop.i ;;
// ld8 gp = [r9]
// mov b6 = r10
// br.cond.sptk.few b6
//
// 0x0B, 0x48, 0x00, 0x02, 0x18, 0x10, 0xA0, 0x40,
// 0x24, 0x30, 0x28, 0x00, 0x00, 0x00, 0x04, 0x00,
// 0x10, 0x08, 0x00, 0x12, 0x18, 0x10, 0x60, 0x50,
// 0x04, 0x80, 0x03, 0x00, 0x60, 0x00, 0x80, 0x00,
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,//address of the template
// 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 //address of VTFixup slot
ulong addrTemplate = reader.ReadUInt64();
ulong absAddr = reader.ReadUInt64();
reader.Position = (uint)peImage.ToFileOffset((RVA)(addrTemplate - peImage.ImageNTHeaders.OptionalHeader.ImageBase));
if (reader.ReadUInt64() != 0x40A010180200480BUL)
return false;
if (reader.ReadUInt64() != 0x0004000000283024UL)
return false;
if (reader.ReadUInt64() != 0x5060101812000810UL)
return false;
if (reader.ReadUInt64() != 0x0080006000038004UL)
return false;
ulong rva = absAddr - peImage.ImageNTHeaders.OptionalHeader.ImageBase;
if (rva > uint.MaxValue)
return false;
funcRva = (uint)rva;
return true;
}
public override void WriteStubRelocs(StubType stubType, RelocDirectory relocDirectory, IChunk chunk, uint stubOffset) {
switch (stubType) {
case StubType.Export:
case StubType.EntryPoint:
relocDirectory.Add(chunk, stubOffset + 0x20);
relocDirectory.Add(chunk, stubOffset + 0x28);
break;
default:
throw new ArgumentOutOfRangeException();
}
}
public override void WriteStub(StubType stubType, DataWriter writer, ulong imageBase, uint stubRva, uint managedFuncRva) {
switch (stubType) {
case StubType.Export:
case StubType.EntryPoint:
writer.WriteUInt64(0x40A010180200480BUL);
writer.WriteUInt64(0x0004000000283024UL);
writer.WriteUInt64(0x5060101812000810UL);
writer.WriteUInt64(0x0080006000038004UL);
writer.WriteUInt64(imageBase + stubRva);
writer.WriteUInt64(imageBase + managedFuncRva);
break;
default:
throw new ArgumentOutOfRangeException();
}
}
}
sealed class ArmCpuArch : CpuArch {
public override uint GetStubAlignment(StubType stubType) {
switch (stubType) {
case StubType.Export:
case StubType.EntryPoint:
return 4;
default:
throw new ArgumentOutOfRangeException();
}
}
public override uint GetStubSize(StubType stubType) {
switch (stubType) {
case StubType.Export:
case StubType.EntryPoint:
return 8;
default:
throw new ArgumentOutOfRangeException();
}
}
public override uint GetStubCodeOffset(StubType stubType) {
switch (stubType) {
case StubType.Export:
case StubType.EntryPoint:
return 0;
default:
throw new ArgumentOutOfRangeException();
}
}
protected override bool TryGetExportedRvaFromStubCore(ref DataReader reader, IPEImage peImage, out uint funcRva) {
funcRva = 0;
// DFF800F0 ldr.w pc,[pc]
// xxxxxxxx
if (reader.ReadUInt32() != 0xF000F8DF)
return false;
funcRva = reader.ReadUInt32() - (uint)peImage.ImageNTHeaders.OptionalHeader.ImageBase;
return true;
}
public override void WriteStubRelocs(StubType stubType, RelocDirectory relocDirectory, IChunk chunk, uint stubOffset) {
switch (stubType) {
case StubType.Export:
case StubType.EntryPoint:
relocDirectory.Add(chunk, stubOffset + 4);
break;
default:
throw new ArgumentOutOfRangeException();
}
}
public override void WriteStub(StubType stubType, DataWriter writer, ulong imageBase, uint stubRva, uint managedFuncRva) {
switch (stubType) {
case StubType.Export:
case StubType.EntryPoint:
writer.WriteUInt32(0xF000F8DF);
writer.WriteUInt32((uint)imageBase + managedFuncRva);
break;
default:
throw new ArgumentOutOfRangeException();
}
}
}
}

View File

@ -1,462 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System;
using System.Collections.Generic;
namespace dnlib.DotNet {
/// <summary>
/// A custom attribute
/// </summary>
public sealed class CustomAttribute : ICustomAttribute {
ICustomAttributeType ctor;
byte[] rawData;
readonly IList<CAArgument> arguments;
readonly IList<CANamedArgument> namedArguments;
uint caBlobOffset;
/// <summary>
/// Gets/sets the custom attribute constructor
/// </summary>
public ICustomAttributeType Constructor {
get => ctor;
set => ctor = value;
}
/// <summary>
/// Gets the attribute type
/// </summary>
public ITypeDefOrRef AttributeType => ctor?.DeclaringType;
/// <summary>
/// Gets the full name of the attribute type
/// </summary>
public string TypeFullName {
get {
if (ctor is MemberRef mrCtor)
return mrCtor.GetDeclaringTypeFullName() ?? string.Empty;
if (ctor is MethodDef mdCtor) {
var declType = mdCtor.DeclaringType;
if (declType is not null)
return declType.FullName;
}
return string.Empty;
}
}
/// <summary>
/// Gets the name of the attribute type
/// </summary>
internal string TypeName {
get {
if (ctor is MemberRef mrCtor)
return mrCtor.GetDeclaringTypeName() ?? string.Empty;
if (ctor is MethodDef mdCtor) {
var declType = mdCtor.DeclaringType;
if (declType is not null)
return declType.Name;
}
return string.Empty;
}
}
/// <summary>
/// <c>true</c> if the raw custom attribute blob hasn't been parsed
/// </summary>
public bool IsRawBlob => rawData is not null;
/// <summary>
/// Gets the raw custom attribute blob or <c>null</c> if the CA was successfully parsed.
/// </summary>
public byte[] RawData => rawData;
/// <summary>
/// Gets all constructor arguments
/// </summary>
public IList<CAArgument> ConstructorArguments => arguments;
/// <summary>
/// <c>true</c> if <see cref="ConstructorArguments"/> is not empty
/// </summary>
public bool HasConstructorArguments => arguments.Count > 0;
/// <summary>
/// Gets all named arguments (field and property values)
/// </summary>
public IList<CANamedArgument> NamedArguments => namedArguments;
/// <summary>
/// <c>true</c> if <see cref="NamedArguments"/> is not empty
/// </summary>
public bool HasNamedArguments => namedArguments.Count > 0;
/// <summary>
/// Gets all <see cref="CANamedArgument"/>s that are field arguments
/// </summary>
public IEnumerable<CANamedArgument> Fields {
get {
var namedArguments = this.namedArguments;
int count = namedArguments.Count;
for (int i = 0; i < count; i++) {
var namedArg = namedArguments[i];
if (namedArg.IsField)
yield return namedArg;
}
}
}
/// <summary>
/// Gets all <see cref="CANamedArgument"/>s that are property arguments
/// </summary>
public IEnumerable<CANamedArgument> Properties {
get {
var namedArguments = this.namedArguments;
int count = namedArguments.Count;
for (int i = 0; i < count; i++) {
var namedArg = namedArguments[i];
if (namedArg.IsProperty)
yield return namedArg;
}
}
}
/// <summary>
/// Gets the #Blob offset or 0 if unknown
/// </summary>
public uint BlobOffset => caBlobOffset;
/// <summary>
/// Constructor
/// </summary>
/// <param name="ctor">Custom attribute constructor</param>
/// <param name="rawData">Raw custom attribute blob</param>
public CustomAttribute(ICustomAttributeType ctor, byte[] rawData)
: this(ctor, null, null, 0) => this.rawData = rawData;
/// <summary>
/// Constructor
/// </summary>
/// <param name="ctor">Custom attribute constructor</param>
public CustomAttribute(ICustomAttributeType ctor)
: this(ctor, null, null, 0) {
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="ctor">Custom attribute constructor</param>
/// <param name="arguments">Constructor arguments or <c>null</c> if none</param>
public CustomAttribute(ICustomAttributeType ctor, IEnumerable<CAArgument> arguments)
: this(ctor, arguments, null) {
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="ctor">Custom attribute constructor</param>
/// <param name="namedArguments">Named arguments or <c>null</c> if none</param>
public CustomAttribute(ICustomAttributeType ctor, IEnumerable<CANamedArgument> namedArguments)
: this(ctor, null, namedArguments) {
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="ctor">Custom attribute constructor</param>
/// <param name="arguments">Constructor arguments or <c>null</c> if none</param>
/// <param name="namedArguments">Named arguments or <c>null</c> if none</param>
public CustomAttribute(ICustomAttributeType ctor, IEnumerable<CAArgument> arguments, IEnumerable<CANamedArgument> namedArguments)
: this(ctor, arguments, namedArguments, 0) {
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="ctor">Custom attribute constructor</param>
/// <param name="arguments">Constructor arguments or <c>null</c> if none</param>
/// <param name="namedArguments">Named arguments or <c>null</c> if none</param>
/// <param name="caBlobOffset">Original custom attribute #Blob offset or 0</param>
public CustomAttribute(ICustomAttributeType ctor, IEnumerable<CAArgument> arguments, IEnumerable<CANamedArgument> namedArguments, uint caBlobOffset) {
this.ctor = ctor;
this.arguments = arguments is null ? new List<CAArgument>() : new List<CAArgument>(arguments);
this.namedArguments = namedArguments is null ? new List<CANamedArgument>() : new List<CANamedArgument>(namedArguments);
this.caBlobOffset = caBlobOffset;
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="ctor">Custom attribute constructor</param>
/// <param name="arguments">Constructor arguments. The list is now owned by this instance.</param>
/// <param name="namedArguments">Named arguments. The list is now owned by this instance.</param>
/// <param name="caBlobOffset">Original custom attribute #Blob offset or 0</param>
internal CustomAttribute(ICustomAttributeType ctor, List<CAArgument> arguments, List<CANamedArgument> namedArguments, uint caBlobOffset) {
this.ctor = ctor;
this.arguments = arguments ?? new List<CAArgument>();
this.namedArguments = namedArguments ?? new List<CANamedArgument>();
this.caBlobOffset = caBlobOffset;
}
/// <summary>
/// Gets the field named <paramref name="name"/>
/// </summary>
/// <param name="name">Name of field</param>
/// <returns>A <see cref="CANamedArgument"/> instance or <c>null</c> if not found</returns>
public CANamedArgument GetField(string name) => GetNamedArgument(name, true);
/// <summary>
/// Gets the field named <paramref name="name"/>
/// </summary>
/// <param name="name">Name of field</param>
/// <returns>A <see cref="CANamedArgument"/> instance or <c>null</c> if not found</returns>
public CANamedArgument GetField(UTF8String name) => GetNamedArgument(name, true);
/// <summary>
/// Gets the property named <paramref name="name"/>
/// </summary>
/// <param name="name">Name of property</param>
/// <returns>A <see cref="CANamedArgument"/> instance or <c>null</c> if not found</returns>
public CANamedArgument GetProperty(string name) => GetNamedArgument(name, false);
/// <summary>
/// Gets the property named <paramref name="name"/>
/// </summary>
/// <param name="name">Name of property</param>
/// <returns>A <see cref="CANamedArgument"/> instance or <c>null</c> if not found</returns>
public CANamedArgument GetProperty(UTF8String name) => GetNamedArgument(name, false);
/// <summary>
/// Gets the property/field named <paramref name="name"/>
/// </summary>
/// <param name="name">Name of property/field</param>
/// <param name="isField"><c>true</c> if it's a field, <c>false</c> if it's a property</param>
/// <returns>A <see cref="CANamedArgument"/> instance or <c>null</c> if not found</returns>
public CANamedArgument GetNamedArgument(string name, bool isField) {
var namedArguments = this.namedArguments;
int count = namedArguments.Count;
for (int i = 0; i < count; i++) {
var namedArg = namedArguments[i];
if (namedArg.IsField == isField && UTF8String.ToSystemStringOrEmpty(namedArg.Name) == name)
return namedArg;
}
return null;
}
/// <summary>
/// Gets the property/field named <paramref name="name"/>
/// </summary>
/// <param name="name">Name of property/field</param>
/// <param name="isField"><c>true</c> if it's a field, <c>false</c> if it's a property</param>
/// <returns>A <see cref="CANamedArgument"/> instance or <c>null</c> if not found</returns>
public CANamedArgument GetNamedArgument(UTF8String name, bool isField) {
var namedArguments = this.namedArguments;
int count = namedArguments.Count;
for (int i = 0; i < count; i++) {
var namedArg = namedArguments[i];
if (namedArg.IsField == isField && UTF8String.Equals(namedArg.Name, name))
return namedArg;
}
return null;
}
/// <inheritdoc/>
public override string ToString() => TypeFullName;
}
/// <summary>
/// A custom attribute constructor argument
/// </summary>
public struct CAArgument : ICloneable {
TypeSig type;
object value;
/// <summary>
/// Gets/sets the argument type
/// </summary>
public TypeSig Type {
readonly get => type;
set => type = value;
}
/// <summary>
/// Gets/sets the argument value
/// </summary>
public object Value {
readonly get => value;
set => this.value = value;
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="type">Argument type</param>
public CAArgument(TypeSig type) {
this.type = type;
value = null;
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="type">Argument type</param>
/// <param name="value">Argument value</param>
public CAArgument(TypeSig type, object value) {
this.type = type;
this.value = value;
}
readonly object ICloneable.Clone() => Clone();
/// <summary>
/// Clones this instance and any <see cref="CAArgument"/>s and <see cref="CANamedArgument"/>s
/// referenced from this instance.
/// </summary>
/// <returns></returns>
public readonly CAArgument Clone() {
var value = this.value;
if (value is CAArgument)
value = ((CAArgument)value).Clone();
else if (value is IList<CAArgument> args) {
var newArgs = new List<CAArgument>(args.Count);
int count = args.Count;
for (int i = 0; i < count; i++) {
var arg = args[i];
newArgs.Add(arg.Clone());
}
value = newArgs;
}
return new CAArgument(type, value);
}
/// <inheritdoc/>
public override readonly string ToString() => $"{value ?? "null"} ({type})";
}
/// <summary>
/// A custom attribute field/property argument
/// </summary>
public sealed class CANamedArgument : ICloneable {
bool isField;
TypeSig type;
UTF8String name;
CAArgument argument;
/// <summary>
/// <c>true</c> if it's a field
/// </summary>
public bool IsField {
get => isField;
set => isField = value;
}
/// <summary>
/// <c>true</c> if it's a property
/// </summary>
public bool IsProperty {
get => !isField;
set => isField = !value;
}
/// <summary>
/// Gets/sets the field/property type
/// </summary>
public TypeSig Type {
get => type;
set => type = value;
}
/// <summary>
/// Gets/sets the property/field name
/// </summary>
public UTF8String Name {
get => name;
set => name = value;
}
/// <summary>
/// Gets/sets the argument
/// </summary>
public CAArgument Argument {
get => argument;
set => argument = value;
}
/// <summary>
/// Gets/sets the argument type
/// </summary>
public TypeSig ArgumentType {
get => argument.Type;
set => argument.Type = value;
}
/// <summary>
/// Gets/sets the argument value
/// </summary>
public object Value {
get => argument.Value;
set => argument.Value = value;
}
/// <summary>
/// Default constructor
/// </summary>
public CANamedArgument() {
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="isField"><c>true</c> if field, <c>false</c> if property</param>
public CANamedArgument(bool isField) => this.isField = isField;
/// <summary>
/// Constructor
/// </summary>
/// <param name="isField"><c>true</c> if field, <c>false</c> if property</param>
/// <param name="type">Field/property type</param>
public CANamedArgument(bool isField, TypeSig type) {
this.isField = isField;
this.type = type;
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="isField"><c>true</c> if field, <c>false</c> if property</param>
/// <param name="type">Field/property type</param>
/// <param name="name">Name of field/property</param>
public CANamedArgument(bool isField, TypeSig type, UTF8String name) {
this.isField = isField;
this.type = type;
this.name = name;
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="isField"><c>true</c> if field, <c>false</c> if property</param>
/// <param name="type">Field/property type</param>
/// <param name="name">Name of field/property</param>
/// <param name="argument">Field/property argument</param>
public CANamedArgument(bool isField, TypeSig type, UTF8String name, CAArgument argument) {
this.isField = isField;
this.type = type;
this.name = name;
this.argument = argument;
}
object ICloneable.Clone() => Clone();
/// <summary>
/// Clones this instance and any <see cref="CAArgument"/>s referenced from this instance.
/// </summary>
/// <returns></returns>
public CANamedArgument Clone() => new CANamedArgument(isField, type, name, argument.Clone());
/// <inheritdoc/>
public override string ToString() => $"({(isField ? "field" : "property")}) {type} {name} = {Value ?? "null"} ({ArgumentType})";
}
}

View File

@ -1,125 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System.Collections.Generic;
using dnlib.Utils;
using System;
namespace dnlib.DotNet {
/// <summary>
/// Stores <see cref="CustomAttribute"/>s
/// </summary>
public class CustomAttributeCollection : LazyList<CustomAttribute, object> {
/// <summary>
/// Default constructor
/// </summary>
public CustomAttributeCollection() {
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="length">Initial length of the list</param>
/// <param name="context">Context passed to <paramref name="readOriginalValue"/></param>
/// <param name="readOriginalValue">Delegate instance that returns original values</param>
public CustomAttributeCollection(int length, object context, Func<object, int, CustomAttribute> readOriginalValue)
: base(length, context, readOriginalValue) {
}
/// <summary>
/// Checks whether a custom attribute is present
/// </summary>
/// <param name="fullName">Full name of custom attribute type</param>
/// <returns><c>true</c> if the custom attribute type is present, <c>false</c> otherwise</returns>
public bool IsDefined(string fullName) => Find(fullName) is not null;
/// <summary>
/// Removes all custom attributes of a certain type
/// </summary>
/// <param name="fullName">Full name of custom attribute type that should be removed</param>
public void RemoveAll(string fullName) {
if (fullName == null)
return;
for (int i = Count - 1; i >= 0; i--) {
var ca = this[i];
if (ca is not null && fullName.EndsWith(ca.TypeName, StringComparison.Ordinal) && ca.TypeFullName == fullName)
RemoveAt(i);
}
}
/// <summary>
/// Finds a custom attribute
/// </summary>
/// <param name="fullName">Full name of custom attribute type</param>
/// <returns>A <see cref="CustomAttribute"/> or <c>null</c> if it wasn't found</returns>
public CustomAttribute Find(string fullName) {
if (fullName == null)
return null;
foreach (var ca in this) {
if (ca is not null && fullName.EndsWith(ca.TypeName, StringComparison.Ordinal) && ca.TypeFullName == fullName)
return ca;
}
return null;
}
/// <summary>
/// Finds all custom attributes of a certain type
/// </summary>
/// <param name="fullName">Full name of custom attribute type</param>
/// <returns>All <see cref="CustomAttribute"/>s of the requested type</returns>
public IEnumerable<CustomAttribute> FindAll(string fullName) {
if (fullName == null)
yield break;
foreach (var ca in this) {
if (ca is not null && fullName.EndsWith(ca.TypeName, StringComparison.Ordinal) && ca.TypeFullName == fullName)
yield return ca;
}
}
/// <summary>
/// Finds a custom attribute
/// </summary>
/// <param name="attrType">Custom attribute type</param>
/// <returns>The first <see cref="CustomAttribute"/> found or <c>null</c> if none found</returns>
public CustomAttribute Find(IType attrType) => Find(attrType, 0);
/// <summary>
/// Finds a custom attribute
/// </summary>
/// <param name="attrType">Custom attribute type</param>
/// <param name="options">Attribute type comparison flags</param>
/// <returns>The first <see cref="CustomAttribute"/> found or <c>null</c> if none found</returns>
public CustomAttribute Find(IType attrType, SigComparerOptions options) {
var comparer = new SigComparer(options);
foreach (var ca in this) {
if (comparer.Equals(ca.AttributeType, attrType))
return ca;
}
return null;
}
/// <summary>
/// Finds all custom attributes of a certain type
/// </summary>
/// <param name="attrType">Custom attribute type</param>
/// <returns>All <see cref="CustomAttribute"/>s of the requested type</returns>
public IEnumerable<CustomAttribute> FindAll(IType attrType) => FindAll(attrType, 0);
/// <summary>
/// Finds all custom attributes of a certain type
/// </summary>
/// <param name="attrType">Custom attribute type</param>
/// <param name="options">Attribute type comparison flags</param>
/// <returns>All <see cref="CustomAttribute"/>s of the requested type</returns>
public IEnumerable<CustomAttribute> FindAll(IType attrType, SigComparerOptions options) {
var comparer = new SigComparer(options);
foreach (var ca in this) {
if (comparer.Equals(ca.AttributeType, attrType))
yield return ca;
}
}
}
}

View File

@ -1,599 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization;
using dnlib.IO;
namespace dnlib.DotNet {
/// <summary>
/// Searches for a type according to custom attribute search rules: first try the
/// current assembly, and if that fails, try mscorlib
/// </summary>
sealed class CAAssemblyRefFinder : IAssemblyRefFinder {
readonly ModuleDef module;
/// <summary>
/// Constructor
/// </summary>
/// <param name="module">The module to search first</param>
public CAAssemblyRefFinder(ModuleDef module) => this.module = module;
/// <inheritdoc/>
public AssemblyRef FindAssemblyRef(TypeRef nonNestedTypeRef) {
var modAsm = module.Assembly;
if (modAsm is not null) {
var type = modAsm.Find(nonNestedTypeRef);
// If the user added a new type with the same name as a corelib type, don't return it,
// only return the type if it is this module's original type.
if (type is TypeDefMD td && td.ReaderModule == module)
return module.UpdateRowId(new AssemblyRefUser(modAsm));
}
else if (module.Find(nonNestedTypeRef) is not null)
return AssemblyRef.CurrentAssembly;
var corLibAsm = module.Context.AssemblyResolver.Resolve(module.CorLibTypes.AssemblyRef, module);
if (corLibAsm is not null) {
var type = corLibAsm.Find(nonNestedTypeRef);
if (type is not null)
return module.CorLibTypes.AssemblyRef;
}
if (nonNestedTypeRef.Namespace == "System" || nonNestedTypeRef.Namespace.StartsWith("System."))
return module.CorLibTypes.AssemblyRef;
if (modAsm is not null)
return module.UpdateRowId(new AssemblyRefUser(modAsm));
return AssemblyRef.CurrentAssembly;
}
}
/// <summary>
/// Thrown by CustomAttributeReader when it fails to parse a custom attribute blob
/// </summary>
[Serializable]
public class CABlobParserException : Exception {
/// <summary>
/// Default constructor
/// </summary>
public CABlobParserException() {
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="message">Error message</param>
public CABlobParserException(string message)
: base(message) {
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="message">Error message</param>
/// <param name="innerException">Other exception</param>
public CABlobParserException(string message, Exception innerException)
: base(message, innerException) {
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="info"></param>
/// <param name="context"></param>
protected CABlobParserException(SerializationInfo info, StreamingContext context)
: base(info, context) {
}
}
/// <summary>
/// Reads custom attributes from the #Blob stream
/// </summary>
public struct CustomAttributeReader {
readonly ModuleDef module;
DataReader reader;
readonly uint caBlobOffset;
readonly GenericParamContext gpContext;
GenericArguments genericArguments;
RecursionCounter recursionCounter;
bool verifyReadAllBytes;
/// <summary>
/// Reads a custom attribute
/// </summary>
/// <param name="readerModule">Reader module</param>
/// <param name="ctor">Custom attribute constructor</param>
/// <param name="offset">Offset of custom attribute in the #Blob stream</param>
/// <returns>A new <see cref="CustomAttribute"/> instance</returns>
public static CustomAttribute Read(ModuleDefMD readerModule, ICustomAttributeType ctor, uint offset) => Read(readerModule, ctor, offset, new GenericParamContext());
/// <summary>
/// Reads a custom attribute
/// </summary>
/// <param name="readerModule">Reader module</param>
/// <param name="ctor">Custom attribute constructor</param>
/// <param name="offset">Offset of custom attribute in the #Blob stream</param>
/// <param name="gpContext">Generic parameter context</param>
/// <returns>A new <see cref="CustomAttribute"/> instance</returns>
public static CustomAttribute Read(ModuleDefMD readerModule, ICustomAttributeType ctor, uint offset, GenericParamContext gpContext) {
var caReader = new CustomAttributeReader(readerModule, offset, gpContext);
try {
if (ctor is null)
return caReader.CreateRaw(ctor);
return caReader.Read(ctor);
}
catch (CABlobParserException) {
return caReader.CreateRaw(ctor);
}
catch (IOException) {
return caReader.CreateRaw(ctor);
}
}
CustomAttribute CreateRaw(ICustomAttributeType ctor) => new CustomAttribute(ctor, GetRawBlob());
/// <summary>
/// Reads a custom attribute
/// </summary>
/// <param name="module">Owner module</param>
/// <param name="caBlob">CA blob</param>
/// <param name="ctor">Custom attribute constructor</param>
/// <returns>A new <see cref="CustomAttribute"/> instance</returns>
public static CustomAttribute Read(ModuleDef module, byte[] caBlob, ICustomAttributeType ctor) =>
Read(module, ByteArrayDataReaderFactory.CreateReader(caBlob), ctor, new GenericParamContext());
/// <summary>
/// Reads a custom attribute
/// </summary>
/// <param name="module">Owner module</param>
/// <param name="reader">A reader positioned at the the first byte of the CA blob</param>
/// <param name="ctor">Custom attribute constructor</param>
/// <returns>A new <see cref="CustomAttribute"/> instance</returns>
public static CustomAttribute Read(ModuleDef module, DataReader reader, ICustomAttributeType ctor) =>
Read(module, ref reader, ctor, new GenericParamContext());
/// <summary>
/// Reads a custom attribute
/// </summary>
/// <param name="module">Owner module</param>
/// <param name="caBlob">CA blob</param>
/// <param name="ctor">Custom attribute constructor</param>
/// <param name="gpContext">Generic parameter context</param>
/// <returns>A new <see cref="CustomAttribute"/> instance</returns>
public static CustomAttribute Read(ModuleDef module, byte[] caBlob, ICustomAttributeType ctor, GenericParamContext gpContext) =>
Read(module, ByteArrayDataReaderFactory.CreateReader(caBlob), ctor, gpContext);
/// <summary>
/// Reads a custom attribute
/// </summary>
/// <param name="module">Owner module</param>
/// <param name="reader">A stream positioned at the the first byte of the CA blob</param>
/// <param name="ctor">Custom attribute constructor</param>
/// <param name="gpContext">Generic parameter context</param>
/// <returns>A new <see cref="CustomAttribute"/> instance</returns>
public static CustomAttribute Read(ModuleDef module, DataReader reader, ICustomAttributeType ctor, GenericParamContext gpContext) =>
Read(module, ref reader, ctor, gpContext);
/// <summary>
/// Reads a custom attribute
/// </summary>
/// <param name="module">Owner module</param>
/// <param name="reader">A stream positioned at the the first byte of the CA blob</param>
/// <param name="ctor">Custom attribute constructor</param>
/// <param name="gpContext">Generic parameter context</param>
/// <returns>A new <see cref="CustomAttribute"/> instance</returns>
static CustomAttribute Read(ModuleDef module, ref DataReader reader, ICustomAttributeType ctor, GenericParamContext gpContext) {
var caReader = new CustomAttributeReader(module, ref reader, gpContext);
CustomAttribute ca;
try {
if (ctor is null)
ca = caReader.CreateRaw(ctor);
else
ca = caReader.Read(ctor);
}
catch (CABlobParserException) {
ca = caReader.CreateRaw(ctor);
}
catch (IOException) {
ca = caReader.CreateRaw(ctor);
}
return ca;
}
/// <summary>
/// Reads custom attribute named arguments
/// </summary>
/// <param name="module">Owner module</param>
/// <param name="reader">A reader positioned at the the first byte of the CA blob</param>
/// <param name="numNamedArgs">Number of named arguments to read from <paramref name="reader"/></param>
/// <param name="gpContext">Generic parameter context</param>
/// <returns>A list of <see cref="CANamedArgument"/>s or <c>null</c> if some error
/// occurred.</returns>
internal static List<CANamedArgument> ReadNamedArguments(ModuleDef module, ref DataReader reader, int numNamedArgs, GenericParamContext gpContext) {
try {
var caReader = new CustomAttributeReader(module, ref reader, gpContext);
var namedArgs = caReader.ReadNamedArguments(numNamedArgs);
reader.CurrentOffset = caReader.reader.CurrentOffset;
return namedArgs;
}
catch (CABlobParserException) {
return null;
}
catch (IOException) {
return null;
}
}
CustomAttributeReader(ModuleDefMD readerModule, uint offset, GenericParamContext gpContext) {
module = readerModule;
caBlobOffset = offset;
reader = readerModule.BlobStream.CreateReader(offset);
genericArguments = null;
recursionCounter = new RecursionCounter();
verifyReadAllBytes = false;
this.gpContext = gpContext;
}
CustomAttributeReader(ModuleDef module, ref DataReader reader, GenericParamContext gpContext) {
this.module = module;
caBlobOffset = 0;
this.reader = reader;
genericArguments = null;
recursionCounter = new RecursionCounter();
verifyReadAllBytes = false;
this.gpContext = gpContext;
}
byte[] GetRawBlob() => reader.ToArray();
CustomAttribute Read(ICustomAttributeType ctor) {
var methodSig = ctor?.MethodSig;
if (methodSig is null)
throw new CABlobParserException("ctor is null or not a method");
if (ctor is MemberRef mrCtor && mrCtor.Class is TypeSpec owner && owner.TypeSig is GenericInstSig gis) {
genericArguments = new GenericArguments();
genericArguments.PushTypeArgs(gis.GenericArguments);
}
var methodSigParams = methodSig.Params;
bool isEmpty = methodSigParams.Count == 0 && reader.Position == reader.Length;
if (!isEmpty && reader.ReadUInt16() != 1)
throw new CABlobParserException("Invalid CA blob prolog");
var ctorArgs = new List<CAArgument>(methodSigParams.Count);
int count = methodSigParams.Count;
for (int i = 0; i < count; i++)
ctorArgs.Add(ReadFixedArg(FixTypeSig(methodSigParams[i])));
// Some tools don't write the next ushort if there are no named arguments.
int numNamedArgs = reader.Position == reader.Length ? 0 : reader.ReadUInt16();
var namedArgs = ReadNamedArguments(numNamedArgs);
// verifyReadAllBytes will be set when we guess the underlying type of an enum.
// To make sure we guessed right, verify that we read all bytes.
if (verifyReadAllBytes && reader.Position != reader.Length)
throw new CABlobParserException("Not all CA blob bytes were read");
return new CustomAttribute(ctor, ctorArgs, namedArgs, caBlobOffset);
}
List<CANamedArgument> ReadNamedArguments(int numNamedArgs) {
if ((uint)numNamedArgs >= 0x4000_0000 || numNamedArgs * 4 > reader.BytesLeft)
return null;
var namedArgs = new List<CANamedArgument>(numNamedArgs);
for (int i = 0; i < numNamedArgs; i++) {
if (reader.Position == reader.Length)
break;
namedArgs.Add(ReadNamedArgument());
}
return namedArgs;
}
TypeSig FixTypeSig(TypeSig type) => SubstituteGenericParameter(type.RemoveModifiers()).RemoveModifiers();
TypeSig SubstituteGenericParameter(TypeSig type) {
if (genericArguments is null)
return type;
return genericArguments.Resolve(type);
}
CAArgument ReadFixedArg(TypeSig argType) {
if (!recursionCounter.Increment())
throw new CABlobParserException("Too much recursion");
if (argType is null)
throw new CABlobParserException("null argType");
CAArgument result;
if (argType is SZArraySig arrayType)
result = ReadArrayArgument(arrayType);
else
result = ReadElem(argType);
recursionCounter.Decrement();
return result;
}
CAArgument ReadElem(TypeSig argType) {
if (argType is null)
throw new CABlobParserException("null argType");
var value = ReadValue((SerializationType)argType.ElementType, argType, out var realArgType);
if (realArgType is null)
throw new CABlobParserException("Invalid arg type");
// One example when this is true is when prop/field type is object and
// value type is string[]
if (value is CAArgument)
return (CAArgument)value;
return new CAArgument(realArgType, value);
}
object ReadValue(SerializationType etype, TypeSig argType, out TypeSig realArgType) {
if (!recursionCounter.Increment())
throw new CABlobParserException("Too much recursion");
object result;
switch (etype) {
case SerializationType.Boolean:
realArgType = module.CorLibTypes.Boolean;
result = reader.ReadByte() != 0;
break;
case SerializationType.Char:
realArgType = module.CorLibTypes.Char;
result = reader.ReadChar();
break;
case SerializationType.I1:
realArgType = module.CorLibTypes.SByte;
result = reader.ReadSByte();
break;
case SerializationType.U1:
realArgType = module.CorLibTypes.Byte;
result = reader.ReadByte();
break;
case SerializationType.I2:
realArgType = module.CorLibTypes.Int16;
result = reader.ReadInt16();
break;
case SerializationType.U2:
realArgType = module.CorLibTypes.UInt16;
result = reader.ReadUInt16();
break;
case SerializationType.I4:
realArgType = module.CorLibTypes.Int32;
result = reader.ReadInt32();
break;
case SerializationType.U4:
realArgType = module.CorLibTypes.UInt32;
result = reader.ReadUInt32();
break;
case SerializationType.I8:
realArgType = module.CorLibTypes.Int64;
result = reader.ReadInt64();
break;
case SerializationType.U8:
realArgType = module.CorLibTypes.UInt64;
result = reader.ReadUInt64();
break;
case SerializationType.R4:
realArgType = module.CorLibTypes.Single;
result = reader.ReadSingle();
break;
case SerializationType.R8:
realArgType = module.CorLibTypes.Double;
result = reader.ReadDouble();
break;
case SerializationType.String:
realArgType = module.CorLibTypes.String;
result = ReadUTF8String();
break;
// It's ET.ValueType if it's eg. a ctor enum arg type
case (SerializationType)ElementType.ValueType:
if (argType is null)
throw new CABlobParserException("Invalid element type");
realArgType = argType;
result = ReadEnumValue(GetEnumUnderlyingType(argType));
break;
// It's ET.Object if it's a ctor object arg type
case (SerializationType)ElementType.Object:
case SerializationType.TaggedObject:
realArgType = ReadFieldOrPropType();
var arraySig = realArgType as SZArraySig;
if (arraySig is not null)
result = ReadArrayArgument(arraySig);
else
result = ReadValue((SerializationType)realArgType.ElementType, realArgType, out var tmpType);
break;
// It's ET.Class if it's eg. a ctor System.Type arg type
case (SerializationType)ElementType.Class:
var tdr = argType as TypeDefOrRefSig;
if (tdr is not null && tdr.DefinitionAssembly.IsCorLib() && tdr.Namespace == "System") {
if (tdr.TypeName == "Type") {
result = ReadValue(SerializationType.Type, tdr, out realArgType);
break;
}
if (tdr.TypeName == "String") {
result = ReadValue(SerializationType.String, tdr, out realArgType);
break;
}
if (tdr.TypeName == "Object") {
result = ReadValue(SerializationType.TaggedObject, tdr, out realArgType);
break;
}
}
// Assume it's an enum that couldn't be resolved
realArgType = argType;
result = ReadEnumValue(null);
break;
case SerializationType.Type:
realArgType = argType;
result = ReadType(true);
break;
case SerializationType.Enum:
realArgType = ReadType(false);
result = ReadEnumValue(GetEnumUnderlyingType(realArgType));
break;
default:
throw new CABlobParserException("Invalid element type");
}
recursionCounter.Decrement();
return result;
}
object ReadEnumValue(TypeSig underlyingType) {
if (underlyingType is not null) {
if (underlyingType.ElementType < ElementType.Boolean || underlyingType.ElementType > ElementType.U8)
throw new CABlobParserException("Invalid enum underlying type");
return ReadValue((SerializationType)underlyingType.ElementType, underlyingType, out var realArgType);
}
// We couldn't resolve the type ref. It should be an enum, but we don't know for sure.
// Most enums use Int32 as the underlying type. Assume that's true also in this case.
// Since we're guessing, verify that we've read all CA blob bytes. If we haven't, then
// we probably guessed wrong.
verifyReadAllBytes = true;
return reader.ReadInt32();
}
TypeSig ReadType(bool canReturnNull) {
var name = ReadUTF8String();
if (canReturnNull && name is null)
return null;
var asmRefFinder = new CAAssemblyRefFinder(module);
var type = TypeNameParser.ParseAsTypeSigReflection(module, UTF8String.ToSystemStringOrEmpty(name), asmRefFinder, gpContext);
if (type is null)
throw new CABlobParserException("Could not parse type");
return type;
}
/// <summary>
/// Gets the enum's underlying type
/// </summary>
/// <param name="type">An enum type</param>
/// <returns>The underlying type or <c>null</c> if we couldn't resolve the type ref</returns>
/// <exception cref="CABlobParserException">If <paramref name="type"/> is not an enum or <c>null</c></exception>
static TypeSig GetEnumUnderlyingType(TypeSig type) {
if (type is null)
throw new CABlobParserException("null enum type");
var td = GetTypeDef(type);
if (td is null)
return null;
if (!td.IsEnum)
throw new CABlobParserException("Not an enum");
return td.GetEnumUnderlyingType().RemoveModifiers();
}
/// <summary>
/// Converts <paramref name="type"/> to a <see cref="TypeDef"/>, possibly resolving
/// a <see cref="TypeRef"/>
/// </summary>
/// <param name="type">The type</param>
/// <returns>A <see cref="TypeDef"/> or <c>null</c> if we couldn't resolve the
/// <see cref="TypeRef"/> or if <paramref name="type"/> is a type spec</returns>
static TypeDef GetTypeDef(TypeSig type) {
if (type is TypeDefOrRefSig tdr) {
var td = tdr.TypeDef;
if (td is not null)
return td;
var tr = tdr.TypeRef;
if (tr is not null)
return tr.Resolve();
}
return null;
}
CAArgument ReadArrayArgument(SZArraySig arrayType) {
if (!recursionCounter.Increment())
throw new CABlobParserException("Too much recursion");
var arg = new CAArgument(arrayType);
int arrayCount = reader.ReadInt32();
if (arrayCount == -1) { // -1 if it's null
}
else if (arrayCount < 0 || arrayCount > reader.BytesLeft)
throw new CABlobParserException("Array is too big");
else {
var array = new List<CAArgument>(arrayCount);
arg.Value = array;
for (int i = 0; i < arrayCount; i++)
array.Add(ReadFixedArg(FixTypeSig(arrayType.Next)));
}
recursionCounter.Decrement();
return arg;
}
CANamedArgument ReadNamedArgument() {
var isField = (SerializationType)reader.ReadByte() switch {
SerializationType.Property => false,
SerializationType.Field => true,
_ => throw new CABlobParserException("Named argument is not a field/property"),
};
var fieldPropType = ReadFieldOrPropType();
var name = ReadUTF8String();
var argument = ReadFixedArg(fieldPropType);
return new CANamedArgument(isField, fieldPropType, name, argument);
}
TypeSig ReadFieldOrPropType() {
if (!recursionCounter.Increment())
throw new CABlobParserException("Too much recursion");
var result = (SerializationType)reader.ReadByte() switch {
SerializationType.Boolean => module.CorLibTypes.Boolean,
SerializationType.Char => module.CorLibTypes.Char,
SerializationType.I1 => module.CorLibTypes.SByte,
SerializationType.U1 => module.CorLibTypes.Byte,
SerializationType.I2 => module.CorLibTypes.Int16,
SerializationType.U2 => module.CorLibTypes.UInt16,
SerializationType.I4 => module.CorLibTypes.Int32,
SerializationType.U4 => module.CorLibTypes.UInt32,
SerializationType.I8 => module.CorLibTypes.Int64,
SerializationType.U8 => module.CorLibTypes.UInt64,
SerializationType.R4 => module.CorLibTypes.Single,
SerializationType.R8 => module.CorLibTypes.Double,
SerializationType.String => module.CorLibTypes.String,
SerializationType.SZArray => new SZArraySig(ReadFieldOrPropType()),
SerializationType.Type => new ClassSig(module.CorLibTypes.GetTypeRef("System", "Type")),
SerializationType.TaggedObject => module.CorLibTypes.Object,
SerializationType.Enum => ReadType(false),
_ => throw new CABlobParserException("Invalid type"),
};
recursionCounter.Decrement();
return result;
}
UTF8String ReadUTF8String() {
if (reader.ReadByte() == 0xFF)
return null;
reader.Position--;
if (!reader.TryReadCompressedUInt32(out uint len))
throw new CABlobParserException("Could not read compressed UInt32");
if (len == 0)
return UTF8String.Empty;
return new UTF8String(reader.ReadBytes((int)len));
}
}
}

View File

@ -1,227 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using dnlib.DotNet.MD;
using dnlib.DotNet.Pdb;
namespace dnlib.DotNet {
/// <summary>
/// A high-level representation of a row in the DeclSecurity table
/// </summary>
[DebuggerDisplay("{Action} Count={SecurityAttributes.Count}")]
public abstract class DeclSecurity : IHasCustomAttribute, IHasCustomDebugInformation {
/// <summary>
/// The row id in its table
/// </summary>
protected uint rid;
/// <inheritdoc/>
public MDToken MDToken => new MDToken(Table.DeclSecurity, rid);
/// <inheritdoc/>
public uint Rid {
get => rid;
set => rid = value;
}
/// <inheritdoc/>
public int HasCustomAttributeTag => 8;
/// <summary>
/// From column DeclSecurity.Action
/// </summary>
public SecurityAction Action {
get => action;
set => action = value;
}
/// <summary/>
protected SecurityAction action;
/// <summary>
/// From column DeclSecurity.PermissionSet
/// </summary>
public IList<SecurityAttribute> SecurityAttributes {
get {
if (securityAttributes is null)
InitializeSecurityAttributes();
return securityAttributes;
}
}
/// <summary/>
protected IList<SecurityAttribute> securityAttributes;
/// <summary>Initializes <see cref="securityAttributes"/></summary>
protected virtual void InitializeSecurityAttributes() =>
Interlocked.CompareExchange(ref securityAttributes, new List<SecurityAttribute>(), null);
/// <summary>
/// Gets all custom attributes
/// </summary>
public CustomAttributeCollection CustomAttributes {
get {
if (customAttributes is null)
InitializeCustomAttributes();
return customAttributes;
}
}
/// <summary/>
protected CustomAttributeCollection customAttributes;
/// <summary>Initializes <see cref="customAttributes"/></summary>
protected virtual void InitializeCustomAttributes() =>
Interlocked.CompareExchange(ref customAttributes, new CustomAttributeCollection(), null);
/// <inheritdoc/>
public bool HasCustomAttributes => CustomAttributes.Count > 0;
/// <inheritdoc/>
public int HasCustomDebugInformationTag => 8;
/// <inheritdoc/>
public bool HasCustomDebugInfos => CustomDebugInfos.Count > 0;
/// <summary>
/// Gets all custom debug infos
/// </summary>
public IList<PdbCustomDebugInfo> CustomDebugInfos {
get {
if (customDebugInfos is null)
InitializeCustomDebugInfos();
return customDebugInfos;
}
}
/// <summary/>
protected IList<PdbCustomDebugInfo> customDebugInfos;
/// <summary>Initializes <see cref="customDebugInfos"/></summary>
protected virtual void InitializeCustomDebugInfos() =>
Interlocked.CompareExchange(ref customDebugInfos, new List<PdbCustomDebugInfo>(), null);
/// <summary>
/// <c>true</c> if <see cref="SecurityAttributes"/> is not empty
/// </summary>
public bool HasSecurityAttributes => SecurityAttributes.Count > 0;
/// <summary>
/// Gets the blob data or <c>null</c> if there's none
/// </summary>
/// <returns>Blob data or <c>null</c></returns>
public abstract byte[] GetBlob();
/// <summary>
/// Returns the .NET Framework 1.x XML string or null if it's not a .NET Framework 1.x format
/// </summary>
/// <returns></returns>
public string GetNet1xXmlString() => GetNet1xXmlStringInternal(SecurityAttributes);
internal static string GetNet1xXmlStringInternal(IList<SecurityAttribute> secAttrs) {
if (secAttrs is null || secAttrs.Count != 1)
return null;
var sa = secAttrs[0];
if (sa is null || sa.TypeFullName != "System.Security.Permissions.PermissionSetAttribute")
return null;
if (sa.NamedArguments.Count != 1)
return null;
var na = sa.NamedArguments[0];
if (na is null || !na.IsProperty || na.Name != "XML")
return null;
if (na.ArgumentType.GetElementType() != ElementType.String)
return null;
var arg = na.Argument;
if (arg.Type.GetElementType() != ElementType.String)
return null;
var utf8 = arg.Value as UTF8String;
if (utf8 is not null)
return utf8;
if (arg.Value is string s)
return s;
return null;
}
}
/// <summary>
/// A DeclSecurity row created by the user and not present in the original .NET file
/// </summary>
public class DeclSecurityUser : DeclSecurity {
/// <summary>
/// Default constructor
/// </summary>
public DeclSecurityUser() {
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="action">The security action</param>
/// <param name="securityAttrs">The security attributes (now owned by this)</param>
public DeclSecurityUser(SecurityAction action, IList<SecurityAttribute> securityAttrs) {
this.action = action;
securityAttributes = securityAttrs;
}
/// <inheritdoc/>
public override byte[] GetBlob() => null;
}
/// <summary>
/// Created from a row in the DeclSecurity table
/// </summary>
sealed class DeclSecurityMD : DeclSecurity, IMDTokenProviderMD {
/// <summary>The module where this instance is located</summary>
readonly ModuleDefMD readerModule;
readonly uint origRid;
readonly uint permissionSet;
/// <inheritdoc/>
public uint OrigRid => origRid;
/// <inheritdoc/>
protected override void InitializeSecurityAttributes() {
var gpContext = new GenericParamContext();
var tmp = DeclSecurityReader.Read(readerModule, permissionSet, gpContext);
Interlocked.CompareExchange(ref securityAttributes, tmp, null);
}
/// <inheritdoc/>
protected override void InitializeCustomAttributes() {
var list = readerModule.Metadata.GetCustomAttributeRidList(Table.DeclSecurity, origRid);
var tmp = new CustomAttributeCollection(list.Count, list, (list2, index) => readerModule.ReadCustomAttribute(list[index]));
Interlocked.CompareExchange(ref customAttributes, tmp, null);
}
/// <inheritdoc/>
protected override void InitializeCustomDebugInfos() {
var list = new List<PdbCustomDebugInfo>();
var gpContext = new GenericParamContext();
readerModule.InitializeCustomDebugInfos(new MDToken(MDToken.Table, origRid), gpContext, list);
Interlocked.CompareExchange(ref customDebugInfos, list, null);
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="readerModule">The module which contains this <c>DeclSecurity</c> row</param>
/// <param name="rid">Row ID</param>
/// <exception cref="ArgumentNullException">If <paramref name="readerModule"/> is <c>null</c></exception>
/// <exception cref="ArgumentException">If <paramref name="rid"/> is invalid</exception>
public DeclSecurityMD(ModuleDefMD readerModule, uint rid) {
#if DEBUG
if (readerModule is null)
throw new ArgumentNullException("readerModule");
if (readerModule.TablesStream.DeclSecurityTable.IsInvalidRID(rid))
throw new BadImageFormatException($"DeclSecurity rid {rid} does not exist");
#endif
origRid = rid;
this.rid = rid;
this.readerModule = readerModule;
bool b = readerModule.TablesStream.TryReadDeclSecurityRow(origRid, out var row);
Debug.Assert(b);
permissionSet = row.PermissionSet;
action = (SecurityAction)row.Action;
}
/// <inheritdoc/>
public override byte[] GetBlob() => readerModule.BlobStream.Read(permissionSet);
}
}

View File

@ -1,129 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System;
using System.Collections.Generic;
using dnlib.IO;
namespace dnlib.DotNet {
/// <summary>
/// Reads <c>DeclSecurity</c> blobs
/// </summary>
public struct DeclSecurityReader {
DataReader reader;
readonly ModuleDef module;
readonly GenericParamContext gpContext;
/// <summary>
/// Reads a <c>DeclSecurity</c> blob
/// </summary>
/// <param name="module">Module that will own the returned list</param>
/// <param name="sig"><c>#Blob</c> offset of <c>DeclSecurity</c> signature</param>
/// <returns>A list of <see cref="SecurityAttribute"/>s</returns>
public static IList<SecurityAttribute> Read(ModuleDefMD module, uint sig) => Read(module, module.BlobStream.CreateReader(sig), new GenericParamContext());
/// <summary>
/// Reads a <c>DeclSecurity</c> blob
/// </summary>
/// <param name="module">Module that will own the returned list</param>
/// <param name="sig"><c>#Blob</c> offset of <c>DeclSecurity</c> signature</param>
/// <param name="gpContext">Generic parameter context</param>
/// <returns>A list of <see cref="SecurityAttribute"/>s</returns>
public static IList<SecurityAttribute> Read(ModuleDefMD module, uint sig, GenericParamContext gpContext) => Read(module, module.BlobStream.CreateReader(sig), gpContext);
/// <summary>
/// Reads a <c>DeclSecurity</c> blob
/// </summary>
/// <param name="module">Module that will own the returned list</param>
/// <param name="blob"><c>DeclSecurity</c> blob</param>
/// <returns>A list of <see cref="SecurityAttribute"/>s</returns>
public static IList<SecurityAttribute> Read(ModuleDef module, byte[] blob) => Read(module, ByteArrayDataReaderFactory.CreateReader(blob), new GenericParamContext());
/// <summary>
/// Reads a <c>DeclSecurity</c> blob
/// </summary>
/// <param name="module">Module that will own the returned list</param>
/// <param name="blob"><c>DeclSecurity</c> blob</param>
/// <param name="gpContext">Generic parameter context</param>///
/// <returns>A list of <see cref="SecurityAttribute"/>s</returns>
public static IList<SecurityAttribute> Read(ModuleDef module, byte[] blob, GenericParamContext gpContext) => Read(module, ByteArrayDataReaderFactory.CreateReader(blob), gpContext);
/// <summary>
/// Reads a <c>DeclSecurity</c> blob
/// </summary>
/// <param name="module">Module that will own the returned list</param>
/// <param name="signature"><c>DeclSecurity</c> stream that will be owned by us</param>
/// <returns>A list of <see cref="SecurityAttribute"/>s</returns>
public static IList<SecurityAttribute> Read(ModuleDef module, DataReader signature) => Read(module, signature, new GenericParamContext());
/// <summary>
/// Reads a <c>DeclSecurity</c> blob
/// </summary>
/// <param name="module">Module that will own the returned list</param>
/// <param name="signature"><c>DeclSecurity</c> stream that will be owned by us</param>
/// <param name="gpContext">Generic parameter context</param>
/// <returns>A list of <see cref="SecurityAttribute"/>s</returns>
public static IList<SecurityAttribute> Read(ModuleDef module, DataReader signature, GenericParamContext gpContext) {
var reader = new DeclSecurityReader(module, signature, gpContext);
return reader.Read();
}
DeclSecurityReader(ModuleDef module, DataReader reader, GenericParamContext gpContext) {
this.reader = reader;
this.module = module;
this.gpContext = gpContext;
}
IList<SecurityAttribute> Read() {
try {
if (reader.Position >= reader.Length)
return new List<SecurityAttribute>();
if (reader.ReadByte() == '.')
return ReadBinaryFormat();
reader.Position--;
return ReadXmlFormat();
}
catch {
return new List<SecurityAttribute>();
}
}
/// <summary>
/// Reads the new (.NET Framework 2.0+) DeclSecurity blob format
/// </summary>
/// <returns></returns>
IList<SecurityAttribute> ReadBinaryFormat() {
int numAttrs = (int)reader.ReadCompressedUInt32();
var list = new List<SecurityAttribute>(numAttrs);
for (int i = 0; i < numAttrs; i++) {
var name = ReadUTF8String();
// Use CA search rules. Some tools don't write the fully qualified name.
var attrRef = TypeNameParser.ParseReflection(module, UTF8String.ToSystemStringOrEmpty(name), new CAAssemblyRefFinder(module), gpContext);
/*int blobLength = (int)*/reader.ReadCompressedUInt32();
int numNamedArgs = (int)reader.ReadCompressedUInt32();
var namedArgs = CustomAttributeReader.ReadNamedArguments(module, ref reader, numNamedArgs, gpContext);
if (namedArgs is null)
throw new ApplicationException("Could not read named arguments");
list.Add(new SecurityAttribute(attrRef, namedArgs));
}
return list;
}
/// <summary>
/// Reads the old (.NET Framework 1.x) DeclSecurity blob format
/// </summary>
/// <returns></returns>
IList<SecurityAttribute> ReadXmlFormat() {
var xml = reader.ReadUtf16String((int)reader.Length / 2);
var sa = SecurityAttribute.CreateFromXml(module, xml);
return new List<SecurityAttribute> { sa };
}
UTF8String ReadUTF8String() {
uint len = reader.ReadCompressedUInt32();
return len == 0 ? UTF8String.Empty : new UTF8String(reader.ReadBytes((int)len));
}
}
}

View File

@ -1,209 +0,0 @@
// dnlib: See LICENSE.txt for more info
namespace dnlib.DotNet {
/// <summary>
/// See CorHdr.h/CorElementType
/// </summary>
public enum ElementType : byte {
/// <summary/>
End = 0x00,
/// <summary>System.Void</summary>
Void = 0x01,
/// <summary>System.Boolean</summary>
Boolean = 0x02,
/// <summary>System.Char</summary>
Char = 0x03,
/// <summary>System.SByte</summary>
I1 = 0x04,
/// <summary>System.Byte</summary>
U1 = 0x05,
/// <summary>System.Int16</summary>
I2 = 0x06,
/// <summary>System.UInt16</summary>
U2 = 0x07,
/// <summary>System.Int32</summary>
I4 = 0x08,
/// <summary>System.UInt32</summary>
U4 = 0x09,
/// <summary>System.Int64</summary>
I8 = 0x0A,
/// <summary>System.UInt64</summary>
U8 = 0x0B,
/// <summary>System.Single</summary>
R4 = 0x0C,
/// <summary>System.Double</summary>
R8 = 0x0D,
/// <summary>System.String</summary>
String = 0x0E,
/// <summary>Pointer type (*)</summary>
Ptr = 0x0F,
/// <summary>ByRef type (&amp;)</summary>
ByRef = 0x10,
/// <summary>Value type</summary>
ValueType = 0x11,
/// <summary>Reference type</summary>
Class = 0x12,
/// <summary>Type generic parameter</summary>
Var = 0x13,
/// <summary>Multidimensional array ([*], [,], [,,], ...)</summary>
Array = 0x14,
/// <summary>Generic instance type</summary>
GenericInst = 0x15,
/// <summary>Typed byref</summary>
TypedByRef = 0x16,
/// <summary>Value array (don't use)</summary>
ValueArray = 0x17,
/// <summary>System.IntPtr</summary>
I = 0x18,
/// <summary>System.UIntPtr</summary>
U = 0x19,
/// <summary>native real (don't use)</summary>
R = 0x1A,
/// <summary>Function pointer</summary>
FnPtr = 0x1B,
/// <summary>System.Object</summary>
Object = 0x1C,
/// <summary>Single-dimension, zero lower bound array ([])</summary>
SZArray = 0x1D,
/// <summary>Method generic parameter</summary>
MVar = 0x1E,
/// <summary>Required C modifier</summary>
CModReqd = 0x1F,
/// <summary>Optional C modifier</summary>
CModOpt = 0x20,
/// <summary>Used internally by the CLR (don't use)</summary>
Internal = 0x21,
/// <summary>Module (don't use)</summary>
Module = 0x3F,
/// <summary>Sentinel (method sigs only)</summary>
Sentinel = 0x41,
/// <summary>Pinned type (locals only)</summary>
Pinned = 0x45,
}
public static partial class Extensions {
/// <summary>
/// Returns <c>true</c> if it's an integer or a floating point type
/// </summary>
/// <param name="etype">Element type</param>
/// <returns></returns>
public static bool IsPrimitive(this ElementType etype) {
switch (etype) {
case ElementType.Boolean:
case ElementType.Char:
case ElementType.I1:
case ElementType.U1:
case ElementType.I2:
case ElementType.U2:
case ElementType.I4:
case ElementType.U4:
case ElementType.I8:
case ElementType.U8:
case ElementType.R4:
case ElementType.R8:
case ElementType.I:
case ElementType.U:
case ElementType.R:
return true;
default:
return false;
}
}
/// <summary>
/// Returns the size of the element type in bytes or <c>-1</c> if it's unknown
/// </summary>
/// <param name="etype">Element type</param>
/// <param name="ptrSize">Size of a pointer</param>
/// <returns></returns>
public static int GetPrimitiveSize(this ElementType etype, int ptrSize = -1) {
switch (etype) {
case ElementType.Boolean:
case ElementType.I1:
case ElementType.U1:
return 1;
case ElementType.Char:
case ElementType.I2:
case ElementType.U2:
return 2;
case ElementType.I4:
case ElementType.U4:
case ElementType.R4:
return 4;
case ElementType.I8:
case ElementType.U8:
case ElementType.R8:
return 8;
case ElementType.Ptr:
case ElementType.FnPtr:
case ElementType.I:
case ElementType.U:
return ptrSize;
default:
return -1;
}
}
/// <summary>
/// Checks whether it's a value type
/// </summary>
/// <param name="etype">this</param>
/// <returns><c>true</c> if it's a value type, <c>false</c> if it's not a value type or
/// if we couldn't determine whether it's a value type. Eg., it could be a generic
/// instance type.</returns>
public static bool IsValueType(this ElementType etype) {
switch (etype) {
case ElementType.Void:
case ElementType.Boolean:
case ElementType.Char:
case ElementType.I1:
case ElementType.U1:
case ElementType.I2:
case ElementType.U2:
case ElementType.I4:
case ElementType.U4:
case ElementType.I8:
case ElementType.U8:
case ElementType.R4:
case ElementType.R8:
case ElementType.ValueType:
case ElementType.TypedByRef:
case ElementType.ValueArray:
case ElementType.I:
case ElementType.U:
case ElementType.R:
return true;
case ElementType.GenericInst:
// We don't have enough info to determine whether this is a value type
return false;
case ElementType.End:
case ElementType.String:
case ElementType.Ptr:
case ElementType.ByRef:
case ElementType.Class:
case ElementType.Var:
case ElementType.Array:
case ElementType.FnPtr:
case ElementType.Object:
case ElementType.SZArray:
case ElementType.MVar:
case ElementType.CModReqd:
case ElementType.CModOpt:
case ElementType.Internal:
case ElementType.Module:
case ElementType.Sentinel:
case ElementType.Pinned:
default:
return false;
}
}
}
}

View File

@ -1,296 +0,0 @@
// dnlib: See LICENSE.txt for more info
namespace dnlib.DotNet.Emit {
/// <summary>
/// A CIL opcode. If the high byte is 0 or if it's <see cref="UNKNOWN1"/>, it's a 1-byte opcode,
/// else it's a two-byte opcode and the highest byte is the first byte of the opcode.
/// </summary>
public enum Code : ushort {
#pragma warning disable 1591 // disable XML doc warning
UNKNOWN1 = 0x0100,
UNKNOWN2 = 0x0101,
Add = 0x0058,
Add_Ovf = 0x00D6,
Add_Ovf_Un = 0x00D7,
And = 0x005F,
Arglist = 0xFE00,
Beq = 0x003B,
Beq_S = 0x002E,
Bge = 0x003C,
Bge_S = 0x002F,
Bge_Un = 0x0041,
Bge_Un_S = 0x0034,
Bgt = 0x003D,
Bgt_S = 0x0030,
Bgt_Un = 0x0042,
Bgt_Un_S = 0x0035,
Ble = 0x003E,
Ble_S = 0x0031,
Ble_Un = 0x0043,
Ble_Un_S = 0x0036,
Blt = 0x003F,
Blt_S = 0x0032,
Blt_Un = 0x0044,
Blt_Un_S = 0x0037,
Bne_Un = 0x0040,
Bne_Un_S = 0x0033,
Box = 0x008C,
Br = 0x0038,
Br_S = 0x002B,
Break = 0x0001,
Brfalse = 0x0039,
Brfalse_S = 0x002C,
Brtrue = 0x003A,
Brtrue_S = 0x002D,
Call = 0x0028,
Calli = 0x0029,
Callvirt = 0x006F,
Castclass = 0x0074,
Ceq = 0xFE01,
Cgt = 0xFE02,
Cgt_Un = 0xFE03,
Ckfinite = 0x00C3,
Clt = 0xFE04,
Clt_Un = 0xFE05,
Constrained = 0xFE16,
Conv_I = 0x00D3,
Conv_I1 = 0x0067,
Conv_I2 = 0x0068,
Conv_I4 = 0x0069,
Conv_I8 = 0x006A,
Conv_Ovf_I = 0x00D4,
Conv_Ovf_I_Un = 0x008A,
Conv_Ovf_I1 = 0x00B3,
Conv_Ovf_I1_Un = 0x0082,
Conv_Ovf_I2 = 0x00B5,
Conv_Ovf_I2_Un = 0x0083,
Conv_Ovf_I4 = 0x00B7,
Conv_Ovf_I4_Un = 0x0084,
Conv_Ovf_I8 = 0x00B9,
Conv_Ovf_I8_Un = 0x0085,
Conv_Ovf_U = 0x00D5,
Conv_Ovf_U_Un = 0x008B,
Conv_Ovf_U1 = 0x00B4,
Conv_Ovf_U1_Un = 0x0086,
Conv_Ovf_U2 = 0x00B6,
Conv_Ovf_U2_Un = 0x0087,
Conv_Ovf_U4 = 0x00B8,
Conv_Ovf_U4_Un = 0x0088,
Conv_Ovf_U8 = 0x00BA,
Conv_Ovf_U8_Un = 0x0089,
Conv_R_Un = 0x0076,
Conv_R4 = 0x006B,
Conv_R8 = 0x006C,
Conv_U = 0x00E0,
Conv_U1 = 0x00D2,
Conv_U2 = 0x00D1,
Conv_U4 = 0x006D,
Conv_U8 = 0x006E,
Cpblk = 0xFE17,
Cpobj = 0x0070,
Div = 0x005B,
Div_Un = 0x005C,
Dup = 0x0025,
Endfilter = 0xFE11,
Endfinally = 0x00DC,
Initblk = 0xFE18,
Initobj = 0xFE15,
Isinst = 0x0075,
Jmp = 0x0027,
Ldarg = 0xFE09,
Ldarg_0 = 0x0002,
Ldarg_1 = 0x0003,
Ldarg_2 = 0x0004,
Ldarg_3 = 0x0005,
Ldarg_S = 0x000E,
Ldarga = 0xFE0A,
Ldarga_S = 0x000F,
Ldc_I4 = 0x0020,
Ldc_I4_0 = 0x0016,
Ldc_I4_1 = 0x0017,
Ldc_I4_2 = 0x0018,
Ldc_I4_3 = 0x0019,
Ldc_I4_4 = 0x001A,
Ldc_I4_5 = 0x001B,
Ldc_I4_6 = 0x001C,
Ldc_I4_7 = 0x001D,
Ldc_I4_8 = 0x001E,
Ldc_I4_M1 = 0x0015,
Ldc_I4_S = 0x001F,
Ldc_I8 = 0x0021,
Ldc_R4 = 0x0022,
Ldc_R8 = 0x0023,
Ldelem = 0x00A3,
Ldelem_I = 0x0097,
Ldelem_I1 = 0x0090,
Ldelem_I2 = 0x0092,
Ldelem_I4 = 0x0094,
Ldelem_I8 = 0x0096,
Ldelem_R4 = 0x0098,
Ldelem_R8 = 0x0099,
Ldelem_Ref = 0x009A,
Ldelem_U1 = 0x0091,
Ldelem_U2 = 0x0093,
Ldelem_U4 = 0x0095,
Ldelema = 0x008F,
Ldfld = 0x007B,
Ldflda = 0x007C,
Ldftn = 0xFE06,
Ldind_I = 0x004D,
Ldind_I1 = 0x0046,
Ldind_I2 = 0x0048,
Ldind_I4 = 0x004A,
Ldind_I8 = 0x004C,
Ldind_R4 = 0x004E,
Ldind_R8 = 0x004F,
Ldind_Ref = 0x0050,
Ldind_U1 = 0x0047,
Ldind_U2 = 0x0049,
Ldind_U4 = 0x004B,
Ldlen = 0x008E,
Ldloc = 0xFE0C,
Ldloc_0 = 0x0006,
Ldloc_1 = 0x0007,
Ldloc_2 = 0x0008,
Ldloc_3 = 0x0009,
Ldloc_S = 0x0011,
Ldloca = 0xFE0D,
Ldloca_S = 0x0012,
Ldnull = 0x0014,
Ldobj = 0x0071,
Ldsfld = 0x007E,
Ldsflda = 0x007F,
Ldstr = 0x0072,
Ldtoken = 0x00D0,
Ldvirtftn = 0xFE07,
Leave = 0x00DD,
Leave_S = 0x00DE,
Localloc = 0xFE0F,
Mkrefany = 0x00C6,
Mul = 0x005A,
Mul_Ovf = 0x00D8,
Mul_Ovf_Un = 0x00D9,
Neg = 0x0065,
Newarr = 0x008D,
Newobj = 0x0073,
No = 0xFE19,
Nop = 0x0000,
Not = 0x0066,
Or = 0x0060,
Pop = 0x0026,
Prefix1 = 0x00FE,
Prefix2 = 0x00FD,
Prefix3 = 0x00FC,
Prefix4 = 0x00FB,
Prefix5 = 0x00FA,
Prefix6 = 0x00F9,
Prefix7 = 0x00F8,
Prefixref = 0x00FF,
Readonly = 0xFE1E,
Refanytype = 0xFE1D,
Refanyval = 0x00C2,
Rem = 0x005D,
Rem_Un = 0x005E,
Ret = 0x002A,
Rethrow = 0xFE1A,
Shl = 0x0062,
Shr = 0x0063,
Shr_Un = 0x0064,
Sizeof = 0xFE1C,
Starg = 0xFE0B,
Starg_S = 0x0010,
Stelem = 0x00A4,
Stelem_I = 0x009B,
Stelem_I1 = 0x009C,
Stelem_I2 = 0x009D,
Stelem_I4 = 0x009E,
Stelem_I8 = 0x009F,
Stelem_R4 = 0x00A0,
Stelem_R8 = 0x00A1,
Stelem_Ref = 0x00A2,
Stfld = 0x007D,
Stind_I = 0x00DF,
Stind_I1 = 0x0052,
Stind_I2 = 0x0053,
Stind_I4 = 0x0054,
Stind_I8 = 0x0055,
Stind_R4 = 0x0056,
Stind_R8 = 0x0057,
Stind_Ref = 0x0051,
Stloc = 0xFE0E,
Stloc_0 = 0x000A,
Stloc_1 = 0x000B,
Stloc_2 = 0x000C,
Stloc_3 = 0x000D,
Stloc_S = 0x0013,
Stobj = 0x0081,
Stsfld = 0x0080,
Sub = 0x0059,
Sub_Ovf = 0x00DA,
Sub_Ovf_Un = 0x00DB,
Switch = 0x0045,
Tailcall = 0xFE14,
Throw = 0x007A,
Unaligned = 0xFE12,
Unbox = 0x0079,
Unbox_Any = 0x00A5,
Volatile = 0xFE13,
Xor = 0x0061,
#pragma warning restore
}
public static partial class Extensions {
/// <summary>
/// Determines whether a <see cref="Code"/> is experimental
/// </summary>
/// <param name="code">The code</param>
/// <returns><c>true</c> if the <see cref="Code"/> is experimental; otherwise, <c>false</c></returns>
public static bool IsExperimental(this Code code) {
byte hi = (byte)((ushort)code >> 8);
return hi >= 0xF0 && hi <= 0xFB;
}
/// <summary>
/// Converts a <see cref="Code"/> to an <see cref="OpCode"/>
/// </summary>
/// <param name="code">The code</param>
/// <returns>A <see cref="OpCode"/> or <c>null</c> if it's invalid</returns>
public static OpCode ToOpCode(this Code code) {
byte hi = (byte)((ushort)code >> 8);
byte lo = (byte)code;
if (hi == 0)
return OpCodes.OneByteOpCodes[lo];
if (hi == 0xFE)
return OpCodes.TwoByteOpCodes[lo];
if (code == Code.UNKNOWN1)
return OpCodes.UNKNOWN1;
if (code == Code.UNKNOWN2)
return OpCodes.UNKNOWN2;
return null;
}
/// <summary>
/// Converts a <see cref="Code"/> to an <see cref="OpCode"/>, using a module context to look
/// up potential experimental opcodes
/// </summary>
/// <param name="code">The code</param>
/// <param name="context">The module context</param>
/// <returns>A <see cref="OpCode"/> or <c>null</c> if it's invalid</returns>
public static OpCode ToOpCode(this Code code, ModuleContext context) {
byte hi = (byte)((ushort)code >> 8);
byte lo = (byte)code;
if (hi == 0)
return OpCodes.OneByteOpCodes[lo];
if (hi == 0xFE)
return OpCodes.TwoByteOpCodes[lo];
if (context.GetExperimentalOpCode(hi, lo) is OpCode op)
return op;
if (code == Code.UNKNOWN1)
return OpCodes.UNKNOWN1;
if (code == Code.UNKNOWN2)
return OpCodes.UNKNOWN2;
return null;
}
}
}

View File

@ -1,569 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System;
using System.Collections.Generic;
using SR = System.Reflection;
using System.Reflection.Emit;
using System.IO;
using dnlib.DotNet.MD;
using dnlib.IO;
namespace dnlib.DotNet.Emit {
/// <summary>
/// <see cref="DynamicMethodBodyReader"/> options
/// </summary>
[Flags]
public enum DynamicMethodBodyReaderOptions {
/// <summary>
/// No option is enabled
/// </summary>
None = 0,
/// <summary>
/// Some fields/methods have an unknown declaring type and don't have a context with
/// that information. If this is enabled, the reader will try to guess it but it doesn't
/// always work. If you get an <see cref="ArgumentException"/>, try enabling this option.
/// </summary>
UnknownDeclaringType = 0x00000001,
}
/// <summary>
/// Reads code from a DynamicMethod
/// </summary>
public class DynamicMethodBodyReader : MethodBodyReaderBase, ISignatureReaderHelper {
static readonly ReflectionFieldInfo rtdmOwnerFieldInfo = new ReflectionFieldInfo("m_owner");
static readonly ReflectionFieldInfo dmResolverFieldInfo = new ReflectionFieldInfo("m_resolver", "_resolver");
static readonly ReflectionFieldInfo rslvCodeFieldInfo = new ReflectionFieldInfo("m_code");
static readonly ReflectionFieldInfo rslvDynamicScopeFieldInfo = new ReflectionFieldInfo("m_scope");
static readonly ReflectionFieldInfo rslvMethodFieldInfo = new ReflectionFieldInfo("m_method");
static readonly ReflectionFieldInfo rslvLocalsFieldInfo = new ReflectionFieldInfo("m_localSignature");
static readonly ReflectionFieldInfo rslvMaxStackFieldInfo = new ReflectionFieldInfo("m_stackSize");
static readonly ReflectionFieldInfo rslvExceptionsFieldInfo = new ReflectionFieldInfo("m_exceptions");
static readonly ReflectionFieldInfo rslvExceptionHeaderFieldInfo = new ReflectionFieldInfo("m_exceptionHeader");
static readonly ReflectionFieldInfo scopeTokensFieldInfo = new ReflectionFieldInfo("m_tokens");
static readonly ReflectionFieldInfo gfiFieldHandleFieldInfo = new ReflectionFieldInfo("m_field", "m_fieldHandle");
static readonly ReflectionFieldInfo gfiContextFieldInfo = new ReflectionFieldInfo("m_context");
static readonly ReflectionFieldInfo gmiMethodHandleFieldInfo = new ReflectionFieldInfo("m_method", "m_methodHandle");
static readonly ReflectionFieldInfo gmiContextFieldInfo = new ReflectionFieldInfo("m_context");
static readonly ReflectionFieldInfo ehCatchAddrFieldInfo = new ReflectionFieldInfo("m_catchAddr");
static readonly ReflectionFieldInfo ehCatchClassFieldInfo = new ReflectionFieldInfo("m_catchClass");
static readonly ReflectionFieldInfo ehCatchEndAddrFieldInfo = new ReflectionFieldInfo("m_catchEndAddr");
static readonly ReflectionFieldInfo ehCurrentCatchFieldInfo = new ReflectionFieldInfo("m_currentCatch");
static readonly ReflectionFieldInfo ehTypeFieldInfo = new ReflectionFieldInfo("m_type");
static readonly ReflectionFieldInfo ehStartAddrFieldInfo = new ReflectionFieldInfo("m_startAddr");
static readonly ReflectionFieldInfo ehEndAddrFieldInfo = new ReflectionFieldInfo("m_endAddr");
static readonly ReflectionFieldInfo ehEndFinallyFieldInfo = new ReflectionFieldInfo("m_endFinally");
static readonly ReflectionFieldInfo vamMethodFieldInfo = new ReflectionFieldInfo("m_method");
static readonly ReflectionFieldInfo vamDynamicMethodFieldInfo = new ReflectionFieldInfo("m_dynamicMethod");
static readonly ReflectionFieldInfo dmDynamicILInfoFieldInfo = new ReflectionFieldInfo("m_DynamicILInfo", "_dynamicILInfo");
static readonly ReflectionFieldInfo dynILInfoMaxStackFieldInfo = new ReflectionFieldInfo("m_maxStackSize");
readonly ModuleDef module;
readonly Importer importer;
readonly GenericParamContext gpContext;
readonly MethodDef method;
readonly int codeSize;
readonly int maxStack;
readonly bool initLocals;
readonly List<object> tokens;
readonly IList<object> ehInfos;
readonly byte[] ehHeader;
readonly string methodName;
readonly DynamicMethodBodyReaderOptions options;
class ReflectionFieldInfo {
SR.FieldInfo fieldInfo;
readonly string fieldName1;
readonly string fieldName2;
public ReflectionFieldInfo(string fieldName) => fieldName1 = fieldName;
public ReflectionFieldInfo(string fieldName1, string fieldName2) {
this.fieldName1 = fieldName1;
this.fieldName2 = fieldName2;
}
public object Read(object instance) {
if (fieldInfo is null)
InitializeField(instance.GetType());
if (fieldInfo is null)
throw new Exception($"Couldn't find field '{fieldName1}' or '{fieldName2}'");
return fieldInfo.GetValue(instance);
}
public bool Exists(object instance) {
InitializeField(instance.GetType());
return fieldInfo is not null;
}
void InitializeField(Type type) {
if (fieldInfo is not null)
return;
const SR.BindingFlags flags = SR.BindingFlags.Instance | SR.BindingFlags.Public | SR.BindingFlags.NonPublic;
fieldInfo = type.GetField(fieldName1, flags);
if (fieldInfo is null && fieldName2 is not null)
fieldInfo = type.GetField(fieldName2, flags);
}
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="module">Module that will own the method body</param>
/// <param name="obj">This can be one of several supported types: the delegate instance
/// created by DynamicMethod.CreateDelegate(), a DynamicMethod instance, a RTDynamicMethod
/// instance or a DynamicResolver instance.</param>
public DynamicMethodBodyReader(ModuleDef module, object obj)
: this(module, obj, new GenericParamContext()) {
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="module">Module that will own the method body</param>
/// <param name="obj">This can be one of several supported types: the delegate instance
/// created by DynamicMethod.CreateDelegate(), a DynamicMethod instance, a RTDynamicMethod
/// instance or a DynamicResolver instance.</param>
/// <param name="gpContext">Generic parameter context</param>
public DynamicMethodBodyReader(ModuleDef module, object obj, GenericParamContext gpContext)
: this(module, obj, new Importer(module, ImporterOptions.TryToUseDefs, gpContext), DynamicMethodBodyReaderOptions.None) {
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="module">Module that will own the method body</param>
/// <param name="obj">This can be one of several supported types: the delegate instance
/// created by DynamicMethod.CreateDelegate(), a DynamicMethod instance, a RTDynamicMethod
/// instance or a DynamicResolver instance.</param>
/// <param name="importer">Importer</param>
public DynamicMethodBodyReader(ModuleDef module, object obj, Importer importer)
: this(module, obj, importer, DynamicMethodBodyReaderOptions.None) {
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="module">Module that will own the method body</param>
/// <param name="obj">This can be one of several supported types: the delegate instance
/// created by DynamicMethod.CreateDelegate(), a DynamicMethod instance, a RTDynamicMethod
/// instance or a DynamicResolver instance.</param>
/// <param name="importer">Importer</param>
/// <param name="options">Options</param>
public DynamicMethodBodyReader(ModuleDef module, object obj, Importer importer, DynamicMethodBodyReaderOptions options)
: base(module.Context) {
this.module = module;
this.importer = importer;
this.options = options;
gpContext = importer.gpContext;
methodName = null;
if (obj is null)
throw new ArgumentNullException(nameof(obj));
if (obj is Delegate del) {
obj = del.Method;
if (obj is null)
throw new Exception("Delegate.Method is null");
}
if (obj.GetType().ToString() == "System.Reflection.Emit.DynamicMethod+RTDynamicMethod") {
obj = rtdmOwnerFieldInfo.Read(obj) as DynamicMethod;
if (obj is null)
throw new Exception("RTDynamicMethod.m_owner is null or invalid");
}
if (obj is DynamicMethod dynMethod) {
methodName = dynMethod.Name;
obj = dmResolverFieldInfo.Read(obj) ?? dmDynamicILInfoFieldInfo.Read(obj);;
if (obj is null)
throw new Exception("No resolver found");
}
string objTypeName = obj.GetType().ToString();
bool isILInfo = objTypeName == "System.Reflection.Emit.DynamicILInfo";
if (objTypeName != "System.Reflection.Emit.DynamicResolver" && !isILInfo)
throw new Exception("Couldn't find DynamicResolver or DynamicILInfo");
var code = rslvCodeFieldInfo.Read(obj) as byte[];
if (code is null)
throw new Exception("No code");
codeSize = code.Length;
var delMethod = rslvMethodFieldInfo.Read(obj) as DynamicMethod;
if (delMethod is null)
throw new Exception("No method");
initLocals = delMethod.InitLocals;
maxStack = isILInfo ? (int)dynILInfoMaxStackFieldInfo.Read(obj) : (int)rslvMaxStackFieldInfo.Read(obj);
var scope = rslvDynamicScopeFieldInfo.Read(obj);
if (scope is null)
throw new Exception("No scope");
var tokensList = scopeTokensFieldInfo.Read(scope) as System.Collections.IList;
if (tokensList is null)
throw new Exception("No tokens");
tokens = new List<object>(tokensList.Count);
for (int i = 0; i < tokensList.Count; i++)
tokens.Add(tokensList[i]);
if (isILInfo)
ehHeader = rslvExceptionsFieldInfo.Read(obj) as byte[];
else {
ehInfos = (IList<object>)rslvExceptionsFieldInfo.Read(obj);
ehHeader = rslvExceptionHeaderFieldInfo.Read(obj) as byte[];
}
UpdateLocals(rslvLocalsFieldInfo.Read(obj) as byte[]);
reader = ByteArrayDataReaderFactory.CreateReader(code);
method = CreateMethodDef(delMethod);
parameters = method.Parameters;
}
class ExceptionInfo {
public int[] CatchAddr;
public Type[] CatchClass;
public int[] CatchEndAddr;
public int CurrentCatch;
public int[] Type;
public int StartAddr;
public int EndAddr;
public int EndFinally;
}
static List<ExceptionInfo> CreateExceptionInfos(IList<object> ehInfos) {
if (ehInfos is null)
return new List<ExceptionInfo>();
var infos = new List<ExceptionInfo>(ehInfos.Count);
int count = ehInfos.Count;
for (int i = 0; i < count; i++) {
var ehInfo = ehInfos[i];
var eh = new ExceptionInfo {
CatchAddr = (int[])ehCatchAddrFieldInfo.Read(ehInfo),
CatchClass = (Type[])ehCatchClassFieldInfo.Read(ehInfo),
CatchEndAddr = (int[])ehCatchEndAddrFieldInfo.Read(ehInfo),
CurrentCatch = (int)ehCurrentCatchFieldInfo.Read(ehInfo),
Type = (int[])ehTypeFieldInfo.Read(ehInfo),
StartAddr = (int)ehStartAddrFieldInfo.Read(ehInfo),
EndAddr = (int)ehEndAddrFieldInfo.Read(ehInfo),
EndFinally = (int)ehEndFinallyFieldInfo.Read(ehInfo),
};
infos.Add(eh);
}
return infos;
}
void UpdateLocals(byte[] localsSig) {
if (localsSig is null || localsSig.Length == 0)
return;
var sig = SignatureReader.ReadSig(this, module.CorLibTypes, localsSig, gpContext) as LocalSig;
if (sig is null)
return;
var sigLocals = sig.Locals;
int count = sigLocals.Count;
for (int i = 0; i < count; i++)
locals.Add(new Local(sigLocals[i]));
}
MethodDef CreateMethodDef(SR.MethodBase delMethod) {
bool isStatic = true;
var method = new MethodDefUser();
var retType = GetReturnType(delMethod);
var pms = GetParameters(delMethod);
if (isStatic)
method.Signature = MethodSig.CreateStatic(retType, pms.ToArray());
else
method.Signature = MethodSig.CreateInstance(retType, pms.ToArray());
method.Parameters.UpdateParameterTypes();
method.ImplAttributes = MethodImplAttributes.IL;
method.Attributes = MethodAttributes.PrivateScope;
if (isStatic)
method.Attributes |= MethodAttributes.Static;
return module.UpdateRowId(method);
}
TypeSig GetReturnType(SR.MethodBase mb) {
if (mb is SR.MethodInfo mi)
return importer.ImportAsTypeSig(mi.ReturnType);
return module.CorLibTypes.Void;
}
List<TypeSig> GetParameters(SR.MethodBase delMethod) {
var pms = new List<TypeSig>();
foreach (var param in delMethod.GetParameters())
pms.Add(importer.ImportAsTypeSig(param.ParameterType));
return pms;
}
/// <summary>
/// Reads the code
/// </summary>
/// <returns></returns>
public bool Read() {
ReadInstructionsNumBytes((uint)codeSize);
CreateExceptionHandlers();
return true;
}
void CreateExceptionHandlers() {
if (ehHeader is not null) {
if (ehHeader.Length < 4)
return;
var reader = new BinaryReader(new MemoryStream(ehHeader));
byte b = reader.ReadByte();
if ((b & 0x40) == 0) { // DynamicResolver only checks bit 6
// Calculate num ehs exactly the same way that DynamicResolver does
int numHandlers = (ushort)((reader.ReadByte() - 2) / 12);
reader.ReadUInt16();
for (int i = 0; i < numHandlers; i++) {
if (reader.BaseStream.Position + 12 > reader.BaseStream.Length)
break;
var eh = new ExceptionHandler();
eh.HandlerType = (ExceptionHandlerType)reader.ReadUInt16();
int offs = reader.ReadUInt16();
eh.TryStart = GetInstructionThrow((uint)offs);
eh.TryEnd = GetInstruction((uint)(reader.ReadByte() + offs));
offs = reader.ReadUInt16();
eh.HandlerStart = GetInstructionThrow((uint)offs);
eh.HandlerEnd = GetInstruction((uint)(reader.ReadByte() + offs));
if (eh.IsCatch)
eh.CatchType = ReadToken(reader.ReadUInt32()) as ITypeDefOrRef;
else if (eh.IsFilter)
eh.FilterStart = GetInstruction(reader.ReadUInt32());
else
reader.ReadUInt32();
exceptionHandlers.Add(eh);
}
}
else {
reader.BaseStream.Position--;
int numHandlers = (ushort)(((reader.ReadUInt32() >> 8) - 4) / 24);
for (int i = 0; i < numHandlers; i++) {
if (reader.BaseStream.Position + 24 > reader.BaseStream.Length)
break;
var eh = new ExceptionHandler();
eh.HandlerType = (ExceptionHandlerType)reader.ReadUInt32();
var offs = reader.ReadUInt32();
eh.TryStart = GetInstructionThrow((uint)offs);
eh.TryEnd = GetInstruction((uint)(reader.ReadUInt32() + offs));
offs = reader.ReadUInt32();
eh.HandlerStart = GetInstructionThrow((uint)offs);
eh.HandlerEnd = GetInstruction((uint)(reader.ReadUInt32() + offs));
if (eh.IsCatch)
eh.CatchType = ReadToken(reader.ReadUInt32()) as ITypeDefOrRef;
else if (eh.IsFilter)
eh.FilterStart = GetInstruction(reader.ReadUInt32());
else
reader.ReadUInt32();
exceptionHandlers.Add(eh);
}
}
}
else if (ehInfos is not null) {
foreach (var ehInfo in CreateExceptionInfos(ehInfos)) {
var tryStart = GetInstructionThrow((uint)ehInfo.StartAddr);
var tryEnd = GetInstruction((uint)ehInfo.EndAddr);
var endFinally = ehInfo.EndFinally < 0 ? null : GetInstruction((uint)ehInfo.EndFinally);
for (int i = 0; i < ehInfo.CurrentCatch; i++) {
var eh = new ExceptionHandler();
eh.HandlerType = (ExceptionHandlerType)ehInfo.Type[i];
eh.TryStart = tryStart;
eh.TryEnd = eh.IsFinally ? endFinally : tryEnd;
eh.FilterStart = null; // not supported by DynamicMethod.ILGenerator
eh.HandlerStart = GetInstructionThrow((uint)ehInfo.CatchAddr[i]);
eh.HandlerEnd = GetInstruction((uint)ehInfo.CatchEndAddr[i]);
eh.CatchType = importer.Import(ehInfo.CatchClass[i]);
exceptionHandlers.Add(eh);
}
}
}
}
/// <summary>
/// Returns the created method. Must be called after <see cref="Read()"/>.
/// </summary>
/// <returns>A new <see cref="CilBody"/> instance</returns>
public MethodDef GetMethod() {
var cilBody = new CilBody(initLocals, instructions, exceptionHandlers, locals);
cilBody.MaxStack = (ushort)Math.Min(maxStack, ushort.MaxValue);
instructions = null;
exceptionHandlers = null;
locals = null;
method.Body = cilBody;
method.Name = methodName;
return method;
}
/// <inheritdoc/>
protected override IField ReadInlineField(Instruction instr) => ReadToken(reader.ReadUInt32()) as IField;
/// <inheritdoc/>
protected override IMethod ReadInlineMethod(Instruction instr) => ReadToken(reader.ReadUInt32()) as IMethod;
/// <inheritdoc/>
protected override MethodSig ReadInlineSig(Instruction instr) => ReadToken(reader.ReadUInt32()) as MethodSig;
/// <inheritdoc/>
protected override string ReadInlineString(Instruction instr) => ReadToken(reader.ReadUInt32()) as string ?? string.Empty;
/// <inheritdoc/>
protected override ITokenOperand ReadInlineTok(Instruction instr) => ReadToken(reader.ReadUInt32()) as ITokenOperand;
/// <inheritdoc/>
protected override ITypeDefOrRef ReadInlineType(Instruction instr) => ReadToken(reader.ReadUInt32()) as ITypeDefOrRef;
object ReadToken(uint token) {
uint rid = token & 0x00FFFFFF;
switch (token >> 24) {
case 0x02:
return ImportType(rid);
case 0x04:
return ImportField(rid);
case 0x06:
case 0x0A:
return ImportMethod(rid);
case 0x11:
return ImportSignature(rid);
case 0x70:
return Resolve(rid) as string;
default:
return null;
}
}
IMethod ImportMethod(uint rid) {
var obj = Resolve(rid);
if (obj is null)
return null;
if (obj is RuntimeMethodHandle) {
if ((options & DynamicMethodBodyReaderOptions.UnknownDeclaringType) != 0) {
// Sometimes it's a generic type but obj != `GenericMethodInfo`, so pass in 'default' and the
// runtime will try to figure out the declaring type. https://github.com/0xd4d/dnlib/issues/298
return importer.Import(SR.MethodBase.GetMethodFromHandle((RuntimeMethodHandle)obj, default));
}
else
return importer.Import(SR.MethodBase.GetMethodFromHandle((RuntimeMethodHandle)obj));
}
if (obj.GetType().ToString() == "System.Reflection.Emit.GenericMethodInfo") {
var context = (RuntimeTypeHandle)gmiContextFieldInfo.Read(obj);
var method = SR.MethodBase.GetMethodFromHandle((RuntimeMethodHandle)gmiMethodHandleFieldInfo.Read(obj), context);
return importer.Import(method);
}
if (obj.GetType().ToString() == "System.Reflection.Emit.VarArgMethod") {
var method = GetVarArgMethod(obj);
if (!(method is DynamicMethod))
return importer.Import(method);
obj = method;
}
if (obj is DynamicMethod dm)
throw new Exception("DynamicMethod calls another DynamicMethod");
return null;
}
SR.MethodInfo GetVarArgMethod(object obj) {
if (vamDynamicMethodFieldInfo.Exists(obj)) {
// .NET Framework 4.0+
var method = vamMethodFieldInfo.Read(obj) as SR.MethodInfo;
var dynMethod = vamDynamicMethodFieldInfo.Read(obj) as DynamicMethod;
return dynMethod ?? method;
}
else {
// .NET Framework 2.0
// This is either a DynamicMethod or a MethodInfo
return vamMethodFieldInfo.Read(obj) as SR.MethodInfo;
}
}
IField ImportField(uint rid) {
var obj = Resolve(rid);
if (obj is null)
return null;
if (obj is RuntimeFieldHandle) {
if ((options & DynamicMethodBodyReaderOptions.UnknownDeclaringType) != 0) {
// Sometimes it's a generic type but obj != `GenericFieldInfo`, so pass in 'default' and the
// runtime will try to figure out the declaring type. https://github.com/0xd4d/dnlib/issues/298
return importer.Import(SR.FieldInfo.GetFieldFromHandle((RuntimeFieldHandle)obj, default));
}
else
return importer.Import(SR.FieldInfo.GetFieldFromHandle((RuntimeFieldHandle)obj));
}
if (obj.GetType().ToString() == "System.Reflection.Emit.GenericFieldInfo") {
var context = (RuntimeTypeHandle)gfiContextFieldInfo.Read(obj);
var field = SR.FieldInfo.GetFieldFromHandle((RuntimeFieldHandle)gfiFieldHandleFieldInfo.Read(obj), context);
return importer.Import(field);
}
return null;
}
ITypeDefOrRef ImportType(uint rid) {
var obj = Resolve(rid);
if (obj is RuntimeTypeHandle)
return importer.Import(Type.GetTypeFromHandle((RuntimeTypeHandle)obj));
return null;
}
CallingConventionSig ImportSignature(uint rid) {
var sig = Resolve(rid) as byte[];
if (sig is null)
return null;
return SignatureReader.ReadSig(this, module.CorLibTypes, sig, gpContext);
}
object Resolve(uint index) {
if (index >= (uint)tokens.Count)
return null;
return tokens[(int)index];
}
/// <inheritdoc />
public override void RestoreMethod(MethodDef method) {
base.RestoreMethod(method);
var body = method.Body;
body.InitLocals = initLocals;
body.MaxStack = (ushort)Math.Min(maxStack, ushort.MaxValue);
}
ITypeDefOrRef ISignatureReaderHelper.ResolveTypeDefOrRef(uint codedToken, GenericParamContext gpContext) {
if (!CodedToken.TypeDefOrRef.Decode(codedToken, out uint token))
return null;
switch (MDToken.ToTable(token)) {
case Table.TypeDef:
case Table.TypeRef:
case Table.TypeSpec:
return module.ResolveToken(token) as ITypeDefOrRef;
}
return null;
}
TypeSig ISignatureReaderHelper.ConvertRTInternalAddress(IntPtr address) => importer.ImportAsTypeSig(MethodTableToTypeConverter.Convert(address));
}
}

View File

@ -1,78 +0,0 @@
// dnlib: See LICENSE.txt for more info
namespace dnlib.DotNet.Emit {
/// <summary>
/// A CIL method exception handler
/// </summary>
public sealed class ExceptionHandler {
/// <summary>
/// First instruction of try block
/// </summary>
public Instruction TryStart;
/// <summary>
/// One instruction past the end of try block or <c>null</c> if it ends at the end
/// of the method.
/// </summary>
public Instruction TryEnd;
/// <summary>
/// Start of filter handler or <c>null</c> if none. The end of filter handler is
/// always <see cref="HandlerStart"/>.
/// </summary>
public Instruction FilterStart;
/// <summary>
/// First instruction of try handler block
/// </summary>
public Instruction HandlerStart;
/// <summary>
/// One instruction past the end of try handler block or <c>null</c> if it ends at the end
/// of the method.
/// </summary>
public Instruction HandlerEnd;
/// <summary>
/// The catch type if <see cref="IsCatch"/> is <see langword="true" />
/// </summary>
public ITypeDefOrRef CatchType;
/// <summary>
/// Type of exception handler clause
/// </summary>
public ExceptionHandlerType HandlerType;
/// <summary>
/// Checks if it's a `catch` handler
/// </summary>
public bool IsCatch => ((uint)HandlerType & 7) == (uint)ExceptionHandlerType.Catch;
/// <summary>
/// Checks if it's a `filter` handler
/// </summary>
public bool IsFilter => (HandlerType & ExceptionHandlerType.Filter) != 0;
/// <summary>
/// Checks if it's a `finally` handler
/// </summary>
public bool IsFinally => (HandlerType & ExceptionHandlerType.Finally) != 0;
/// <summary>
/// Checks if it's a `fault` handler
/// </summary>
public bool IsFault => (HandlerType & ExceptionHandlerType.Fault) != 0;
/// <summary>
/// Default constructor
/// </summary>
public ExceptionHandler() {
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="handlerType">Exception clause type</param>
public ExceptionHandler(ExceptionHandlerType handlerType) => HandlerType = handlerType;
}
}

View File

@ -1,22 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System;
namespace dnlib.DotNet.Emit {
/// <summary>
/// Type of exception handler. See CorHdr.h/CorExceptionFlag
/// </summary>
[Flags]
public enum ExceptionHandlerType {
/// <summary/>
Catch = 0x0000,
/// <summary/>
Filter = 0x0001,
/// <summary/>
Finally = 0x0002,
/// <summary/>
Fault = 0x0004,
/// <summary/>
Duplicated = 0x0008,
}
}

View File

@ -1,9 +0,0 @@
// dnlib: See LICENSE.txt for more info
namespace dnlib.DotNet.Emit {
/// <summary>
/// Extension methods
/// </summary>
public static partial class Extensions {
}
}

View File

@ -1,27 +0,0 @@
// dnlib: See LICENSE.txt for more info
namespace dnlib.DotNet.Emit {
/// <summary>
/// CIL opcode flow control
/// </summary>
public enum FlowControl {
/// <summary/>
Branch,
/// <summary/>
Break,
/// <summary/>
Call,
/// <summary/>
Cond_Branch,
/// <summary/>
Meta,
/// <summary/>
Next,
/// <summary/>
Phi,
/// <summary/>
Return,
/// <summary/>
Throw,
}
}

View File

@ -1,827 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System;
using System.Collections.Generic;
using dnlib.DotNet.Pdb;
namespace dnlib.DotNet.Emit {
/// <summary>
/// A CIL instruction (opcode + operand)
/// </summary>
public sealed class Instruction {
/// <summary>
/// The opcode
/// </summary>
public OpCode OpCode;
/// <summary>
/// The opcode operand
/// </summary>
public object Operand;
/// <summary>
/// Offset of the instruction in the method body
/// </summary>
public uint Offset;
/// <summary>
/// PDB sequence point or <c>null</c> if none
/// </summary>
public SequencePoint SequencePoint;
/// <summary>
/// Default constructor
/// </summary>
public Instruction() {
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="opCode">Opcode</param>
public Instruction(OpCode opCode) => OpCode = opCode;
/// <summary>
/// Constructor
/// </summary>
/// <param name="opCode">Opcode</param>
/// <param name="operand">The operand</param>
public Instruction(OpCode opCode, object operand) {
OpCode = opCode;
Operand = operand;
}
/// <summary>
/// Creates a new instruction with no operand
/// </summary>
/// <param name="opCode">The opcode</param>
/// <returns>A new <see cref="Instruction"/> instance</returns>
public static Instruction Create(OpCode opCode) {
if (opCode.OperandType != OperandType.InlineNone)
throw new ArgumentException("Must be a no-operand opcode", nameof(opCode));
return new Instruction(opCode);
}
/// <summary>
/// Creates a new instruction with a <see cref="byte"/> operand
/// </summary>
/// <param name="opCode">The opcode</param>
/// <param name="value">The value</param>
/// <returns>A new <see cref="Instruction"/> instance</returns>
public static Instruction Create(OpCode opCode, byte value) {
if (opCode.Code != Code.Unaligned)
throw new ArgumentException("Opcode does not have a byte operand", nameof(opCode));
return new Instruction(opCode, value);
}
/// <summary>
/// Creates a new instruction with a <see cref="sbyte"/> operand
/// </summary>
/// <param name="opCode">The opcode</param>
/// <param name="value">The value</param>
/// <returns>A new <see cref="Instruction"/> instance</returns>
public static Instruction Create(OpCode opCode, sbyte value) {
if (opCode.Code != Code.Ldc_I4_S)
throw new ArgumentException("Opcode does not have a sbyte operand", nameof(opCode));
return new Instruction(opCode, value);
}
/// <summary>
/// Creates a new instruction with an <see cref="int"/> operand
/// </summary>
/// <param name="opCode">The opcode</param>
/// <param name="value">The value</param>
/// <returns>A new <see cref="Instruction"/> instance</returns>
public static Instruction Create(OpCode opCode, int value) {
if (opCode.OperandType != OperandType.InlineI)
throw new ArgumentException("Opcode does not have an int32 operand", nameof(opCode));
return new Instruction(opCode, value);
}
/// <summary>
/// Creates a new instruction with a <see cref="long"/> operand
/// </summary>
/// <param name="opCode">The opcode</param>
/// <param name="value">The value</param>
/// <returns>A new <see cref="Instruction"/> instance</returns>
public static Instruction Create(OpCode opCode, long value) {
if (opCode.OperandType != OperandType.InlineI8)
throw new ArgumentException("Opcode does not have an int64 operand", nameof(opCode));
return new Instruction(opCode, value);
}
/// <summary>
/// Creates a new instruction with a <see cref="float"/> operand
/// </summary>
/// <param name="opCode">The opcode</param>
/// <param name="value">The value</param>
/// <returns>A new <see cref="Instruction"/> instance</returns>
public static Instruction Create(OpCode opCode, float value) {
if (opCode.OperandType != OperandType.ShortInlineR)
throw new ArgumentException("Opcode does not have a real4 operand", nameof(opCode));
return new Instruction(opCode, value);
}
/// <summary>
/// Creates a new instruction with a <see cref="double"/> operand
/// </summary>
/// <param name="opCode">The opcode</param>
/// <param name="value">The value</param>
/// <returns>A new <see cref="Instruction"/> instance</returns>
public static Instruction Create(OpCode opCode, double value) {
if (opCode.OperandType != OperandType.InlineR)
throw new ArgumentException("Opcode does not have a real8 operand", nameof(opCode));
return new Instruction(opCode, value);
}
/// <summary>
/// Creates a new instruction with a string operand
/// </summary>
/// <param name="opCode">The opcode</param>
/// <param name="s">The string</param>
/// <returns>A new <see cref="Instruction"/> instance</returns>
public static Instruction Create(OpCode opCode, string s) {
if (opCode.OperandType != OperandType.InlineString)
throw new ArgumentException("Opcode does not have a string operand", nameof(opCode));
return new Instruction(opCode, s);
}
/// <summary>
/// Creates a new instruction with an instruction target operand
/// </summary>
/// <param name="opCode">The opcode</param>
/// <param name="target">Target instruction</param>
/// <returns>A new <see cref="Instruction"/> instance</returns>
public static Instruction Create(OpCode opCode, Instruction target) {
if (opCode.OperandType != OperandType.ShortInlineBrTarget && opCode.OperandType != OperandType.InlineBrTarget)
throw new ArgumentException("Opcode does not have an instruction operand", nameof(opCode));
return new Instruction(opCode, target);
}
/// <summary>
/// Creates a new instruction with an instruction target list operand
/// </summary>
/// <param name="opCode">The opcode</param>
/// <param name="targets">The targets</param>
/// <returns>A new <see cref="Instruction"/> instance</returns>
public static Instruction Create(OpCode opCode, IList<Instruction> targets) {
if (opCode.OperandType != OperandType.InlineSwitch)
throw new ArgumentException("Opcode does not have a targets array operand", nameof(opCode));
return new Instruction(opCode, targets);
}
/// <summary>
/// Creates a new instruction with a type operand
/// </summary>
/// <param name="opCode">The opcode</param>
/// <param name="type">The type</param>
/// <returns>A new <see cref="Instruction"/> instance</returns>
public static Instruction Create(OpCode opCode, ITypeDefOrRef type) {
if (opCode.OperandType != OperandType.InlineType && opCode.OperandType != OperandType.InlineTok)
throw new ArgumentException("Opcode does not have a type operand", nameof(opCode));
return new Instruction(opCode, type);
}
/// <summary>
/// Creates a new instruction with a type operand
/// </summary>
/// <param name="opCode">The opcode</param>
/// <param name="type">The type</param>
/// <returns>A new <see cref="Instruction"/> instance</returns>
public static Instruction Create(OpCode opCode, CorLibTypeSig type) => Create(opCode, type.TypeDefOrRef);
/// <summary>
/// Creates a new instruction with a method/field operand
/// </summary>
/// <param name="opCode">The opcode</param>
/// <param name="mr">The method/field</param>
/// <returns>A new <see cref="Instruction"/> instance</returns>
public static Instruction Create(OpCode opCode, MemberRef mr) {
if (opCode.OperandType != OperandType.InlineField && opCode.OperandType != OperandType.InlineMethod && opCode.OperandType != OperandType.InlineTok)
throw new ArgumentException("Opcode does not have a field operand", nameof(opCode));
return new Instruction(opCode, mr);
}
/// <summary>
/// Creates a new instruction with a field operand
/// </summary>
/// <param name="opCode">The opcode</param>
/// <param name="field">The field</param>
/// <returns>A new <see cref="Instruction"/> instance</returns>
public static Instruction Create(OpCode opCode, IField field) {
if (opCode.OperandType != OperandType.InlineField && opCode.OperandType != OperandType.InlineTok)
throw new ArgumentException("Opcode does not have a field operand", nameof(opCode));
return new Instruction(opCode, field);
}
/// <summary>
/// Creates a new instruction with a method operand
/// </summary>
/// <param name="opCode">The opcode</param>
/// <param name="method">The method</param>
/// <returns>A new <see cref="Instruction"/> instance</returns>
public static Instruction Create(OpCode opCode, IMethod method) {
if (opCode.OperandType != OperandType.InlineMethod && opCode.OperandType != OperandType.InlineTok)
throw new ArgumentException("Opcode does not have a method operand", nameof(opCode));
return new Instruction(opCode, method);
}
/// <summary>
/// Creates a new instruction with a token operand
/// </summary>
/// <param name="opCode">The opcode</param>
/// <param name="token">The token</param>
/// <returns>A new <see cref="Instruction"/> instance</returns>
public static Instruction Create(OpCode opCode, ITokenOperand token) {
if (opCode.OperandType != OperandType.InlineTok)
throw new ArgumentException("Opcode does not have a token operand", nameof(opCode));
return new Instruction(opCode, token);
}
/// <summary>
/// Creates a new instruction with a method signature operand
/// </summary>
/// <param name="opCode">The opcode</param>
/// <param name="methodSig">The method signature</param>
/// <returns>A new <see cref="Instruction"/> instance</returns>
public static Instruction Create(OpCode opCode, MethodSig methodSig) {
if (opCode.OperandType != OperandType.InlineSig)
throw new ArgumentException("Opcode does not have a method sig operand", nameof(opCode));
return new Instruction(opCode, methodSig);
}
/// <summary>
/// Creates a new instruction with a method parameter operand
/// </summary>
/// <param name="opCode">The opcode</param>
/// <param name="parameter">The method parameter</param>
/// <returns>A new <see cref="Instruction"/> instance</returns>
public static Instruction Create(OpCode opCode, Parameter parameter) {
if (opCode.OperandType != OperandType.ShortInlineVar && opCode.OperandType != OperandType.InlineVar)
throw new ArgumentException("Opcode does not have a method parameter operand", nameof(opCode));
return new Instruction(opCode, parameter);
}
/// <summary>
/// Creates a new instruction with a method local operand
/// </summary>
/// <param name="opCode">The opcode</param>
/// <param name="local">The method local</param>
/// <returns>A new <see cref="Instruction"/> instance</returns>
public static Instruction Create(OpCode opCode, Local local) {
if (opCode.OperandType != OperandType.ShortInlineVar && opCode.OperandType != OperandType.InlineVar)
throw new ArgumentException("Opcode does not have a method local operand", nameof(opCode));
return new Instruction(opCode, local);
}
/// <summary>
/// Creates a <c>ldci4</c> instruction
/// </summary>
/// <param name="value">Operand value</param>
/// <returns>A new <see cref="Instruction"/> instance</returns>
public static Instruction CreateLdcI4(int value) {
switch (value) {
case -1:return OpCodes.Ldc_I4_M1.ToInstruction();
case 0: return OpCodes.Ldc_I4_0.ToInstruction();
case 1: return OpCodes.Ldc_I4_1.ToInstruction();
case 2: return OpCodes.Ldc_I4_2.ToInstruction();
case 3: return OpCodes.Ldc_I4_3.ToInstruction();
case 4: return OpCodes.Ldc_I4_4.ToInstruction();
case 5: return OpCodes.Ldc_I4_5.ToInstruction();
case 6: return OpCodes.Ldc_I4_6.ToInstruction();
case 7: return OpCodes.Ldc_I4_7.ToInstruction();
case 8: return OpCodes.Ldc_I4_8.ToInstruction();
}
if (sbyte.MinValue <= value && value <= sbyte.MaxValue)
return new Instruction(OpCodes.Ldc_I4_S, (sbyte)value);
return new Instruction(OpCodes.Ldc_I4, value);
}
/// <summary>
/// Gets the size in bytes of the instruction
/// </summary>
/// <returns></returns>
public int GetSize() {
var opCode = OpCode;
switch (opCode.OperandType) {
case OperandType.InlineBrTarget:
case OperandType.InlineField:
case OperandType.InlineI:
case OperandType.InlineMethod:
case OperandType.InlineSig:
case OperandType.InlineString:
case OperandType.InlineTok:
case OperandType.InlineType:
case OperandType.ShortInlineR:
return opCode.Size + 4;
case OperandType.InlineI8:
case OperandType.InlineR:
return opCode.Size + 8;
case OperandType.InlineNone:
case OperandType.InlinePhi:
default:
return opCode.Size;
case OperandType.InlineSwitch:
var targets = Operand as IList<Instruction>;
return opCode.Size + 4 + (targets is null ? 0 : targets.Count * 4);
case OperandType.InlineVar:
return opCode.Size + 2;
case OperandType.ShortInlineBrTarget:
case OperandType.ShortInlineI:
case OperandType.ShortInlineVar:
return opCode.Size + 1;
}
}
static bool IsSystemVoid(TypeSig type) => type.RemovePinnedAndModifiers().GetElementType() == ElementType.Void;
/// <summary>
/// Updates <paramref name="stack"/> with the new stack size
/// </summary>
/// <param name="stack">Current stack size</param>
public void UpdateStack(ref int stack) => UpdateStack(ref stack, false);
/// <summary>
/// Updates <paramref name="stack"/> with the new stack size
/// </summary>
/// <param name="stack">Current stack size</param>
/// <param name="methodHasReturnValue"><c>true</c> if the method has a return value,
/// <c>false</c> otherwise</param>
public void UpdateStack(ref int stack, bool methodHasReturnValue) {
CalculateStackUsage(methodHasReturnValue, out int pushes, out int pops);
if (pops == -1)
stack = 0;
else
stack += pushes - pops;
}
/// <summary>
/// Calculates stack usage
/// </summary>
/// <param name="pushes">Updated with number of stack pushes</param>
/// <param name="pops">Updated with number of stack pops or <c>-1</c> if the stack should
/// be cleared.</param>
public void CalculateStackUsage(out int pushes, out int pops) => CalculateStackUsage(false, out pushes, out pops);
/// <summary>
/// Calculates stack usage
/// </summary>
/// <param name="methodHasReturnValue"><c>true</c> if method has a return value</param>
/// <param name="pushes">Updated with number of stack pushes</param>
/// <param name="pops">Updated with number of stack pops or <c>-1</c> if the stack should
/// be cleared.</param>
public void CalculateStackUsage(bool methodHasReturnValue, out int pushes, out int pops) {
var opCode = OpCode;
if (opCode.FlowControl == FlowControl.Call)
CalculateStackUsageCall(opCode.Code, out pushes, out pops);
else
CalculateStackUsageNonCall(opCode, methodHasReturnValue, out pushes, out pops);
}
void CalculateStackUsageCall(Code code, out int pushes, out int pops) {
pushes = 0;
pops = 0;
// It doesn't push or pop anything. The stack should be empty when JMP is executed.
if (code == Code.Jmp)
return;
MethodSig sig;
var op = Operand;
if (op is IMethod method)
sig = method.MethodSig;
else
sig = op as MethodSig; // calli instruction
if (sig is null)
return;
bool implicitThis = sig.ImplicitThis;
if (!IsSystemVoid(sig.RetType) || (code == Code.Newobj && sig.HasThis))
pushes++;
pops += sig.Params.Count;
var paramsAfterSentinel = sig.ParamsAfterSentinel;
if (paramsAfterSentinel is not null)
pops += paramsAfterSentinel.Count;
if (implicitThis && code != Code.Newobj)
pops++;
if (code == Code.Calli)
pops++;
}
void CalculateStackUsageNonCall(OpCode opCode, bool hasReturnValue, out int pushes, out int pops) {
switch (opCode.StackBehaviourPush) {
case StackBehaviour.Push0:
pushes = 0;
break;
case StackBehaviour.Push1:
case StackBehaviour.Pushi:
case StackBehaviour.Pushi8:
case StackBehaviour.Pushr4:
case StackBehaviour.Pushr8:
case StackBehaviour.Pushref:
pushes = 1;
break;
case StackBehaviour.Push1_push1:
pushes = 2;
break;
case StackBehaviour.Varpush: // only call, calli, callvirt which are handled elsewhere
default:
pushes = 0;
break;
}
switch (opCode.StackBehaviourPop) {
case StackBehaviour.Pop0:
pops = 0;
break;
case StackBehaviour.Pop1:
case StackBehaviour.Popi:
case StackBehaviour.Popref:
pops = 1;
break;
case StackBehaviour.Pop1_pop1:
case StackBehaviour.Popi_pop1:
case StackBehaviour.Popi_popi:
case StackBehaviour.Popi_popi8:
case StackBehaviour.Popi_popr4:
case StackBehaviour.Popi_popr8:
case StackBehaviour.Popref_pop1:
case StackBehaviour.Popref_popi:
pops = 2;
break;
case StackBehaviour.Popi_popi_popi:
case StackBehaviour.Popref_popi_popi:
case StackBehaviour.Popref_popi_popi8:
case StackBehaviour.Popref_popi_popr4:
case StackBehaviour.Popref_popi_popr8:
case StackBehaviour.Popref_popi_popref:
case StackBehaviour.Popref_popi_pop1:
pops = 3;
break;
case StackBehaviour.PopAll:
pops = -1;
break;
case StackBehaviour.Varpop: // call, calli, callvirt, newobj (all handled elsewhere), and ret
if (hasReturnValue)
pops = 1;
else
pops = 0;
break;
default:
pops = 0;
break;
}
}
/// <summary>
/// Checks whether it's one of the <c>leave</c> instructions
/// </summary>
public bool IsLeave() => OpCode == OpCodes.Leave || OpCode == OpCodes.Leave_S;
/// <summary>
/// Checks whether it's one of the <c>br</c> instructions
/// </summary>
public bool IsBr() => OpCode == OpCodes.Br || OpCode == OpCodes.Br_S;
/// <summary>
/// Checks whether it's one of the <c>brfalse</c> instructions
/// </summary>
public bool IsBrfalse() => OpCode == OpCodes.Brfalse || OpCode == OpCodes.Brfalse_S;
/// <summary>
/// Checks whether it's one of the <c>brtrue</c> instructions
/// </summary>
public bool IsBrtrue() => OpCode == OpCodes.Brtrue || OpCode == OpCodes.Brtrue_S;
/// <summary>
/// Checks whether it's one of the conditional branch instructions (bcc, brtrue, brfalse)
/// </summary>
public bool IsConditionalBranch() {
switch (OpCode.Code) {
case Code.Bge:
case Code.Bge_S:
case Code.Bge_Un:
case Code.Bge_Un_S:
case Code.Blt:
case Code.Blt_S:
case Code.Blt_Un:
case Code.Blt_Un_S:
case Code.Bgt:
case Code.Bgt_S:
case Code.Bgt_Un:
case Code.Bgt_Un_S:
case Code.Ble:
case Code.Ble_S:
case Code.Ble_Un:
case Code.Ble_Un_S:
case Code.Brfalse:
case Code.Brfalse_S:
case Code.Brtrue:
case Code.Brtrue_S:
case Code.Beq:
case Code.Beq_S:
case Code.Bne_Un:
case Code.Bne_Un_S:
return true;
default:
return false;
}
}
/// <summary>
/// Checks whether this is one of the <c>ldc.i4</c> instructions
/// </summary>
public bool IsLdcI4() {
switch (OpCode.Code) {
case Code.Ldc_I4_M1:
case Code.Ldc_I4_0:
case Code.Ldc_I4_1:
case Code.Ldc_I4_2:
case Code.Ldc_I4_3:
case Code.Ldc_I4_4:
case Code.Ldc_I4_5:
case Code.Ldc_I4_6:
case Code.Ldc_I4_7:
case Code.Ldc_I4_8:
case Code.Ldc_I4_S:
case Code.Ldc_I4:
return true;
default:
return false;
}
}
/// <summary>
/// Returns a <c>ldc.i4</c> instruction's operand
/// </summary>
/// <returns>The integer value</returns>
/// <exception cref="InvalidOperationException"><see cref="OpCode"/> isn't one of the
/// <c>ldc.i4</c> opcodes</exception>
public int GetLdcI4Value() =>
OpCode.Code switch {
Code.Ldc_I4_M1 => -1,
Code.Ldc_I4_0 => 0,
Code.Ldc_I4_1 => 1,
Code.Ldc_I4_2 => 2,
Code.Ldc_I4_3 => 3,
Code.Ldc_I4_4 => 4,
Code.Ldc_I4_5 => 5,
Code.Ldc_I4_6 => 6,
Code.Ldc_I4_7 => 7,
Code.Ldc_I4_8 => 8,
Code.Ldc_I4_S => (sbyte)Operand,
Code.Ldc_I4 => (int)Operand,
_ => throw new InvalidOperationException($"Not a ldc.i4 instruction: {this}"),
};
/// <summary>
/// Checks whether it's one of the <c>ldarg</c> instructions, but does <c>not</c> check
/// whether it's one of the <c>ldarga</c> instructions.
/// </summary>
public bool IsLdarg() {
switch (OpCode.Code) {
case Code.Ldarg:
case Code.Ldarg_S:
case Code.Ldarg_0:
case Code.Ldarg_1:
case Code.Ldarg_2:
case Code.Ldarg_3:
return true;
default:
return false;
}
}
/// <summary>
/// Checks whether it's one of the <c>ldloc</c> instructions, but does <c>not</c> check
/// whether it's one of the <c>ldloca</c> instructions.
/// </summary>
public bool IsLdloc() {
switch (OpCode.Code) {
case Code.Ldloc:
case Code.Ldloc_0:
case Code.Ldloc_1:
case Code.Ldloc_2:
case Code.Ldloc_3:
case Code.Ldloc_S:
return true;
default:
return false;
}
}
/// <summary>
/// Checks whether it's one of the <c>starg</c> instructions
/// </summary>
public bool IsStarg() {
switch (OpCode.Code) {
case Code.Starg:
case Code.Starg_S:
return true;
default:
return false;
}
}
/// <summary>
/// Checks whether it's one of the <c>stloc</c> instructions
/// </summary>
public bool IsStloc() {
switch (OpCode.Code) {
case Code.Stloc:
case Code.Stloc_0:
case Code.Stloc_1:
case Code.Stloc_2:
case Code.Stloc_3:
case Code.Stloc_S:
return true;
default:
return false;
}
}
/// <summary>
/// Returns the local if it's a <c>ldloc</c>, <c>stloc</c> or <c>ldloca</c> instruction
/// </summary>
/// <param name="locals">The locals</param>
/// <returns>The local or <c>null</c> if it's not a <c>ldloc</c>, <c>stloc</c> or <c>ldloca</c>
/// instruction or if the local doesn't exist.</returns>
public Local GetLocal(IList<Local> locals) {
int index;
var code = OpCode.Code;
switch (code) {
case Code.Ldloc:
case Code.Ldloc_S:
case Code.Stloc:
case Code.Stloc_S:
case Code.Ldloca:
case Code.Ldloca_S:
return Operand as Local;
case Code.Ldloc_0:
case Code.Ldloc_1:
case Code.Ldloc_2:
case Code.Ldloc_3:
index = code - Code.Ldloc_0;
break;
case Code.Stloc_0:
case Code.Stloc_1:
case Code.Stloc_2:
case Code.Stloc_3:
index = code - Code.Stloc_0;
break;
default:
return null;
}
if ((uint)index < (uint)locals.Count)
return locals[index];
return null;
}
/// <summary>
/// Gets the index of the instruction's parameter operand or <c>-1</c> if the parameter
/// is missing or if it's not an instruction with a parameter operand.
/// </summary>
public int GetParameterIndex() {
switch (OpCode.Code) {
case Code.Ldarg_0: return 0;
case Code.Ldarg_1: return 1;
case Code.Ldarg_2: return 2;
case Code.Ldarg_3: return 3;
case Code.Starg:
case Code.Starg_S:
case Code.Ldarga:
case Code.Ldarga_S:
case Code.Ldarg:
case Code.Ldarg_S:
var parameter = Operand as Parameter;
if (parameter is not null)
return parameter.Index;
break;
}
return -1;
}
/// <summary>
/// Returns a method parameter
/// </summary>
/// <param name="parameters">All parameters</param>
/// <returns>A parameter or <c>null</c> if it doesn't exist</returns>
public Parameter GetParameter(IList<Parameter> parameters) {
int i = GetParameterIndex();
if ((uint)i < (uint)parameters.Count)
return parameters[i];
return null;
}
/// <summary>
/// Returns an argument type
/// </summary>
/// <param name="methodSig">Method signature</param>
/// <param name="declaringType">Declaring type (only needed if it's an instance method)</param>
/// <returns>The type or <c>null</c> if it doesn't exist</returns>
public TypeSig GetArgumentType(MethodSig methodSig, ITypeDefOrRef declaringType) {
if (methodSig is null)
return null;
int index = GetParameterIndex();
if (index == 0 && methodSig.ImplicitThis) {
if (declaringType is null)
return null;
TypeSig declSig;
bool isValueType;
if (declaringType is TypeSpec spec) {
declSig = spec.TypeSig;
isValueType = declSig.IsValueType;
}
else {
// Consistent with ParameterList.UpdateThisParameterType
var td = declaringType.ResolveTypeDef();
if (td is null)
return declaringType.ToTypeSig();
isValueType = td.IsValueType;
ClassOrValueTypeSig cvSig = isValueType ? new ValueTypeSig(td) : new ClassSig(td);
if (td.HasGenericParameters) {
int gpCount = td.GenericParameters.Count;
var genArgs = new List<TypeSig>(gpCount);
for (int i = 0; i < gpCount; i++)
genArgs.Add(new GenericVar(i, td));
declSig = new GenericInstSig(cvSig, genArgs);
}
else
declSig = cvSig;
}
return isValueType ? new ByRefSig(declSig) : declSig;
}
if (methodSig.ImplicitThis)
index--;
if ((uint)index < (uint)methodSig.Params.Count)
return methodSig.Params[index];
return null;
}
/// <summary>
/// Clone this instance. The <see cref="Operand"/> and <see cref="SequencePoint"/> fields
/// are shared by this instance and the created instance.
/// </summary>
public Instruction Clone() =>
new Instruction {
Offset = Offset,
OpCode = OpCode,
Operand = Operand,
SequencePoint = SequencePoint,
};
/// <inheritdoc/>
public override string ToString() => InstructionPrinter.ToString(this);
}
static partial class Extensions {
/// <summary>
/// Gets the opcode or <see cref="OpCodes.UNKNOWN1"/> if <paramref name="self"/> is <c>null</c>
/// </summary>
/// <param name="self">this</param>
/// <returns></returns>
public static OpCode GetOpCode(this Instruction self) => self?.OpCode ?? OpCodes.UNKNOWN1;
/// <summary>
/// Gets the operand or <c>null</c> if <paramref name="self"/> is <c>null</c>
/// </summary>
/// <param name="self">this</param>
/// <returns></returns>
public static object GetOperand(this Instruction self) => self?.Operand;
/// <summary>
/// Gets the offset or 0 if <paramref name="self"/> is <c>null</c>
/// </summary>
/// <param name="self">this</param>
/// <returns></returns>
public static uint GetOffset(this Instruction self) => self?.Offset ?? 0;
/// <summary>
/// Gets the sequence point or <c>null</c> if <paramref name="self"/> is <c>null</c>
/// </summary>
/// <param name="self">this</param>
/// <returns></returns>
public static dnlib.DotNet.Pdb.SequencePoint GetSequencePoint(this Instruction self) => self?.SequencePoint;
}
}

View File

@ -1,168 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System.Collections.Generic;
using System.Text;
namespace dnlib.DotNet.Emit {
/// <summary>
/// Converts instructions to strings
/// </summary>
public static class InstructionPrinter {
/// <summary>
/// Converts an instruction to a string
/// </summary>
/// <param name="instr">The instruction</param>
/// <returns>The result</returns>
public static string ToString(Instruction instr) {
if (instr is null)
return string.Empty;
var sb = new StringBuilder();
sb.Append($"IL_{instr.Offset:X4}: ");
sb.Append(instr.OpCode.Name);
AddOperandString(sb, instr, " ");
return sb.ToString();
}
/// <summary>
/// Gets the instruction's operand as a string
/// </summary>
/// <param name="instr">The instruction</param>
/// <returns>The operand as a string</returns>
public static string GetOperandString(Instruction instr) {
var sb = new StringBuilder();
AddOperandString(sb, instr, string.Empty);
return sb.ToString();
}
/// <summary>
/// Add an instruction's operand to <paramref name="sb"/>
/// </summary>
/// <param name="sb">Place result here</param>
/// <param name="instr">The instruction</param>
public static void AddOperandString(StringBuilder sb, Instruction instr) => AddOperandString(sb, instr, string.Empty);
/// <summary>
/// Add an instruction's operand to <paramref name="sb"/>
/// </summary>
/// <param name="sb">Place result here</param>
/// <param name="instr">The instruction</param>
/// <param name="extra">A string that will be added before the operand, if there's
/// an operand.</param>
public static void AddOperandString(StringBuilder sb, Instruction instr, string extra) {
var op = instr.Operand;
switch (instr.OpCode.OperandType) {
case OperandType.InlineBrTarget:
case OperandType.ShortInlineBrTarget:
sb.Append(extra);
AddInstructionTarget(sb, op as Instruction);
break;
case OperandType.InlineField:
case OperandType.InlineMethod:
case OperandType.InlineTok:
case OperandType.InlineType:
sb.Append(extra);
if (op is IFullName)
sb.Append((op as IFullName).FullName);
else if (op is not null)
sb.Append(op.ToString());
else
sb.Append("null");
break;
case OperandType.InlineI:
case OperandType.InlineI8:
case OperandType.InlineR:
case OperandType.ShortInlineI:
case OperandType.ShortInlineR:
sb.Append($"{extra}{op}");
break;
case OperandType.InlineSig:
sb.Append(extra);
FullNameFactory.MethodFullNameSB(null, (UTF8String)null, op as MethodSig, null, null, null, sb);
break;
case OperandType.InlineString:
sb.Append(extra);
EscapeString(sb, op as string, true);
break;
case OperandType.InlineSwitch:
var targets = op as IList<Instruction>;
if (targets is null)
sb.Append("null");
else {
sb.Append('(');
for (int i = 0; i < targets.Count; i++) {
if (i != 0)
sb.Append(',');
AddInstructionTarget(sb, targets[i]);
}
sb.Append(')');
}
break;
case OperandType.InlineVar:
case OperandType.ShortInlineVar:
sb.Append(extra);
if (op is null)
sb.Append("null");
else
sb.Append(op.ToString());
break;
case OperandType.InlineNone:
case OperandType.InlinePhi:
default:
break;
}
}
static void AddInstructionTarget(StringBuilder sb, Instruction targetInstr) {
if (targetInstr is null)
sb.Append("null");
else
sb.Append($"IL_{targetInstr.Offset:X4}");
}
static void EscapeString(StringBuilder sb, string s, bool addQuotes) {
if (s is null) {
sb.Append("null");
return;
}
if (addQuotes)
sb.Append('"');
foreach (var c in s) {
if ((int)c < 0x20) {
switch (c) {
case '\a': sb.Append(@"\a"); break;
case '\b': sb.Append(@"\b"); break;
case '\f': sb.Append(@"\f"); break;
case '\n': sb.Append(@"\n"); break;
case '\r': sb.Append(@"\r"); break;
case '\t': sb.Append(@"\t"); break;
case '\v': sb.Append(@"\v"); break;
default:
sb.Append($@"\u{(int)c:X4}");
break;
}
}
else if (c == '\\' || c == '"') {
sb.Append('\\');
sb.Append(c);
}
else
sb.Append(c);
}
if (addQuotes)
sb.Append('"');
}
}
}

View File

@ -1,44 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System;
using System.Runtime.Serialization;
namespace dnlib.DotNet.Emit {
/// <summary>
/// Thrown when invalid data is detected while parsing a .NET method
/// </summary>
[Serializable]
public class InvalidMethodException : Exception {
/// <summary>
/// Default constructor
/// </summary>
public InvalidMethodException() {
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="msg">Error message</param>
public InvalidMethodException(string msg)
: base(msg) {
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="msg">Error message</param>
/// <param name="innerException">The inner exception or <c>null</c> if none</param>
public InvalidMethodException(string msg, Exception innerException)
: base(msg, innerException) {
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="info"></param>
/// <param name="context"></param>
protected InvalidMethodException(SerializationInfo info, StreamingContext context)
: base(info, context) {
}
}
}

View File

@ -1,195 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System.Collections.Generic;
using System.Diagnostics;
using dnlib.Utils;
using dnlib.DotNet.Pdb;
namespace dnlib.DotNet.Emit {
/// <summary>
/// A collection of <see cref="Local"/>s
/// </summary>
[DebuggerDisplay("Count = {Count}")]
[DebuggerTypeProxy(typeof(LocalList_CollectionDebugView))]
public sealed class LocalList : IListListener<Local>, IList<Local> {
readonly LazyList<Local> locals;
/// <summary>
/// Gets the number of locals
/// </summary>
public int Count => locals.Count;
/// <summary>
/// Gets the list of locals
/// </summary>
public IList<Local> Locals => locals;
/// <summary>
/// Gets the N'th local
/// </summary>
/// <param name="index">The local index</param>
public Local this[int index] {
get => locals[index];
set => locals[index] = value;
}
/// <summary>
/// Default constructor
/// </summary>
public LocalList() => locals = new LazyList<Local>(this);
/// <summary>
/// Constructor
/// </summary>
/// <param name="locals">All locals that will be owned by this instance</param>
public LocalList(IList<Local> locals) {
this.locals = new LazyList<Local>(this);
for (int i = 0; i < locals.Count; i++)
this.locals.Add(locals[i]);
}
/// <summary>
/// Adds a new local and then returns it
/// </summary>
/// <param name="local">The local that should be added to the list</param>
/// <returns>The input is always returned</returns>
public Local Add(Local local) {
locals.Add(local);
return local;
}
/// <inheritdoc/>
void IListListener<Local>.OnLazyAdd(int index, ref Local value) {
}
/// <inheritdoc/>
void IListListener<Local>.OnAdd(int index, Local value) => value.Index = index;
/// <inheritdoc/>
void IListListener<Local>.OnRemove(int index, Local value) => value.Index = -1;
/// <inheritdoc/>
void IListListener<Local>.OnResize(int index) {
for (int i = index; i < locals.Count_NoLock; i++)
locals.Get_NoLock(i).Index = i;
}
/// <inheritdoc/>
void IListListener<Local>.OnClear() {
foreach (var local in locals.GetEnumerable_NoLock())
local.Index = -1;
}
/// <inheritdoc/>
public int IndexOf(Local item) => locals.IndexOf(item);
/// <inheritdoc/>
public void Insert(int index, Local item) => locals.Insert(index, item);
/// <inheritdoc/>
public void RemoveAt(int index) => locals.RemoveAt(index);
void ICollection<Local>.Add(Local item) => locals.Add(item);
/// <inheritdoc/>
public void Clear() => locals.Clear();
/// <inheritdoc/>
public bool Contains(Local item) => locals.Contains(item);
/// <inheritdoc/>
public void CopyTo(Local[] array, int arrayIndex) => locals.CopyTo(array, arrayIndex);
/// <inheritdoc/>
public bool IsReadOnly => false;
/// <inheritdoc/>
public bool Remove(Local item) => locals.Remove(item);
/// <inheritdoc/>
public LazyList<Local>.Enumerator GetEnumerator() => locals.GetEnumerator();
IEnumerator<Local> IEnumerable<Local>.GetEnumerator() => locals.GetEnumerator();
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => ((IEnumerable<Local>)this).GetEnumerator();
}
/// <summary>
/// A method local
/// </summary>
public sealed class Local : IVariable {
TypeSig typeSig;
int index;
string name;
PdbLocalAttributes attributes;
/// <summary>
/// Gets/sets the type of the local
/// </summary>
public TypeSig Type {
get => typeSig;
set => typeSig = value;
}
/// <summary>
/// Local index
/// </summary>
public int Index {
get => index;
internal set => index = value;
}
/// <summary>
/// Gets the name. This property is obsolete, use <see cref="PdbLocal"/> to get/set the name stored in the PDB file.
/// </summary>
public string Name {
get => name;
set => name = value;
}
/// <summary>
/// Gets the attributes. This property is obsolete, use <see cref="PdbLocal"/> to get/set the attributes stored in the PDB file.
/// </summary>
public PdbLocalAttributes Attributes {
get => attributes;
set => attributes = value;
}
internal void SetName(string name) => this.name = name;
internal void SetAttributes(PdbLocalAttributes attributes) => this.attributes = attributes;
/// <summary>
/// Constructor
/// </summary>
/// <param name="typeSig">The type</param>
public Local(TypeSig typeSig) => this.typeSig = typeSig;
/// <summary>
/// Constructor
/// </summary>
/// <param name="typeSig">The type</param>
/// <param name="name">Name of local</param>
public Local(TypeSig typeSig, string name) {
this.typeSig = typeSig;
this.name = name;
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="typeSig">The type</param>
/// <param name="name">Name of local</param>
/// <param name="index">Index, should only be used if you don't add it to the locals list</param>
public Local(TypeSig typeSig, string name, int index) {
this.typeSig = typeSig;
this.name = name;
this.index = index;
}
/// <inheritdoc/>
public override string ToString() {
var n = name;
if (string.IsNullOrEmpty(n))
return $"V_{Index}";
return n;
}
}
}

View File

@ -1,216 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System.Collections.Generic;
using dnlib.DotNet.Pdb;
using dnlib.PE;
namespace dnlib.DotNet.Emit {
/// <summary>
/// Method body base class
/// </summary>
public abstract class MethodBody {
}
/// <summary>
/// A native method body
/// </summary>
public sealed class NativeMethodBody : MethodBody {
RVA rva;
/// <summary>
/// Gets/sets the RVA of the native method body
/// </summary>
public RVA RVA {
get => rva;
set => rva = value;
}
/// <summary>
/// Default constructor
/// </summary>
public NativeMethodBody() {
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="rva">RVA of method body</param>
public NativeMethodBody(RVA rva) => this.rva = rva;
}
/// <summary>
/// CIL (managed code) body
/// </summary>
public sealed class CilBody : MethodBody {
bool keepOldMaxStack;
bool initLocals;
byte headerSize;
ushort maxStack;
uint localVarSigTok;
readonly IList<Instruction> instructions;
readonly IList<ExceptionHandler> exceptionHandlers;
readonly LocalList localList;
/// <summary>
/// Size of a small header
/// </summary>
public const byte SMALL_HEADER_SIZE = 1;
/// <summary>
/// Gets/sets a flag indicating whether the original max stack value should be used.
/// </summary>
public bool KeepOldMaxStack {
get => keepOldMaxStack;
set => keepOldMaxStack = value;
}
/// <summary>
/// Gets/sets the init locals flag. This is only valid if the method has any locals.
/// </summary>
public bool InitLocals {
get => initLocals;
set => initLocals = value;
}
/// <summary>
/// Gets/sets the size in bytes of the method body header. The instructions immediately follow
/// the header.
/// </summary>
public byte HeaderSize {
get => headerSize;
set => headerSize = value;
}
/// <summary>
/// <c>true</c> if it was a small body header (<see cref="HeaderSize"/> is <c>1</c>)
/// </summary>
public bool IsSmallHeader => headerSize == SMALL_HEADER_SIZE;
/// <summary>
/// <c>true</c> if it was a big body header
/// </summary>
public bool IsBigHeader => headerSize != SMALL_HEADER_SIZE;
/// <summary>
/// Gets/sets max stack value from the fat method header.
/// </summary>
public ushort MaxStack {
get => maxStack;
set => maxStack = value;
}
/// <summary>
/// Gets/sets the locals metadata token
/// </summary>
public uint LocalVarSigTok {
get => localVarSigTok;
set => localVarSigTok = value;
}
/// <summary>
/// <c>true</c> if <see cref="Instructions"/> is not empty
/// </summary>
public bool HasInstructions => instructions.Count > 0;
/// <summary>
/// Gets the instructions
/// </summary>
public IList<Instruction> Instructions => instructions;
/// <summary>
/// <c>true</c> if <see cref="ExceptionHandlers"/> is not empty
/// </summary>
public bool HasExceptionHandlers => exceptionHandlers.Count > 0;
/// <summary>
/// Gets the exception handlers
/// </summary>
public IList<ExceptionHandler> ExceptionHandlers => exceptionHandlers;
/// <summary>
/// <c>true</c> if <see cref="Variables"/> is not empty
/// </summary>
public bool HasVariables => localList.Count > 0;
/// <summary>
/// Gets the locals
/// </summary>
public LocalList Variables => localList;
/// <summary>
/// Gets/sets the PDB method. This is <c>null</c> if no PDB has been loaded or if there's
/// no PDB info for this method.
/// </summary>
public PdbMethod PdbMethod {
get => pdbMethod;
set => pdbMethod = value;
}
PdbMethod pdbMethod;
/// <summary>
/// <c>true</c> if <see cref="PdbMethod"/> is not <c>null</c>
/// </summary>
public bool HasPdbMethod => PdbMethod is not null;
/// <summary>
/// Gets the total size of the body in the PE file, including header, IL bytes, and exception handlers.
/// This property returns 0 if the size is unknown.
/// </summary>
internal uint MetadataBodySize { get; set; }
/// <summary>
/// Default constructor
/// </summary>
public CilBody() {
initLocals = true;
instructions = new List<Instruction>();
exceptionHandlers = new List<ExceptionHandler>();
localList = new LocalList();
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="initLocals">Init locals flag</param>
/// <param name="instructions">All instructions. This instance will own the list.</param>
/// <param name="exceptionHandlers">All exception handlers. This instance will own the list.</param>
/// <param name="locals">All locals. This instance will own the locals in the list.</param>
public CilBody(bool initLocals, IList<Instruction> instructions, IList<ExceptionHandler> exceptionHandlers, IList<Local> locals) {
this.initLocals = initLocals;
this.instructions = instructions;
this.exceptionHandlers = exceptionHandlers;
localList = new LocalList(locals);
}
/// <summary>
/// Shorter instructions are converted to the longer form, eg. <c>Ldc_I4_1</c> is
/// converted to <c>Ldc_I4</c> with a <c>1</c> as the operand.
/// </summary>
/// <param name="parameters">All method parameters, including the hidden 'this' parameter
/// if it's an instance method. Use <see cref="MethodDef.Parameters"/>.</param>
public void SimplifyMacros(IList<Parameter> parameters) => instructions.SimplifyMacros(localList, parameters);
/// <summary>
/// Optimizes instructions by using the shorter form if possible. Eg. <c>Ldc_I4</c> <c>1</c>
/// will be replaced with <c>Ldc_I4_1</c>.
/// </summary>
public void OptimizeMacros() => instructions.OptimizeMacros();
/// <summary>
/// Short branch instructions are converted to the long form, eg. <c>Beq_S</c> is
/// converted to <c>Beq</c>.
/// </summary>
public void SimplifyBranches() => instructions.SimplifyBranches();
/// <summary>
/// Optimizes branches by using the smallest possible branch
/// </summary>
public void OptimizeBranches() => instructions.OptimizeBranches();
/// <summary>
/// Updates each instruction's offset
/// </summary>
/// <returns>Total size in bytes of all instructions</returns>
public uint UpdateInstructionOffsets() => instructions.UpdateInstructionOffsets();
}
}

View File

@ -1,542 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System.Collections.Generic;
using System.IO;
using dnlib.IO;
namespace dnlib.DotNet.Emit {
/// <summary>
/// Reads strings from #US heap
/// </summary>
public interface IStringResolver {
/// <summary>
/// Reads a string from the #US heap
/// </summary>
/// <param name="token">String token</param>
/// <returns>A string</returns>
string ReadUserString(uint token);
}
/// <summary>
/// Resolves instruction operands
/// </summary>
public interface IInstructionOperandResolver : ITokenResolver, IStringResolver {
}
public static partial class Extensions {
/// <summary>
/// Resolves a token
/// </summary>
/// <param name="self">An <see cref="IInstructionOperandResolver"/> object</param>
/// <param name="token">The metadata token</param>
/// <returns>A <see cref="IMDTokenProvider"/> or <c>null</c> if <paramref name="token"/> is invalid</returns>
public static IMDTokenProvider ResolveToken(this IInstructionOperandResolver self, uint token) =>
self.ResolveToken(token, new GenericParamContext());
}
/// <summary>
/// Reads a .NET method body (header, locals, instructions, exception handlers)
/// </summary>
public sealed class MethodBodyReader : MethodBodyReaderBase {
readonly IInstructionOperandResolver opResolver;
bool hasReadHeader;
byte headerSize;
ushort flags;
ushort maxStack;
uint codeSize;
uint localVarSigTok;
uint startOfHeader;
uint totalBodySize;
DataReader? exceptionsReader;
readonly GenericParamContext gpContext;
/// <summary>
/// Creates a CIL method body or returns an empty one if <paramref name="reader"/> doesn't
/// point to the start of a valid CIL method body.
/// </summary>
/// <param name="opResolver">The operand resolver</param>
/// <param name="reader">A reader positioned at the start of a .NET method body</param>
/// <param name="method">Use parameters from this method</param>
public static CilBody CreateCilBody(IInstructionOperandResolver opResolver, DataReader reader, MethodDef method) =>
CreateCilBody(opResolver, reader, null, method.Parameters, new GenericParamContext());
/// <summary>
/// Creates a CIL method body or returns an empty one if <paramref name="reader"/> doesn't
/// point to the start of a valid CIL method body.
/// </summary>
/// <param name="opResolver">The operand resolver</param>
/// <param name="reader">A reader positioned at the start of a .NET method body</param>
/// <param name="method">Use parameters from this method</param>
/// <param name="gpContext">Generic parameter context</param>
public static CilBody CreateCilBody(IInstructionOperandResolver opResolver, DataReader reader, MethodDef method, GenericParamContext gpContext) =>
CreateCilBody(opResolver, reader, null, method.Parameters, gpContext);
/// <summary>
/// Creates a CIL method body or returns an empty one if <paramref name="reader"/> doesn't
/// point to the start of a valid CIL method body.
/// </summary>
/// <param name="opResolver">The operand resolver</param>
/// <param name="reader">A reader positioned at the start of a .NET method body</param>
/// <param name="parameters">Method parameters</param>
public static CilBody CreateCilBody(IInstructionOperandResolver opResolver, DataReader reader, IList<Parameter> parameters) =>
CreateCilBody(opResolver, reader, null, parameters, new GenericParamContext());
/// <summary>
/// Creates a CIL method body or returns an empty one if <paramref name="reader"/> doesn't
/// point to the start of a valid CIL method body.
/// </summary>
/// <param name="opResolver">The operand resolver</param>
/// <param name="reader">A reader positioned at the start of a .NET method body</param>
/// <param name="parameters">Method parameters</param>
/// <param name="gpContext">Generic parameter context</param>
public static CilBody CreateCilBody(IInstructionOperandResolver opResolver, DataReader reader, IList<Parameter> parameters, GenericParamContext gpContext) =>
CreateCilBody(opResolver, reader, null, parameters, gpContext);
/// <summary>
/// Creates a CIL method body or returns an empty one if <paramref name="reader"/> doesn't
/// point to the start of a valid CIL method body.
/// </summary>
/// <param name="opResolver">The operand resolver</param>
/// <param name="reader">A reader positioned at the start of a .NET method body</param>
/// <param name="parameters">Method parameters</param>
/// <param name="gpContext">Generic parameter context</param>
/// <param name="context">The module context</param>
public static CilBody CreateCilBody(IInstructionOperandResolver opResolver, DataReader reader, IList<Parameter> parameters, GenericParamContext gpContext, ModuleContext context) =>
CreateCilBody(opResolver, reader, null, parameters, gpContext, context);
/// <summary>
/// Creates a CIL method body or returns an empty one if <paramref name="code"/> is not
/// a valid CIL method body.
/// </summary>
/// <param name="opResolver">The operand resolver</param>
/// <param name="code">All code</param>
/// <param name="exceptions">Exceptions or <c>null</c> if all exception handlers are in
/// <paramref name="code"/></param>
/// <param name="parameters">Method parameters</param>
public static CilBody CreateCilBody(IInstructionOperandResolver opResolver, byte[] code, byte[] exceptions, IList<Parameter> parameters) =>
CreateCilBody(opResolver, ByteArrayDataReaderFactory.CreateReader(code), exceptions is null ? (DataReader?)null : ByteArrayDataReaderFactory.CreateReader(exceptions), parameters, new GenericParamContext());
/// <summary>
/// Creates a CIL method body or returns an empty one if <paramref name="code"/> is not
/// a valid CIL method body.
/// </summary>
/// <param name="opResolver">The operand resolver</param>
/// <param name="code">All code</param>
/// <param name="exceptions">Exceptions or <c>null</c> if all exception handlers are in
/// <paramref name="code"/></param>
/// <param name="parameters">Method parameters</param>
/// <param name="gpContext">Generic parameter context</param>
public static CilBody CreateCilBody(IInstructionOperandResolver opResolver, byte[] code, byte[] exceptions, IList<Parameter> parameters, GenericParamContext gpContext) =>
CreateCilBody(opResolver, ByteArrayDataReaderFactory.CreateReader(code), exceptions is null ? (DataReader?)null : ByteArrayDataReaderFactory.CreateReader(exceptions), parameters, gpContext);
/// <summary>
/// Creates a CIL method body or returns an empty one if <paramref name="codeReader"/> doesn't
/// point to the start of a valid CIL method body.
/// </summary>
/// <param name="opResolver">The operand resolver</param>
/// <param name="codeReader">A reader positioned at the start of a .NET method body</param>
/// <param name="ehReader">Exception handler reader or <c>null</c> if exceptions aren't
/// present or if <paramref name="codeReader"/> contains the exception handlers</param>
/// <param name="parameters">Method parameters</param>
public static CilBody CreateCilBody(IInstructionOperandResolver opResolver, DataReader codeReader, DataReader? ehReader, IList<Parameter> parameters) =>
CreateCilBody(opResolver, codeReader, ehReader, parameters, new GenericParamContext());
/// <summary>
/// Creates a CIL method body or returns an empty one if <paramref name="codeReader"/> doesn't
/// point to the start of a valid CIL method body.
/// </summary>
/// <param name="opResolver">The operand resolver</param>
/// <param name="codeReader">A reader positioned at the start of a .NET method body</param>
/// <param name="ehReader">Exception handler reader or <c>null</c> if exceptions aren't
/// present or if <paramref name="codeReader"/> contains the exception handlers</param>
/// <param name="parameters">Method parameters</param>
/// <param name="gpContext">Generic parameter context</param>
public static CilBody CreateCilBody(IInstructionOperandResolver opResolver, DataReader codeReader, DataReader? ehReader, IList<Parameter> parameters, GenericParamContext gpContext) =>
CreateCilBody(opResolver, codeReader, ehReader, parameters, gpContext, null);
/// <summary>
/// Creates a CIL method body or returns an empty one if <paramref name="codeReader"/> doesn't
/// point to the start of a valid CIL method body.
/// </summary>
/// <param name="opResolver">The operand resolver</param>
/// <param name="codeReader">A reader positioned at the start of a .NET method body</param>
/// <param name="ehReader">Exception handler reader or <c>null</c> if exceptions aren't
/// present or if <paramref name="codeReader"/> contains the exception handlers</param>
/// <param name="parameters">Method parameters</param>
/// <param name="gpContext">Generic parameter context</param>
/// <param name="context">The module context</param>
public static CilBody CreateCilBody(IInstructionOperandResolver opResolver, DataReader codeReader, DataReader? ehReader, IList<Parameter> parameters, GenericParamContext gpContext, ModuleContext context) {
var mbReader = new MethodBodyReader(opResolver, codeReader, ehReader, parameters, gpContext, context);
if (!mbReader.Read())
return new CilBody();
return mbReader.CreateCilBody();
}
/// <summary>
/// Creates a CIL method body or returns an empty one if <paramref name="code"/> is not
/// a valid CIL method body.
/// </summary>
/// <param name="opResolver">The operand resolver</param>
/// <param name="code">All code</param>
/// <param name="exceptions">Exceptions or <c>null</c> if all exception handlers are in
/// <paramref name="code"/></param>
/// <param name="parameters">Method parameters</param>
/// <param name="flags">Method header flags, eg. 2 if tiny method</param>
/// <param name="maxStack">Max stack</param>
/// <param name="codeSize">Code size</param>
/// <param name="localVarSigTok">Local variable signature token or 0 if none</param>
public static CilBody CreateCilBody(IInstructionOperandResolver opResolver, byte[] code, byte[] exceptions, IList<Parameter> parameters, ushort flags, ushort maxStack, uint codeSize, uint localVarSigTok) =>
CreateCilBody(opResolver, code, exceptions, parameters, flags, maxStack, codeSize, localVarSigTok, new GenericParamContext());
/// <summary>
/// Creates a CIL method body or returns an empty one if <paramref name="code"/> is not
/// a valid CIL method body.
/// </summary>
/// <param name="opResolver">The operand resolver</param>
/// <param name="code">All code</param>
/// <param name="exceptions">Exceptions or <c>null</c> if all exception handlers are in
/// <paramref name="code"/></param>
/// <param name="parameters">Method parameters</param>
/// <param name="flags">Method header flags, eg. 2 if tiny method</param>
/// <param name="maxStack">Max stack</param>
/// <param name="codeSize">Code size</param>
/// <param name="localVarSigTok">Local variable signature token or 0 if none</param>
/// <param name="gpContext">Generic parameter context</param>
public static CilBody CreateCilBody(IInstructionOperandResolver opResolver, byte[] code, byte[] exceptions, IList<Parameter> parameters, ushort flags, ushort maxStack, uint codeSize, uint localVarSigTok, GenericParamContext gpContext) =>
CreateCilBody(opResolver, code, exceptions, parameters, flags, maxStack, codeSize, localVarSigTok, gpContext, null);
/// <summary>
/// Creates a CIL method body or returns an empty one if <paramref name="code"/> is not
/// a valid CIL method body.
/// </summary>
/// <param name="opResolver">The operand resolver</param>
/// <param name="code">All code</param>
/// <param name="exceptions">Exceptions or <c>null</c> if all exception handlers are in
/// <paramref name="code"/></param>
/// <param name="parameters">Method parameters</param>
/// <param name="flags">Method header flags, eg. 2 if tiny method</param>
/// <param name="maxStack">Max stack</param>
/// <param name="codeSize">Code size</param>
/// <param name="localVarSigTok">Local variable signature token or 0 if none</param>
/// <param name="gpContext">Generic parameter context</param>
/// <param name="context">The module context</param>
public static CilBody CreateCilBody(IInstructionOperandResolver opResolver, byte[] code, byte[] exceptions, IList<Parameter> parameters, ushort flags, ushort maxStack, uint codeSize, uint localVarSigTok, GenericParamContext gpContext, ModuleContext context) {
var codeReader = ByteArrayDataReaderFactory.CreateReader(code);
var ehReader = exceptions is null ? (DataReader?)null : ByteArrayDataReaderFactory.CreateReader(exceptions);
var mbReader = new MethodBodyReader(opResolver, codeReader, ehReader, parameters, gpContext, context);
mbReader.SetHeader(flags, maxStack, codeSize, localVarSigTok);
if (!mbReader.Read())
return new CilBody();
return mbReader.CreateCilBody();
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="opResolver">The operand resolver</param>
/// <param name="reader">A reader positioned at the start of a .NET method body</param>
/// <param name="method">Use parameters from this method</param>
public MethodBodyReader(IInstructionOperandResolver opResolver, DataReader reader, MethodDef method)
: this(opResolver, reader, null, method.Parameters, new GenericParamContext()) {
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="opResolver">The operand resolver</param>
/// <param name="reader">A reader positioned at the start of a .NET method body</param>
/// <param name="method">Use parameters from this method</param>
/// <param name="gpContext">Generic parameter context</param>
public MethodBodyReader(IInstructionOperandResolver opResolver, DataReader reader, MethodDef method, GenericParamContext gpContext)
: this(opResolver, reader, null, method.Parameters, gpContext) {
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="opResolver">The operand resolver</param>
/// <param name="reader">A reader positioned at the start of a .NET method body</param>
/// <param name="parameters">Method parameters</param>
public MethodBodyReader(IInstructionOperandResolver opResolver, DataReader reader, IList<Parameter> parameters)
: this(opResolver, reader, null, parameters, new GenericParamContext()) {
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="opResolver">The operand resolver</param>
/// <param name="reader">A reader positioned at the start of a .NET method body</param>
/// <param name="parameters">Method parameters</param>
/// <param name="gpContext">Generic parameter context</param>
public MethodBodyReader(IInstructionOperandResolver opResolver, DataReader reader, IList<Parameter> parameters, GenericParamContext gpContext)
: this(opResolver, reader, null, parameters, gpContext) {
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="opResolver">The operand resolver</param>
/// <param name="codeReader">A reader positioned at the start of a .NET method body</param>
/// <param name="ehReader">Exception handler reader or <c>null</c> if exceptions aren't
/// present or if <paramref name="codeReader"/> contains the exception handlers</param>
/// <param name="parameters">Method parameters</param>
public MethodBodyReader(IInstructionOperandResolver opResolver, DataReader codeReader, DataReader? ehReader, IList<Parameter> parameters)
: this(opResolver, codeReader, ehReader, parameters, new GenericParamContext()) {
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="opResolver">The operand resolver</param>
/// <param name="codeReader">A reader positioned at the start of a .NET method body</param>
/// <param name="ehReader">Exception handler reader or <c>null</c> if exceptions aren't
/// present or if <paramref name="codeReader"/> contains the exception handlers</param>
/// <param name="parameters">Method parameters</param>
/// <param name="gpContext">Generic parameter context</param>
public MethodBodyReader(IInstructionOperandResolver opResolver, DataReader codeReader, DataReader? ehReader, IList<Parameter> parameters, GenericParamContext gpContext)
: this(opResolver, codeReader, ehReader, parameters, gpContext, null) {
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="opResolver">The operand resolver</param>
/// <param name="codeReader">A reader positioned at the start of a .NET method body</param>
/// <param name="ehReader">Exception handler reader or <c>null</c> if exceptions aren't
/// present or if <paramref name="codeReader"/> contains the exception handlers</param>
/// <param name="parameters">Method parameters</param>
/// <param name="gpContext">Generic parameter context</param>
/// <param name="context">Module context</param>
public MethodBodyReader(IInstructionOperandResolver opResolver, DataReader codeReader, DataReader? ehReader, IList<Parameter> parameters, GenericParamContext gpContext, ModuleContext context)
: base(codeReader, parameters, context) {
this.opResolver = opResolver;
exceptionsReader = ehReader;
this.gpContext = gpContext;
startOfHeader = uint.MaxValue;
}
/// <summary>
/// Initializes the method header
/// </summary>
/// <param name="flags">Header flags, eg. 2 if it's a tiny method</param>
/// <param name="maxStack">Max stack</param>
/// <param name="codeSize">Code size</param>
/// <param name="localVarSigTok">Local variable signature token</param>
void SetHeader(ushort flags, ushort maxStack, uint codeSize, uint localVarSigTok) {
hasReadHeader = true;
this.flags = flags;
this.maxStack = maxStack;
this.codeSize = codeSize;
this.localVarSigTok = localVarSigTok;
}
/// <summary>
/// Reads the method body header, locals, all instructions, and the exception handlers (if any)
/// </summary>
/// <returns><c>true</c> if it worked, and <c>false</c> if something failed</returns>
public bool Read() {
try {
if (!ReadHeader())
return false;
SetLocals(ReadLocals());
ReadInstructions();
ReadExceptionHandlers(out totalBodySize);
return true;
}
catch (InvalidMethodException) {
return false;
}
catch (IOException) {
return false;
}
}
/// <summary>
/// Reads the method header
/// </summary>
bool ReadHeader() {
if (hasReadHeader)
return true;
hasReadHeader = true;
startOfHeader = reader.Position;
byte b = reader.ReadByte();
switch (b & 7) {
case 2:
case 6:
// Tiny header. [7:2] = code size, max stack is 8, no locals or exception handlers
flags = 2;
maxStack = 8;
codeSize = (uint)(b >> 2);
localVarSigTok = 0;
headerSize = 1;
break;
case 3:
// Fat header. Can have locals and exception handlers
flags = (ushort)((reader.ReadByte() << 8) | b);
headerSize = (byte)(flags >> 12);
maxStack = reader.ReadUInt16();
codeSize = reader.ReadUInt32();
localVarSigTok = reader.ReadUInt32();
// The CLR allows the code to start inside the method header. But if it does,
// the CLR doesn't read any exceptions.
reader.Position = reader.Position - 12 + headerSize * 4U;
if (headerSize < 3)
flags &= 0xFFF7;
headerSize *= 4;
break;
default:
return false;
}
if ((ulong)reader.Position + codeSize > reader.Length)
return false;
return true;
}
/// <summary>
/// Reads the locals
/// </summary>
/// <returns>All locals or <c>null</c> if there are none</returns>
IList<TypeSig> ReadLocals() {
var standAloneSig = opResolver.ResolveToken(localVarSigTok, gpContext) as StandAloneSig;
if (standAloneSig is null)
return null;
var localSig = standAloneSig.LocalSig;
if (localSig is null)
return null;
return localSig.Locals;
}
/// <summary>
/// Reads all instructions
/// </summary>
void ReadInstructions() => ReadInstructionsNumBytes(codeSize);
/// <inheritdoc/>
protected override IField ReadInlineField(Instruction instr) => opResolver.ResolveToken(reader.ReadUInt32(), gpContext) as IField;
/// <inheritdoc/>
protected override IMethod ReadInlineMethod(Instruction instr) => opResolver.ResolveToken(reader.ReadUInt32(), gpContext) as IMethod;
/// <inheritdoc/>
protected override MethodSig ReadInlineSig(Instruction instr) {
var standAloneSig = opResolver.ResolveToken(reader.ReadUInt32(), gpContext) as StandAloneSig;
if (standAloneSig is null)
return null;
var sig = standAloneSig.MethodSig;
if (sig is not null)
sig.OriginalToken = standAloneSig.MDToken.Raw;
return sig;
}
/// <inheritdoc/>
protected override string ReadInlineString(Instruction instr) => opResolver.ReadUserString(reader.ReadUInt32()) ?? string.Empty;
/// <inheritdoc/>
protected override ITokenOperand ReadInlineTok(Instruction instr) => opResolver.ResolveToken(reader.ReadUInt32(), gpContext) as ITokenOperand;
/// <inheritdoc/>
protected override ITypeDefOrRef ReadInlineType(Instruction instr) => opResolver.ResolveToken(reader.ReadUInt32(), gpContext) as ITypeDefOrRef;
/// <summary>
/// Reads all exception handlers
/// </summary>
void ReadExceptionHandlers(out uint totalBodySize) {
if ((flags & 8) == 0) {
totalBodySize = startOfHeader == uint.MaxValue ? 0 : reader.Position - startOfHeader;
return;
}
bool canSaveTotalBodySize;
DataReader ehReader;
if (exceptionsReader is not null) {
canSaveTotalBodySize = false;
ehReader = exceptionsReader.Value;
}
else {
canSaveTotalBodySize = true;
ehReader = reader;
ehReader.Position = (ehReader.Position + 3) & ~3U;
}
// Only read the first one. Any others aren't used.
byte b = ehReader.ReadByte();
if ((b & 0x3F) != 1) {
totalBodySize = startOfHeader == uint.MaxValue ? 0 : reader.Position - startOfHeader;
return; // Not exception handler clauses
}
if ((b & 0x40) != 0)
ReadFatExceptionHandlers(ref ehReader);
else
ReadSmallExceptionHandlers(ref ehReader);
if (canSaveTotalBodySize)
totalBodySize = startOfHeader == uint.MaxValue ? 0 : ehReader.Position - startOfHeader;
else
totalBodySize = 0;
}
void ReadFatExceptionHandlers(ref DataReader ehReader) {
ehReader.Position--;
int num = (int)((ehReader.ReadUInt32() >> 8) / 24);
for (int i = 0; i < num; i++) {
var eh = new ExceptionHandler((ExceptionHandlerType)ehReader.ReadUInt32());
uint offs = ehReader.ReadUInt32();
eh.TryStart = GetInstruction(offs);
eh.TryEnd = GetInstruction(offs + ehReader.ReadUInt32());
offs = ehReader.ReadUInt32();
eh.HandlerStart = GetInstruction(offs);
eh.HandlerEnd = GetInstruction(offs + ehReader.ReadUInt32());
if (eh.IsCatch)
eh.CatchType = opResolver.ResolveToken(ehReader.ReadUInt32(), gpContext) as ITypeDefOrRef;
else if (eh.IsFilter)
eh.FilterStart = GetInstruction(ehReader.ReadUInt32());
else
ehReader.ReadUInt32();
Add(eh);
}
}
void ReadSmallExceptionHandlers(ref DataReader ehReader) {
int num = (int)((uint)ehReader.ReadByte() / 12);
ehReader.Position += 2;
for (int i = 0; i < num; i++) {
var eh = new ExceptionHandler((ExceptionHandlerType)ehReader.ReadUInt16());
uint offs = ehReader.ReadUInt16();
eh.TryStart = GetInstruction(offs);
eh.TryEnd = GetInstruction(offs + ehReader.ReadByte());
offs = ehReader.ReadUInt16();
eh.HandlerStart = GetInstruction(offs);
eh.HandlerEnd = GetInstruction(offs + ehReader.ReadByte());
if (eh.IsCatch)
eh.CatchType = opResolver.ResolveToken(ehReader.ReadUInt32(), gpContext) as ITypeDefOrRef;
else if (eh.IsFilter)
eh.FilterStart = GetInstruction(ehReader.ReadUInt32());
else
ehReader.ReadUInt32();
Add(eh);
}
}
/// <summary>
/// Creates a CIL body. Must be called after <see cref="Read()"/>, and can only be
/// called once.
/// </summary>
/// <returns>A new <see cref="CilBody"/> instance</returns>
public CilBody CreateCilBody() {
// Set init locals if it's a tiny method or if the init locals bit is set (fat header)
bool initLocals = flags == 2 || (flags & 0x10) != 0;
var cilBody = new CilBody(initLocals, instructions, exceptionHandlers, locals);
cilBody.HeaderSize = headerSize;
cilBody.MaxStack = maxStack;
cilBody.LocalVarSigTok = localVarSigTok;
cilBody.MetadataBodySize = totalBodySize;
instructions = null;
exceptionHandlers = null;
locals = null;
return cilBody;
}
}
}

View File

@ -1,587 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System;
using System.Collections.Generic;
using dnlib.IO;
namespace dnlib.DotNet.Emit {
/// <summary>
/// Method body reader base class
/// </summary>
public abstract class MethodBodyReaderBase {
/// <summary>The method reader</summary>
protected DataReader reader;
/// <summary>All parameters</summary>
protected IList<Parameter> parameters;
/// <summary>All locals</summary>
protected IList<Local> locals = new List<Local>();
/// <summary>All instructions</summary>
protected IList<Instruction> instructions;
/// <summary>All exception handlers</summary>
protected IList<ExceptionHandler> exceptionHandlers = new List<ExceptionHandler>();
uint currentOffset;
/// <summary>First byte after the end of the code</summary>
protected uint codeEndOffs;
/// <summary>Start offset of method</summary>
protected uint codeStartOffs;
readonly ModuleContext context;
/// <summary>
/// Gets all parameters
/// </summary>
public IList<Parameter> Parameters => parameters;
/// <summary>
/// Gets all locals
/// </summary>
public IList<Local> Locals => locals;
/// <summary>
/// Gets all instructions
/// </summary>
public IList<Instruction> Instructions => instructions;
/// <summary>
/// Gets all exception handlers
/// </summary>
public IList<ExceptionHandler> ExceptionHandlers => exceptionHandlers;
/// <summary>
/// Constructor
/// </summary>
protected MethodBodyReaderBase() {
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="context">The module context</param>
protected MethodBodyReaderBase(ModuleContext context) {
this.context = context;
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="reader">The reader</param>
protected MethodBodyReaderBase(DataReader reader)
: this(reader, null) {
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="reader">The reader</param>
/// <param name="parameters">Method parameters or <c>null</c> if they're not known yet</param>
protected MethodBodyReaderBase(DataReader reader, IList<Parameter> parameters)
: this(reader, parameters, null) {
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="reader">The reader</param>
/// <param name="parameters">Method parameters or <c>null</c> if they're not known yet</param>
/// <param name="context">The module context</param>
protected MethodBodyReaderBase(DataReader reader, IList<Parameter> parameters, ModuleContext context) {
this.reader = reader;
this.parameters = parameters;
this.context = context;
}
/// <summary>
/// Sets new locals
/// </summary>
/// <param name="newLocals">A list of types of all locals or <c>null</c> if none</param>
protected void SetLocals(IList<TypeSig> newLocals) {
var locals = this.locals;
locals.Clear();
if (newLocals is null)
return;
int count = newLocals.Count;
for (int i = 0; i < count; i++)
locals.Add(new Local(newLocals[i]));
}
/// <summary>
/// Sets new locals
/// </summary>
/// <param name="newLocals">A list of types of all locals or <c>null</c> if none</param>
protected void SetLocals(IList<Local> newLocals) {
var locals = this.locals;
locals.Clear();
if (newLocals is null)
return;
int count = newLocals.Count;
for (int i = 0; i < count; i++)
locals.Add(new Local(newLocals[i].Type));
}
/// <summary>
/// Reads all instructions
/// </summary>
/// <param name="numInstrs">Number of instructions to read</param>
protected void ReadInstructions(int numInstrs) {
codeStartOffs = reader.Position;
codeEndOffs = reader.Length; // We don't know the end pos so use the last one
this.instructions = new List<Instruction>(numInstrs);
currentOffset = 0;
var instructions = this.instructions;
for (int i = 0; i < numInstrs && reader.Position < codeEndOffs; i++)
instructions.Add(ReadOneInstruction());
FixBranches();
}
/// <summary>
/// Reads all instructions
/// </summary>
/// <param name="codeSize">Size of code</param>
protected void ReadInstructionsNumBytes(uint codeSize) {
codeStartOffs = reader.Position;
codeEndOffs = reader.Position + codeSize;
if (codeEndOffs < codeStartOffs || codeEndOffs > reader.Length)
throw new InvalidMethodException("Invalid code size");
this.instructions = new List<Instruction>(); //TODO: Estimate number of instructions based on codeSize
currentOffset = 0;
var instructions = this.instructions;
while (reader.Position < codeEndOffs)
instructions.Add(ReadOneInstruction());
reader.Position = codeEndOffs;
FixBranches();
}
/// <summary>
/// Fixes all branch instructions so their operands are set to an <see cref="Instruction"/>
/// instead of an offset.
/// </summary>
void FixBranches() {
var instructions = this.instructions;
int count = instructions.Count;
for (int i = 0; i < count; i++) {
var instr = instructions[i];
switch (instr.OpCode.OperandType) {
case OperandType.InlineBrTarget:
case OperandType.ShortInlineBrTarget:
instr.Operand = GetInstruction((uint)instr.Operand);
break;
case OperandType.InlineSwitch:
var uintTargets = (IList<uint>)instr.Operand;
var targets = new Instruction[uintTargets.Count];
for (int j = 0; j < uintTargets.Count; j++)
targets[j] = GetInstruction(uintTargets[j]);
instr.Operand = targets;
break;
}
}
}
/// <summary>
/// Finds an instruction
/// </summary>
/// <param name="offset">Offset of instruction</param>
/// <returns>The instruction or <c>null</c> if there's no instruction at <paramref name="offset"/>.</returns>
protected Instruction GetInstruction(uint offset) {
// The instructions are sorted and all Offset fields are correct. Do a binary search.
var instructions = this.instructions;
int lo = 0, hi = instructions.Count - 1;
while (lo <= hi && hi != -1) {
int i = (lo + hi) / 2;
var instr = instructions[i];
if (instr.Offset == offset)
return instr;
if (offset < instr.Offset)
hi = i - 1;
else
lo = i + 1;
}
return null;
}
/// <summary>
/// Finds an instruction and throws if it's not present
/// </summary>
/// <param name="offset">Offset of instruction</param>
/// <returns>The instruction</returns>
/// <exception cref="InvalidOperationException">There's no instruction at
/// <paramref name="offset"/></exception>
protected Instruction GetInstructionThrow(uint offset) {
var instr = GetInstruction(offset);
if (instr is not null)
return instr;
throw new InvalidOperationException($"There's no instruction @ {offset:X4}");
}
/// <summary>
/// Reads the next instruction
/// </summary>
Instruction ReadOneInstruction() {
var instr = new Instruction();
instr.Offset = currentOffset;
instr.OpCode = ReadOpCode();
instr.Operand = ReadOperand(instr);
if (instr.OpCode.Code == Code.Switch) {
var targets = (IList<uint>)instr.Operand;
currentOffset += (uint)(instr.OpCode.Size + 4 + 4 * targets.Count);
}
else
currentOffset += (uint)instr.GetSize();
if (currentOffset < instr.Offset)
reader.Position = codeEndOffs;
return instr;
}
/// <summary>
/// Reads the next OpCode from the current position
/// </summary>
OpCode ReadOpCode() {
var op = reader.ReadByte();
if (op == 0xFE)
return OpCodes.TwoByteOpCodes[reader.ReadByte()];
if (op >= 0xF0 && op <= 0xFB && context is not null && reader.BytesLeft >= 1) {
if (context.GetExperimentalOpCode(op, reader.ReadByte()) is OpCode opCode)
return opCode;
else
reader.Position--;
}
return OpCodes.OneByteOpCodes[op];
}
/// <summary>
/// Reads the instruction operand (if any)
/// </summary>
/// <param name="instr">The instruction</param>
object ReadOperand(Instruction instr) =>
instr.OpCode.OperandType switch {
OperandType.InlineBrTarget => ReadInlineBrTarget(instr),
OperandType.InlineField => ReadInlineField(instr),
OperandType.InlineI => ReadInlineI(instr),
OperandType.InlineI8 => ReadInlineI8(instr),
OperandType.InlineMethod => ReadInlineMethod(instr),
OperandType.InlineNone => ReadInlineNone(instr),
OperandType.InlinePhi => ReadInlinePhi(instr),
OperandType.InlineR => ReadInlineR(instr),
OperandType.InlineSig => ReadInlineSig(instr),
OperandType.InlineString => ReadInlineString(instr),
OperandType.InlineSwitch => ReadInlineSwitch(instr),
OperandType.InlineTok => ReadInlineTok(instr),
OperandType.InlineType => ReadInlineType(instr),
OperandType.InlineVar => ReadInlineVar(instr),
OperandType.ShortInlineBrTarget => ReadShortInlineBrTarget(instr),
OperandType.ShortInlineI => ReadShortInlineI(instr),
OperandType.ShortInlineR => ReadShortInlineR(instr),
OperandType.ShortInlineVar => ReadShortInlineVar(instr),
_ => throw new InvalidOperationException("Invalid OpCode.OperandType"),
};
/// <summary>
/// Reads a <see cref="OperandType.InlineBrTarget"/> operand
/// </summary>
/// <param name="instr">The current instruction</param>
/// <returns>The operand</returns>
protected virtual uint ReadInlineBrTarget(Instruction instr) => instr.Offset + (uint)instr.GetSize() + reader.ReadUInt32();
/// <summary>
/// Reads a <see cref="OperandType.InlineField"/> operand
/// </summary>
/// <param name="instr">The current instruction</param>
/// <returns>The operand</returns>
protected abstract IField ReadInlineField(Instruction instr);
/// <summary>
/// Reads a <see cref="OperandType.InlineI"/> operand
/// </summary>
/// <param name="instr">The current instruction</param>
/// <returns>The operand</returns>
protected virtual int ReadInlineI(Instruction instr) => reader.ReadInt32();
/// <summary>
/// Reads a <see cref="OperandType.InlineI8"/> operand
/// </summary>
/// <param name="instr">The current instruction</param>
/// <returns>The operand</returns>
protected virtual long ReadInlineI8(Instruction instr) => reader.ReadInt64();
/// <summary>
/// Reads a <see cref="OperandType.InlineMethod"/> operand
/// </summary>
/// <param name="instr">The current instruction</param>
/// <returns>The operand</returns>
protected abstract IMethod ReadInlineMethod(Instruction instr);
/// <summary>
/// Reads a <see cref="OperandType.InlineNone"/> operand
/// </summary>
/// <param name="instr">The current instruction</param>
/// <returns>The operand</returns>
protected virtual object ReadInlineNone(Instruction instr) => null;
/// <summary>
/// Reads a <see cref="OperandType.InlinePhi"/> operand
/// </summary>
/// <param name="instr">The current instruction</param>
/// <returns>The operand</returns>
protected virtual object ReadInlinePhi(Instruction instr) => null;
/// <summary>
/// Reads a <see cref="OperandType.InlineR"/> operand
/// </summary>
/// <param name="instr">The current instruction</param>
/// <returns>The operand</returns>
protected virtual double ReadInlineR(Instruction instr) => reader.ReadDouble();
/// <summary>
/// Reads a <see cref="OperandType.InlineSig"/> operand
/// </summary>
/// <param name="instr">The current instruction</param>
/// <returns>The operand</returns>
protected abstract MethodSig ReadInlineSig(Instruction instr);
/// <summary>
/// Reads a <see cref="OperandType.InlineString"/> operand
/// </summary>
/// <param name="instr">The current instruction</param>
/// <returns>The operand</returns>
protected abstract string ReadInlineString(Instruction instr);
/// <summary>
/// Reads a <see cref="OperandType.InlineSwitch"/> operand
/// </summary>
/// <param name="instr">The current instruction</param>
/// <returns>The operand</returns>
protected virtual IList<uint> ReadInlineSwitch(Instruction instr) {
var num = reader.ReadUInt32();
long offsetAfterInstr = (long)instr.Offset + (long)instr.OpCode.Size + 4L + (long)num * 4;
if (offsetAfterInstr > uint.MaxValue || codeStartOffs + offsetAfterInstr > codeEndOffs) {
reader.Position = codeEndOffs;
return Array2.Empty<uint>();
}
var targets = new uint[num];
uint offset = (uint)offsetAfterInstr;
for (int i = 0; i < targets.Length; i++)
targets[i] = offset + reader.ReadUInt32();
return targets;
}
/// <summary>
/// Reads a <see cref="OperandType.InlineTok"/> operand
/// </summary>
/// <param name="instr">The current instruction</param>
/// <returns>The operand</returns>
protected abstract ITokenOperand ReadInlineTok(Instruction instr);
/// <summary>
/// Reads a <see cref="OperandType.InlineType"/> operand
/// </summary>
/// <param name="instr">The current instruction</param>
/// <returns>The operand</returns>
protected abstract ITypeDefOrRef ReadInlineType(Instruction instr);
/// <summary>
/// Reads a <see cref="OperandType.InlineVar"/> operand
/// </summary>
/// <param name="instr">The current instruction</param>
/// <returns>The operand</returns>
protected virtual IVariable ReadInlineVar(Instruction instr) {
if (IsArgOperandInstruction(instr))
return ReadInlineVarArg(instr);
return ReadInlineVarLocal(instr);
}
/// <summary>
/// Reads a <see cref="OperandType.InlineVar"/> (a parameter) operand
/// </summary>
/// <param name="instr">The current instruction</param>
/// <returns>The operand</returns>
protected virtual Parameter ReadInlineVarArg(Instruction instr) => GetParameter(reader.ReadUInt16());
/// <summary>
/// Reads a <see cref="OperandType.InlineVar"/> (a local) operand
/// </summary>
/// <param name="instr">The current instruction</param>
/// <returns>The operand</returns>
protected virtual Local ReadInlineVarLocal(Instruction instr) => GetLocal(reader.ReadUInt16());
/// <summary>
/// Reads a <see cref="OperandType.ShortInlineBrTarget"/> operand
/// </summary>
/// <param name="instr">The current instruction</param>
/// <returns>The operand</returns>
protected virtual uint ReadShortInlineBrTarget(Instruction instr) => instr.Offset + (uint)instr.GetSize() + (uint)reader.ReadSByte();
/// <summary>
/// Reads a <see cref="OperandType.ShortInlineI"/> operand
/// </summary>
/// <param name="instr">The current instruction</param>
/// <returns>The operand</returns>
protected virtual object ReadShortInlineI(Instruction instr) {
if (instr.OpCode.Code == Code.Ldc_I4_S)
return reader.ReadSByte();
return reader.ReadByte();
}
/// <summary>
/// Reads a <see cref="OperandType.ShortInlineR"/> operand
/// </summary>
/// <param name="instr">The current instruction</param>
/// <returns>The operand</returns>
protected virtual float ReadShortInlineR(Instruction instr) => reader.ReadSingle();
/// <summary>
/// Reads a <see cref="OperandType.ShortInlineVar"/> operand
/// </summary>
/// <param name="instr">The current instruction</param>
/// <returns>The operand</returns>
protected virtual IVariable ReadShortInlineVar(Instruction instr) {
if (IsArgOperandInstruction(instr))
return ReadShortInlineVarArg(instr);
return ReadShortInlineVarLocal(instr);
}
/// <summary>
/// Reads a <see cref="OperandType.ShortInlineVar"/> (a parameter) operand
/// </summary>
/// <param name="instr">The current instruction</param>
/// <returns>The operand</returns>
protected virtual Parameter ReadShortInlineVarArg(Instruction instr) => GetParameter(reader.ReadByte());
/// <summary>
/// Reads a <see cref="OperandType.ShortInlineVar"/> (a local) operand
/// </summary>
/// <param name="instr">The current instruction</param>
/// <returns>The operand</returns>
protected virtual Local ReadShortInlineVarLocal(Instruction instr) => GetLocal(reader.ReadByte());
/// <summary>
/// Returns <c>true</c> if it's one of the ldarg/starg instructions that have an operand
/// </summary>
/// <param name="instr">The instruction to check</param>
protected static bool IsArgOperandInstruction(Instruction instr) {
switch (instr.OpCode.Code) {
case Code.Ldarg:
case Code.Ldarg_S:
case Code.Ldarga:
case Code.Ldarga_S:
case Code.Starg:
case Code.Starg_S:
return true;
default:
return false;
}
}
/// <summary>
/// Returns a parameter
/// </summary>
/// <param name="index">A parameter index</param>
/// <returns>A <see cref="Parameter"/> or <c>null</c> if <paramref name="index"/> is invalid</returns>
protected Parameter GetParameter(int index) {
var parameters = this.parameters;
if ((uint)index < (uint)parameters.Count)
return parameters[index];
return null;
}
/// <summary>
/// Returns a local
/// </summary>
/// <param name="index">A local index</param>
/// <returns>A <see cref="Local"/> or <c>null</c> if <paramref name="index"/> is invalid</returns>
protected Local GetLocal(int index) {
var locals = this.locals;
if ((uint)index < (uint)locals.Count)
return locals[index];
return null;
}
/// <summary>
/// Add an exception handler if it appears valid
/// </summary>
/// <param name="eh">The exception handler</param>
/// <returns><c>true</c> if it was added, <c>false</c> otherwise</returns>
protected bool Add(ExceptionHandler eh) {
uint tryStart = GetOffset(eh.TryStart);
uint tryEnd = GetOffset(eh.TryEnd);
if (tryEnd <= tryStart)
return false;
uint handlerStart = GetOffset(eh.HandlerStart);
uint handlerEnd = GetOffset(eh.HandlerEnd);
if (handlerEnd <= handlerStart)
return false;
if (eh.IsFilter) {
if (eh.FilterStart is null)
return false;
if (eh.FilterStart.Offset >= handlerStart)
return false;
}
if (handlerStart <= tryStart && tryStart < handlerEnd)
return false;
if (handlerStart < tryEnd && tryEnd <= handlerEnd)
return false;
if (tryStart <= handlerStart && handlerStart < tryEnd)
return false;
if (tryStart < handlerEnd && handlerEnd <= tryEnd)
return false;
// It's probably valid, so let's add it.
exceptionHandlers.Add(eh);
return true;
}
/// <summary>
/// Gets the offset of an instruction
/// </summary>
/// <param name="instr">The instruction or <c>null</c> if the offset is the first offset
/// at the end of the method.</param>
/// <returns>The instruction offset</returns>
uint GetOffset(Instruction instr) {
if (instr is not null)
return instr.Offset;
var instructions = this.instructions;
if (instructions.Count == 0)
return 0;
return instructions[instructions.Count - 1].Offset;
}
/// <summary>
/// Restores a <see cref="MethodDef"/>'s body with the parsed method instructions
/// and exception handlers
/// </summary>
/// <param name="method">The method that gets updated with the instructions, locals, and
/// exception handlers.</param>
public virtual void RestoreMethod(MethodDef method) {
var body = method.Body;
body.Variables.Clear();
var locals = this.locals;
if (locals is not null) {
int count = locals.Count;
for (int i = 0; i < count; i++)
body.Variables.Add(locals[i]);
}
body.Instructions.Clear();
var instructions = this.instructions;
if (instructions is not null) {
int count = instructions.Count;
for (int i = 0; i < count; i++)
body.Instructions.Add(instructions[i]);
}
body.ExceptionHandlers.Clear();
var exceptionHandlers = this.exceptionHandlers;
if (exceptionHandlers is not null) {
int count = exceptionHandlers.Count;
for (int i = 0; i < count; i++)
body.ExceptionHandlers.Add(exceptionHandlers[i]);
}
}
}
}

View File

@ -1,156 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Emit;
using SR = System.Reflection;
namespace dnlib.DotNet.Emit {
/// <summary>
/// Converts a type address to a <see cref="Type"/>. The address can be found in
/// <c>RuntimeTypeHandle.Value</c> and it's the same address you use with the WinDbg SOS command
/// !dumpmt.
/// </summary>
static class MethodTableToTypeConverter {
const string METHOD_NAME = "m";
static readonly MethodInfo setMethodBodyMethodInfo = typeof(MethodBuilder).GetMethod("SetMethodBody", BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
static readonly FieldInfo localSignatureFieldInfo = typeof(ILGenerator).GetField("m_localSignature", BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
static readonly FieldInfo sigDoneFieldInfo = typeof(SignatureHelper).GetField("m_sigDone", BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
static readonly FieldInfo currSigFieldInfo = typeof(SignatureHelper).GetField("m_currSig", BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
static readonly FieldInfo signatureFieldInfo = typeof(SignatureHelper).GetField("m_signature", BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
static readonly FieldInfo ptrFieldInfo = typeof(RuntimeTypeHandle).GetField("m_ptr", BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
static readonly Dictionary<IntPtr, Type> addrToType = new Dictionary<IntPtr, Type>();
static ModuleBuilder moduleBuilder;
static int numNewTypes;
static object lockObj = new object();
static MethodTableToTypeConverter() {
if (ptrFieldInfo is null) {
#if NETSTANDARD || NETCOREAPP
var asmb = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("DynAsm"), AssemblyBuilderAccess.Run);
#else
var asmb = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("DynAsm"), AssemblyBuilderAccess.Run);
#endif
moduleBuilder = asmb.DefineDynamicModule("DynMod");
}
// In .NET 8+, ILGenerator is an abstract class and the actual ILGenerator implementation is found in RuntimeILGenerator.
localSignatureFieldInfo ??= Type.GetType("System.Reflection.Emit.RuntimeILGenerator")?.GetField("m_localSignature", BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
}
/// <summary>
/// Converts <paramref name="address"/> to a <see cref="Type"/>.
/// </summary>
/// <param name="address">Address of type</param>
/// <returns>The <see cref="Type"/> or <c>null</c></returns>
public static Type Convert(IntPtr address) {
lock (lockObj) {
if (addrToType.TryGetValue(address, out var type))
return type;
type = GetTypeNET20(address) ?? GetTypeUsingTypeBuilder(address);
addrToType[address] = type;
return type;
}
}
static Type GetTypeUsingTypeBuilder(IntPtr address) {
if (moduleBuilder is null)
return null;
var tb = moduleBuilder.DefineType(GetNextTypeName());
var mb = tb.DefineMethod(METHOD_NAME, SR.MethodAttributes.Static, typeof(void), Array2.Empty<Type>());
try {
if (setMethodBodyMethodInfo is not null)
return GetTypeNET45(tb, mb, address);
else
return GetTypeNET40(tb, mb, address);
}
catch {
moduleBuilder = null;
return null;
}
}
// .NET Framework 4.5 and later have the documented SetMethodBody() method.
static Type GetTypeNET45(TypeBuilder tb, MethodBuilder mb, IntPtr address) {
var code = new byte[1] { 0x2A };
int maxStack = 8;
var locals = GetLocalSignature(address);
setMethodBodyMethodInfo.Invoke(mb, new object[5] { code, maxStack, locals, null, null });
#if NETSTANDARD
var type = tb.CreateTypeInfo();
#else
var type = tb.CreateType();
#endif
var createdMethod = type.GetMethod(METHOD_NAME, BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance);
return createdMethod.GetMethodBody().LocalVariables[0].LocalType;
}
// This code works with .NET Framework 4.0+ but will throw an exception if .NET Framework 2.0 is used
// ("operation could destabilize the runtime")
static Type GetTypeNET40(TypeBuilder tb, MethodBuilder mb, IntPtr address) {
var ilg = mb.GetILGenerator();
ilg.Emit(SR.Emit.OpCodes.Ret);
// We need at least one local to make sure the SignatureHelper from ILGenerator is used.
ilg.DeclareLocal(typeof(int));
var locals = GetLocalSignature(address);
var sigHelper = (SignatureHelper)localSignatureFieldInfo.GetValue(ilg);
sigDoneFieldInfo.SetValue(sigHelper, true);
currSigFieldInfo.SetValue(sigHelper, locals.Length);
signatureFieldInfo.SetValue(sigHelper, locals);
#if NETSTANDARD
var type = tb.CreateTypeInfo();
#else
var type = tb.CreateType();
#endif
var createdMethod = type.GetMethod(METHOD_NAME, BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance);
return createdMethod.GetMethodBody().LocalVariables[0].LocalType;
}
// .NET Framework 2.0 - 3.5
static Type GetTypeNET20(IntPtr address) {
if (ptrFieldInfo is null)
return null;
object th = new RuntimeTypeHandle();
ptrFieldInfo.SetValue(th, address);
return Type.GetTypeFromHandle((RuntimeTypeHandle)th);
}
static string GetNextTypeName() => $"Type{numNewTypes++}";
static byte[] GetLocalSignature(IntPtr mtAddr) {
ulong mtValue = (ulong)mtAddr.ToInt64();
if (IntPtr.Size == 4) {
return new byte[] {
0x07,
0x01,
(byte)ElementType.Internal,
(byte)mtValue,
(byte)(mtValue >> 8),
(byte)(mtValue >> 16),
(byte)(mtValue >> 24),
};
}
else {
return new byte[] {
0x07,
0x01,
(byte)ElementType.Internal,
(byte)mtValue,
(byte)(mtValue >> 8),
(byte)(mtValue >> 16),
(byte)(mtValue >> 24),
(byte)(mtValue >> 32),
(byte)(mtValue >> 40),
(byte)(mtValue >> 48),
(byte)(mtValue >> 56),
};
}
}
}
}

View File

@ -1,516 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System.Collections.Generic;
namespace dnlib.DotNet.Emit {
/// <summary>
/// Instruction utility methods
/// </summary>
public static class MethodUtils {
/// <summary>
/// Shorter instructions are converted to the longer form, eg. <c>Ldc_I4_1</c> is
/// converted to <c>Ldc_I4</c> with a <c>1</c> as the operand.
/// </summary>
/// <param name="instructions">All instructions</param>
/// <param name="locals">All locals</param>
/// <param name="parameters">All method parameters, including the hidden 'this' parameter
/// if it's an instance method. Use <see cref="MethodDef.Parameters"/>.</param>
public static void SimplifyMacros(this IList<Instruction> instructions, IList<Local> locals, IList<Parameter> parameters) {
int count = instructions.Count;
for (int i = 0; i < count; i++) {
var instr = instructions[i];
switch (instr.OpCode.Code) {
case Code.Beq_S:
instr.OpCode = OpCodes.Beq;
break;
case Code.Bge_S:
instr.OpCode = OpCodes.Bge;
break;
case Code.Bge_Un_S:
instr.OpCode = OpCodes.Bge_Un;
break;
case Code.Bgt_S:
instr.OpCode = OpCodes.Bgt;
break;
case Code.Bgt_Un_S:
instr.OpCode = OpCodes.Bgt_Un;
break;
case Code.Ble_S:
instr.OpCode = OpCodes.Ble;
break;
case Code.Ble_Un_S:
instr.OpCode = OpCodes.Ble_Un;
break;
case Code.Blt_S:
instr.OpCode = OpCodes.Blt;
break;
case Code.Blt_Un_S:
instr.OpCode = OpCodes.Blt_Un;
break;
case Code.Bne_Un_S:
instr.OpCode = OpCodes.Bne_Un;
break;
case Code.Br_S:
instr.OpCode = OpCodes.Br;
break;
case Code.Brfalse_S:
instr.OpCode = OpCodes.Brfalse;
break;
case Code.Brtrue_S:
instr.OpCode = OpCodes.Brtrue;
break;
case Code.Ldarg_0:
instr.OpCode = OpCodes.Ldarg;
instr.Operand = ReadList(parameters, 0);
break;
case Code.Ldarg_1:
instr.OpCode = OpCodes.Ldarg;
instr.Operand = ReadList(parameters, 1);
break;
case Code.Ldarg_2:
instr.OpCode = OpCodes.Ldarg;
instr.Operand = ReadList(parameters, 2);
break;
case Code.Ldarg_3:
instr.OpCode = OpCodes.Ldarg;
instr.Operand = ReadList(parameters, 3);
break;
case Code.Ldarg_S:
instr.OpCode = OpCodes.Ldarg;
break;
case Code.Ldarga_S:
instr.OpCode = OpCodes.Ldarga;
break;
case Code.Ldc_I4_0:
instr.OpCode = OpCodes.Ldc_I4;
instr.Operand = 0;
break;
case Code.Ldc_I4_1:
instr.OpCode = OpCodes.Ldc_I4;
instr.Operand = 1;
break;
case Code.Ldc_I4_2:
instr.OpCode = OpCodes.Ldc_I4;
instr.Operand = 2;
break;
case Code.Ldc_I4_3:
instr.OpCode = OpCodes.Ldc_I4;
instr.Operand = 3;
break;
case Code.Ldc_I4_4:
instr.OpCode = OpCodes.Ldc_I4;
instr.Operand = 4;
break;
case Code.Ldc_I4_5:
instr.OpCode = OpCodes.Ldc_I4;
instr.Operand = 5;
break;
case Code.Ldc_I4_6:
instr.OpCode = OpCodes.Ldc_I4;
instr.Operand = 6;
break;
case Code.Ldc_I4_7:
instr.OpCode = OpCodes.Ldc_I4;
instr.Operand = 7;
break;
case Code.Ldc_I4_8:
instr.OpCode = OpCodes.Ldc_I4;
instr.Operand = 8;
break;
case Code.Ldc_I4_M1:
instr.OpCode = OpCodes.Ldc_I4;
instr.Operand = -1;
break;
case Code.Ldc_I4_S:
instr.OpCode = OpCodes.Ldc_I4;
instr.Operand = (int)(sbyte)instr.Operand;
break;
case Code.Ldloc_0:
instr.OpCode = OpCodes.Ldloc;
instr.Operand = ReadList(locals, 0);
break;
case Code.Ldloc_1:
instr.OpCode = OpCodes.Ldloc;
instr.Operand = ReadList(locals, 1);
break;
case Code.Ldloc_2:
instr.OpCode = OpCodes.Ldloc;
instr.Operand = ReadList(locals, 2);
break;
case Code.Ldloc_3:
instr.OpCode = OpCodes.Ldloc;
instr.Operand = ReadList(locals, 3);
break;
case Code.Ldloc_S:
instr.OpCode = OpCodes.Ldloc;
break;
case Code.Ldloca_S:
instr.OpCode = OpCodes.Ldloca;
break;
case Code.Leave_S:
instr.OpCode = OpCodes.Leave;
break;
case Code.Starg_S:
instr.OpCode = OpCodes.Starg;
break;
case Code.Stloc_0:
instr.OpCode = OpCodes.Stloc;
instr.Operand = ReadList(locals, 0);
break;
case Code.Stloc_1:
instr.OpCode = OpCodes.Stloc;
instr.Operand = ReadList(locals, 1);
break;
case Code.Stloc_2:
instr.OpCode = OpCodes.Stloc;
instr.Operand = ReadList(locals, 2);
break;
case Code.Stloc_3:
instr.OpCode = OpCodes.Stloc;
instr.Operand = ReadList(locals, 3);
break;
case Code.Stloc_S:
instr.OpCode = OpCodes.Stloc;
break;
}
}
}
static T ReadList<T>(IList<T> list, int index) {
if (list is null)
return default;
if ((uint)index < (uint)list.Count)
return list[index];
return default;
}
/// <summary>
/// Optimizes instructions by using the shorter form if possible. Eg. <c>Ldc_I4</c> <c>1</c>
/// will be replaced with <c>Ldc_I4_1</c>.
/// </summary>
/// <param name="instructions">All instructions</param>
public static void OptimizeMacros(this IList<Instruction> instructions) {
int count = instructions.Count;
for (int i = 0; i < count; i++) {
var instr = instructions[i];
Parameter arg;
Local local;
switch (instr.OpCode.Code) {
case Code.Ldarg:
case Code.Ldarg_S:
arg = instr.Operand as Parameter;
if (arg is null)
break;
if (arg.Index == 0) {
instr.OpCode = OpCodes.Ldarg_0;
instr.Operand = null;
}
else if (arg.Index == 1) {
instr.OpCode = OpCodes.Ldarg_1;
instr.Operand = null;
}
else if (arg.Index == 2) {
instr.OpCode = OpCodes.Ldarg_2;
instr.Operand = null;
}
else if (arg.Index == 3) {
instr.OpCode = OpCodes.Ldarg_3;
instr.Operand = null;
}
else if (byte.MinValue <= arg.Index && arg.Index <= byte.MaxValue)
instr.OpCode = OpCodes.Ldarg_S;
break;
case Code.Ldarga:
arg = instr.Operand as Parameter;
if (arg is null)
break;
if (byte.MinValue <= arg.Index && arg.Index <= byte.MaxValue)
instr.OpCode = OpCodes.Ldarga_S;
break;
case Code.Ldc_I4:
case Code.Ldc_I4_S:
int i4;
if (instr.Operand is int)
i4 = (int)instr.Operand;
else if (instr.Operand is sbyte)
i4 = (sbyte)instr.Operand;
else
break;
switch (i4) {
case 0:
instr.OpCode = OpCodes.Ldc_I4_0;
instr.Operand = null;
break;
case 1:
instr.OpCode = OpCodes.Ldc_I4_1;
instr.Operand = null;
break;
case 2:
instr.OpCode = OpCodes.Ldc_I4_2;
instr.Operand = null;
break;
case 3:
instr.OpCode = OpCodes.Ldc_I4_3;
instr.Operand = null;
break;
case 4:
instr.OpCode = OpCodes.Ldc_I4_4;
instr.Operand = null;
break;
case 5:
instr.OpCode = OpCodes.Ldc_I4_5;
instr.Operand = null;
break;
case 6:
instr.OpCode = OpCodes.Ldc_I4_6;
instr.Operand = null;
break;
case 7:
instr.OpCode = OpCodes.Ldc_I4_7;
instr.Operand = null;
break;
case 8:
instr.OpCode = OpCodes.Ldc_I4_8;
instr.Operand = null;
break;
case -1:
instr.OpCode = OpCodes.Ldc_I4_M1;
instr.Operand = null;
break;
default:
if (sbyte.MinValue <= i4 && i4 <= sbyte.MaxValue) {
instr.OpCode = OpCodes.Ldc_I4_S;
instr.Operand = (sbyte)i4;
}
break;
}
break;
case Code.Ldloc:
case Code.Ldloc_S:
local = instr.Operand as Local;
if (local is null)
break;
if (local.Index == 0) {
instr.OpCode = OpCodes.Ldloc_0;
instr.Operand = null;
}
else if (local.Index == 1) {
instr.OpCode = OpCodes.Ldloc_1;
instr.Operand = null;
}
else if (local.Index == 2) {
instr.OpCode = OpCodes.Ldloc_2;
instr.Operand = null;
}
else if (local.Index == 3) {
instr.OpCode = OpCodes.Ldloc_3;
instr.Operand = null;
}
else if (byte.MinValue <= local.Index && local.Index <= byte.MaxValue)
instr.OpCode = OpCodes.Ldloc_S;
break;
case Code.Ldloca:
local = instr.Operand as Local;
if (local is null)
break;
if (byte.MinValue <= local.Index && local.Index <= byte.MaxValue)
instr.OpCode = OpCodes.Ldloca_S;
break;
case Code.Starg:
arg = instr.Operand as Parameter;
if (arg is null)
break;
if (byte.MinValue <= arg.Index && arg.Index <= byte.MaxValue)
instr.OpCode = OpCodes.Starg_S;
break;
case Code.Stloc:
case Code.Stloc_S:
local = instr.Operand as Local;
if (local is null)
break;
if (local.Index == 0) {
instr.OpCode = OpCodes.Stloc_0;
instr.Operand = null;
}
else if (local.Index == 1) {
instr.OpCode = OpCodes.Stloc_1;
instr.Operand = null;
}
else if (local.Index == 2) {
instr.OpCode = OpCodes.Stloc_2;
instr.Operand = null;
}
else if (local.Index == 3) {
instr.OpCode = OpCodes.Stloc_3;
instr.Operand = null;
}
else if (byte.MinValue <= local.Index && local.Index <= byte.MaxValue)
instr.OpCode = OpCodes.Stloc_S;
break;
}
}
OptimizeBranches(instructions);
}
/// <summary>
/// Short branch instructions are converted to the long form, eg. <c>Beq_S</c> is
/// converted to <c>Beq</c>.
/// </summary>
/// <param name="instructions">All instructions</param>
public static void SimplifyBranches(this IList<Instruction> instructions) {
int count = instructions.Count;
for (int i = 0; i < count; i++) {
var instr = instructions[i];
switch (instr.OpCode.Code) {
case Code.Beq_S: instr.OpCode = OpCodes.Beq; break;
case Code.Bge_S: instr.OpCode = OpCodes.Bge; break;
case Code.Bgt_S: instr.OpCode = OpCodes.Bgt; break;
case Code.Ble_S: instr.OpCode = OpCodes.Ble; break;
case Code.Blt_S: instr.OpCode = OpCodes.Blt; break;
case Code.Bne_Un_S: instr.OpCode = OpCodes.Bne_Un; break;
case Code.Bge_Un_S: instr.OpCode = OpCodes.Bge_Un; break;
case Code.Bgt_Un_S: instr.OpCode = OpCodes.Bgt_Un; break;
case Code.Ble_Un_S: instr.OpCode = OpCodes.Ble_Un; break;
case Code.Blt_Un_S: instr.OpCode = OpCodes.Blt_Un; break;
case Code.Br_S: instr.OpCode = OpCodes.Br; break;
case Code.Brfalse_S:instr.OpCode = OpCodes.Brfalse; break;
case Code.Brtrue_S: instr.OpCode = OpCodes.Brtrue; break;
case Code.Leave_S: instr.OpCode = OpCodes.Leave; break;
}
}
}
/// <summary>
/// Optimizes branches by using the smallest possible branch
/// </summary>
/// <param name="instructions">All instructions</param>
public static void OptimizeBranches(this IList<Instruction> instructions) {
while (true) {
UpdateInstructionOffsets(instructions);
bool modified = false;
int count = instructions.Count;
for (int i = 0; i < count; i++) {
var instr = instructions[i];
OpCode shortOpCode;
switch (instr.OpCode.Code) {
case Code.Beq: shortOpCode = OpCodes.Beq_S; break;
case Code.Bge: shortOpCode = OpCodes.Bge_S; break;
case Code.Bge_Un: shortOpCode = OpCodes.Bge_Un_S; break;
case Code.Bgt: shortOpCode = OpCodes.Bgt_S; break;
case Code.Bgt_Un: shortOpCode = OpCodes.Bgt_Un_S; break;
case Code.Ble: shortOpCode = OpCodes.Ble_S; break;
case Code.Ble_Un: shortOpCode = OpCodes.Ble_Un_S; break;
case Code.Blt: shortOpCode = OpCodes.Blt_S; break;
case Code.Blt_Un: shortOpCode = OpCodes.Blt_Un_S; break;
case Code.Bne_Un: shortOpCode = OpCodes.Bne_Un_S; break;
case Code.Br: shortOpCode = OpCodes.Br_S; break;
case Code.Brfalse: shortOpCode = OpCodes.Brfalse_S; break;
case Code.Brtrue: shortOpCode = OpCodes.Brtrue_S; break;
case Code.Leave: shortOpCode = OpCodes.Leave_S; break;
default: continue;
}
var targetInstr = instr.Operand as Instruction;
if (targetInstr is null)
continue;
int afterShortInstr;
if (targetInstr.Offset >= instr.Offset) {
// Target is >= this instruction so use the offset after
// current instruction
afterShortInstr = (int)instr.Offset + instr.GetSize();
}
else {
// Target is < this instruction so use the offset after
// the short instruction
const int operandSize = 1;
afterShortInstr = (int)instr.Offset + shortOpCode.Size + operandSize;
}
int displ = (int)targetInstr.Offset - afterShortInstr;
if (sbyte.MinValue <= displ && displ <= sbyte.MaxValue) {
instr.OpCode = shortOpCode;
modified = true;
}
}
if (!modified)
break;
}
}
/// <summary>
/// Updates each instruction's offset
/// </summary>
/// <param name="instructions">All instructions</param>
/// <returns>Total size in bytes of all instructions</returns>
public static uint UpdateInstructionOffsets(this IList<Instruction> instructions) {
uint offset = 0;
int count = instructions.Count;
for (int i = 0; i < count; i++) {
var instr = instructions[i];
instr.Offset = offset;
offset += (uint)instr.GetSize();
}
return offset;
}
}
}

View File

@ -1,213 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System.Collections.Generic;
namespace dnlib.DotNet.Emit {
/// <summary>
/// A CIL opcode
/// </summary>
public sealed class OpCode {
/// <summary>
/// The opcode name
/// </summary>
public readonly string Name;
/// <summary>
/// The opcode as a <see cref="Code"/> enum
/// </summary>
public readonly Code Code;
/// <summary>
/// Operand type
/// </summary>
public readonly OperandType OperandType;
/// <summary>
/// Flow control info
/// </summary>
public readonly FlowControl FlowControl;
/// <summary>
/// Opcode type
/// </summary>
public readonly OpCodeType OpCodeType;
/// <summary>
/// Push stack behavior
/// </summary>
public readonly StackBehaviour StackBehaviourPush;
/// <summary>
/// Pop stack behavior
/// </summary>
public readonly StackBehaviour StackBehaviourPop;
/// <summary>
/// Gets the value which is compatible with <see cref="System.Reflection.Emit.OpCode.Value"/>
/// </summary>
public short Value => (short)Code;
/// <summary>
/// Gets the size of the opcode. It's either 1 or 2 bytes.
/// </summary>
public int Size => Code < (Code)0x100 || Code == Code.UNKNOWN1 ? 1 : 2;
/// <summary>
/// Constructs an experimental opcode.
/// </summary>
public OpCode(string name, byte first, byte second, OperandType operandType, FlowControl flowControl, StackBehaviour push, StackBehaviour pop)
: this(name, (Code)((first << 8) | second), operandType, flowControl, OpCodeType.Experimental, push, pop, true) {
}
internal OpCode(string name, Code code, OperandType operandType, FlowControl flowControl, OpCodeType opCodeType, StackBehaviour push, StackBehaviour pop, bool experimental = false) {
Name = name;
Code = code;
OperandType = operandType;
FlowControl = flowControl;
OpCodeType = opCodeType;
StackBehaviourPush = push;
StackBehaviourPop = pop;
if (!experimental) {
if (((ushort)code >> 8) == 0)
OpCodes.OneByteOpCodes[(byte)code] = this;
else if (((ushort)code >> 8) == 0xFE)
OpCodes.TwoByteOpCodes[(byte)code] = this;
}
}
/// <summary>
/// Creates a new instruction with no operand
/// </summary>
/// <returns>A new <see cref="Instruction"/> instance</returns>
public Instruction ToInstruction() => Instruction.Create(this);
/// <summary>
/// Creates a new instruction with a <see cref="byte"/> operand
/// </summary>
/// <param name="value">The value</param>
/// <returns>A new <see cref="Instruction"/> instance</returns>
public Instruction ToInstruction(byte value) => Instruction.Create(this, value);
/// <summary>
/// Creates a new instruction with a <see cref="sbyte"/> operand
/// </summary>
/// <param name="value">The value</param>
/// <returns>A new <see cref="Instruction"/> instance</returns>
public Instruction ToInstruction(sbyte value) => Instruction.Create(this, value);
/// <summary>
/// Creates a new instruction with an <see cref="int"/> operand
/// </summary>
/// <param name="value">The value</param>
/// <returns>A new <see cref="Instruction"/> instance</returns>
public Instruction ToInstruction(int value) => Instruction.Create(this, value);
/// <summary>
/// Creates a new instruction with a <see cref="long"/> operand
/// </summary>
/// <param name="value">The value</param>
/// <returns>A new <see cref="Instruction"/> instance</returns>
public Instruction ToInstruction(long value) => Instruction.Create(this, value);
/// <summary>
/// Creates a new instruction with a <see cref="float"/> operand
/// </summary>
/// <param name="value">The value</param>
/// <returns>A new <see cref="Instruction"/> instance</returns>
public Instruction ToInstruction(float value) => Instruction.Create(this, value);
/// <summary>
/// Creates a new instruction with a <see cref="double"/> operand
/// </summary>
/// <param name="value">The value</param>
/// <returns>A new <see cref="Instruction"/> instance</returns>
public Instruction ToInstruction(double value) => Instruction.Create(this, value);
/// <summary>
/// Creates a new instruction with a string operand
/// </summary>
/// <param name="s">The string</param>
/// <returns>A new <see cref="Instruction"/> instance</returns>
public Instruction ToInstruction(string s) => Instruction.Create(this, s);
/// <summary>
/// Creates a new instruction with an instruction target operand
/// </summary>
/// <param name="target">Target instruction</param>
/// <returns>A new <see cref="Instruction"/> instance</returns>
public Instruction ToInstruction(Instruction target) => Instruction.Create(this, target);
/// <summary>
/// Creates a new instruction with an instruction target list operand
/// </summary>
/// <param name="targets">The targets</param>
/// <returns>A new <see cref="Instruction"/> instance</returns>
public Instruction ToInstruction(IList<Instruction> targets) => Instruction.Create(this, targets);
/// <summary>
/// Creates a new instruction with a type operand
/// </summary>
/// <param name="type">The type</param>
/// <returns>A new <see cref="Instruction"/> instance</returns>
public Instruction ToInstruction(ITypeDefOrRef type) => Instruction.Create(this, type);
/// <summary>
/// Creates a new instruction with a type operand
/// </summary>
/// <param name="type">The type</param>
/// <returns>A new <see cref="Instruction"/> instance</returns>
public Instruction ToInstruction(CorLibTypeSig type) => Instruction.Create(this, type.TypeDefOrRef);
/// <summary>
/// Creates a new instruction with a method/field operand
/// </summary>
/// <param name="mr">The method/field</param>
/// <returns>A new <see cref="Instruction"/> instance</returns>
public Instruction ToInstruction(MemberRef mr) => Instruction.Create(this, mr);
/// <summary>
/// Creates a new instruction with a field operand
/// </summary>
/// <param name="field">The field</param>
/// <returns>A new <see cref="Instruction"/> instance</returns>
public Instruction ToInstruction(IField field) => Instruction.Create(this, field);
/// <summary>
/// Creates a new instruction with a method operand
/// </summary>
/// <param name="method">The method</param>
/// <returns>A new <see cref="Instruction"/> instance</returns>
public Instruction ToInstruction(IMethod method) => Instruction.Create(this, method);
/// <summary>
/// Creates a new instruction with a token operand
/// </summary>
/// <param name="token">The token</param>
/// <returns>A new <see cref="Instruction"/> instance</returns>
public Instruction ToInstruction(ITokenOperand token) => Instruction.Create(this, token);
/// <summary>
/// Creates a new instruction with a method signature operand
/// </summary>
/// <param name="methodSig">The method signature</param>
/// <returns>A new <see cref="Instruction"/> instance</returns>
public Instruction ToInstruction(MethodSig methodSig) => Instruction.Create(this, methodSig);
/// <summary>
/// Creates a new instruction with a method parameter operand
/// </summary>
/// <param name="parameter">The method parameter</param>
/// <returns>A new <see cref="Instruction"/> instance</returns>
public Instruction ToInstruction(Parameter parameter) => Instruction.Create(this, parameter);
/// <summary>
/// Creates a new instruction with a method local operand
/// </summary>
/// <param name="local">The method local</param>
/// <returns>A new <see cref="Instruction"/> instance</returns>
public Instruction ToInstruction(Local local) => Instruction.Create(this, local);
/// <inheritdoc/>
public override string ToString() => Name;
}
}

View File

@ -1,23 +0,0 @@
// dnlib: See LICENSE.txt for more info
namespace dnlib.DotNet.Emit {
/// <summary>
/// CIL opcode type
/// </summary>
public enum OpCodeType : byte {
/// <summary/>
Annotation,
/// <summary/>
Macro,
/// <summary/>
Nternal,
/// <summary/>
Objmodel,
/// <summary/>
Prefix,
/// <summary/>
Primitive,
/// <summary/>
Experimental,
}
}

View File

@ -1,263 +0,0 @@
// dnlib: See LICENSE.txt for more info
namespace dnlib.DotNet.Emit {
/// <summary>
/// Contains all valid CIL opcodes
/// </summary>
public static class OpCodes {
/// <summary>
/// All one-byte opcodes
/// </summary>
public static readonly OpCode[] OneByteOpCodes = new OpCode[0x100];
/// <summary>
/// All two-byte opcodes (first byte is <c>0xFE</c>)
/// </summary>
public static readonly OpCode[] TwoByteOpCodes = new OpCode[0x100];
#pragma warning disable 1591 // disable XML doc warning
public static readonly OpCode UNKNOWN1 = new OpCode("UNKNOWN1", Code.UNKNOWN1, OperandType.InlineNone, FlowControl.Meta, OpCodeType.Nternal, StackBehaviour.Push0, StackBehaviour.Pop0);
public static readonly OpCode UNKNOWN2 = new OpCode("UNKNOWN2", Code.UNKNOWN2, OperandType.InlineNone, FlowControl.Meta, OpCodeType.Nternal, StackBehaviour.Push0, StackBehaviour.Pop0);
public static readonly OpCode Nop = new OpCode("nop", Code.Nop, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Push0, StackBehaviour.Pop0);
public static readonly OpCode Break = new OpCode("break", Code.Break, OperandType.InlineNone, FlowControl.Break, OpCodeType.Primitive, StackBehaviour.Push0, StackBehaviour.Pop0);
public static readonly OpCode Ldarg_0 = new OpCode("ldarg.0", Code.Ldarg_0, OperandType.InlineNone, FlowControl.Next, OpCodeType.Macro, StackBehaviour.Push1, StackBehaviour.Pop0);
public static readonly OpCode Ldarg_1 = new OpCode("ldarg.1", Code.Ldarg_1, OperandType.InlineNone, FlowControl.Next, OpCodeType.Macro, StackBehaviour.Push1, StackBehaviour.Pop0);
public static readonly OpCode Ldarg_2 = new OpCode("ldarg.2", Code.Ldarg_2, OperandType.InlineNone, FlowControl.Next, OpCodeType.Macro, StackBehaviour.Push1, StackBehaviour.Pop0);
public static readonly OpCode Ldarg_3 = new OpCode("ldarg.3", Code.Ldarg_3, OperandType.InlineNone, FlowControl.Next, OpCodeType.Macro, StackBehaviour.Push1, StackBehaviour.Pop0);
public static readonly OpCode Ldloc_0 = new OpCode("ldloc.0", Code.Ldloc_0, OperandType.InlineNone, FlowControl.Next, OpCodeType.Macro, StackBehaviour.Push1, StackBehaviour.Pop0);
public static readonly OpCode Ldloc_1 = new OpCode("ldloc.1", Code.Ldloc_1, OperandType.InlineNone, FlowControl.Next, OpCodeType.Macro, StackBehaviour.Push1, StackBehaviour.Pop0);
public static readonly OpCode Ldloc_2 = new OpCode("ldloc.2", Code.Ldloc_2, OperandType.InlineNone, FlowControl.Next, OpCodeType.Macro, StackBehaviour.Push1, StackBehaviour.Pop0);
public static readonly OpCode Ldloc_3 = new OpCode("ldloc.3", Code.Ldloc_3, OperandType.InlineNone, FlowControl.Next, OpCodeType.Macro, StackBehaviour.Push1, StackBehaviour.Pop0);
public static readonly OpCode Stloc_0 = new OpCode("stloc.0", Code.Stloc_0, OperandType.InlineNone, FlowControl.Next, OpCodeType.Macro, StackBehaviour.Push0, StackBehaviour.Pop1);
public static readonly OpCode Stloc_1 = new OpCode("stloc.1", Code.Stloc_1, OperandType.InlineNone, FlowControl.Next, OpCodeType.Macro, StackBehaviour.Push0, StackBehaviour.Pop1);
public static readonly OpCode Stloc_2 = new OpCode("stloc.2", Code.Stloc_2, OperandType.InlineNone, FlowControl.Next, OpCodeType.Macro, StackBehaviour.Push0, StackBehaviour.Pop1);
public static readonly OpCode Stloc_3 = new OpCode("stloc.3", Code.Stloc_3, OperandType.InlineNone, FlowControl.Next, OpCodeType.Macro, StackBehaviour.Push0, StackBehaviour.Pop1);
public static readonly OpCode Ldarg_S = new OpCode("ldarg.s", Code.Ldarg_S, OperandType.ShortInlineVar, FlowControl.Next, OpCodeType.Macro, StackBehaviour.Push1, StackBehaviour.Pop0);
public static readonly OpCode Ldarga_S = new OpCode("ldarga.s", Code.Ldarga_S, OperandType.ShortInlineVar, FlowControl.Next, OpCodeType.Macro, StackBehaviour.Pushi, StackBehaviour.Pop0);
public static readonly OpCode Starg_S = new OpCode("starg.s", Code.Starg_S, OperandType.ShortInlineVar, FlowControl.Next, OpCodeType.Macro, StackBehaviour.Push0, StackBehaviour.Pop1);
public static readonly OpCode Ldloc_S = new OpCode("ldloc.s", Code.Ldloc_S, OperandType.ShortInlineVar, FlowControl.Next, OpCodeType.Macro, StackBehaviour.Push1, StackBehaviour.Pop0);
public static readonly OpCode Ldloca_S = new OpCode("ldloca.s", Code.Ldloca_S, OperandType.ShortInlineVar, FlowControl.Next, OpCodeType.Macro, StackBehaviour.Pushi, StackBehaviour.Pop0);
public static readonly OpCode Stloc_S = new OpCode("stloc.s", Code.Stloc_S, OperandType.ShortInlineVar, FlowControl.Next, OpCodeType.Macro, StackBehaviour.Push0, StackBehaviour.Pop1);
public static readonly OpCode Ldnull = new OpCode("ldnull", Code.Ldnull, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushref, StackBehaviour.Pop0);
public static readonly OpCode Ldc_I4_M1 = new OpCode("ldc.i4.m1", Code.Ldc_I4_M1, OperandType.InlineNone, FlowControl.Next, OpCodeType.Macro, StackBehaviour.Pushi, StackBehaviour.Pop0);
public static readonly OpCode Ldc_I4_0 = new OpCode("ldc.i4.0", Code.Ldc_I4_0, OperandType.InlineNone, FlowControl.Next, OpCodeType.Macro, StackBehaviour.Pushi, StackBehaviour.Pop0);
public static readonly OpCode Ldc_I4_1 = new OpCode("ldc.i4.1", Code.Ldc_I4_1, OperandType.InlineNone, FlowControl.Next, OpCodeType.Macro, StackBehaviour.Pushi, StackBehaviour.Pop0);
public static readonly OpCode Ldc_I4_2 = new OpCode("ldc.i4.2", Code.Ldc_I4_2, OperandType.InlineNone, FlowControl.Next, OpCodeType.Macro, StackBehaviour.Pushi, StackBehaviour.Pop0);
public static readonly OpCode Ldc_I4_3 = new OpCode("ldc.i4.3", Code.Ldc_I4_3, OperandType.InlineNone, FlowControl.Next, OpCodeType.Macro, StackBehaviour.Pushi, StackBehaviour.Pop0);
public static readonly OpCode Ldc_I4_4 = new OpCode("ldc.i4.4", Code.Ldc_I4_4, OperandType.InlineNone, FlowControl.Next, OpCodeType.Macro, StackBehaviour.Pushi, StackBehaviour.Pop0);
public static readonly OpCode Ldc_I4_5 = new OpCode("ldc.i4.5", Code.Ldc_I4_5, OperandType.InlineNone, FlowControl.Next, OpCodeType.Macro, StackBehaviour.Pushi, StackBehaviour.Pop0);
public static readonly OpCode Ldc_I4_6 = new OpCode("ldc.i4.6", Code.Ldc_I4_6, OperandType.InlineNone, FlowControl.Next, OpCodeType.Macro, StackBehaviour.Pushi, StackBehaviour.Pop0);
public static readonly OpCode Ldc_I4_7 = new OpCode("ldc.i4.7", Code.Ldc_I4_7, OperandType.InlineNone, FlowControl.Next, OpCodeType.Macro, StackBehaviour.Pushi, StackBehaviour.Pop0);
public static readonly OpCode Ldc_I4_8 = new OpCode("ldc.i4.8", Code.Ldc_I4_8, OperandType.InlineNone, FlowControl.Next, OpCodeType.Macro, StackBehaviour.Pushi, StackBehaviour.Pop0);
public static readonly OpCode Ldc_I4_S = new OpCode("ldc.i4.s", Code.Ldc_I4_S, OperandType.ShortInlineI, FlowControl.Next, OpCodeType.Macro, StackBehaviour.Pushi, StackBehaviour.Pop0);
public static readonly OpCode Ldc_I4 = new OpCode("ldc.i4", Code.Ldc_I4, OperandType.InlineI, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushi, StackBehaviour.Pop0);
public static readonly OpCode Ldc_I8 = new OpCode("ldc.i8", Code.Ldc_I8, OperandType.InlineI8, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushi8, StackBehaviour.Pop0);
public static readonly OpCode Ldc_R4 = new OpCode("ldc.r4", Code.Ldc_R4, OperandType.ShortInlineR, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushr4, StackBehaviour.Pop0);
public static readonly OpCode Ldc_R8 = new OpCode("ldc.r8", Code.Ldc_R8, OperandType.InlineR, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushr8, StackBehaviour.Pop0);
public static readonly OpCode Dup = new OpCode("dup", Code.Dup, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Push1_push1, StackBehaviour.Pop1);
public static readonly OpCode Pop = new OpCode("pop", Code.Pop, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Push0, StackBehaviour.Pop1);
public static readonly OpCode Jmp = new OpCode("jmp", Code.Jmp, OperandType.InlineMethod, FlowControl.Call, OpCodeType.Primitive, StackBehaviour.Push0, StackBehaviour.Pop0);
public static readonly OpCode Call = new OpCode("call", Code.Call, OperandType.InlineMethod, FlowControl.Call, OpCodeType.Primitive, StackBehaviour.Varpush, StackBehaviour.Varpop);
public static readonly OpCode Calli = new OpCode("calli", Code.Calli, OperandType.InlineSig, FlowControl.Call, OpCodeType.Primitive, StackBehaviour.Varpush, StackBehaviour.Varpop);
public static readonly OpCode Ret = new OpCode("ret", Code.Ret, OperandType.InlineNone, FlowControl.Return, OpCodeType.Primitive, StackBehaviour.Push0, StackBehaviour.Varpop);
public static readonly OpCode Br_S = new OpCode("br.s", Code.Br_S, OperandType.ShortInlineBrTarget, FlowControl.Branch, OpCodeType.Macro, StackBehaviour.Push0, StackBehaviour.Pop0);
public static readonly OpCode Brfalse_S = new OpCode("brfalse.s", Code.Brfalse_S, OperandType.ShortInlineBrTarget, FlowControl.Cond_Branch, OpCodeType.Macro, StackBehaviour.Push0, StackBehaviour.Popi);
public static readonly OpCode Brtrue_S = new OpCode("brtrue.s", Code.Brtrue_S, OperandType.ShortInlineBrTarget, FlowControl.Cond_Branch, OpCodeType.Macro, StackBehaviour.Push0, StackBehaviour.Popi);
public static readonly OpCode Beq_S = new OpCode("beq.s", Code.Beq_S, OperandType.ShortInlineBrTarget, FlowControl.Cond_Branch, OpCodeType.Macro, StackBehaviour.Push0, StackBehaviour.Pop1_pop1);
public static readonly OpCode Bge_S = new OpCode("bge.s", Code.Bge_S, OperandType.ShortInlineBrTarget, FlowControl.Cond_Branch, OpCodeType.Macro, StackBehaviour.Push0, StackBehaviour.Pop1_pop1);
public static readonly OpCode Bgt_S = new OpCode("bgt.s", Code.Bgt_S, OperandType.ShortInlineBrTarget, FlowControl.Cond_Branch, OpCodeType.Macro, StackBehaviour.Push0, StackBehaviour.Pop1_pop1);
public static readonly OpCode Ble_S = new OpCode("ble.s", Code.Ble_S, OperandType.ShortInlineBrTarget, FlowControl.Cond_Branch, OpCodeType.Macro, StackBehaviour.Push0, StackBehaviour.Pop1_pop1);
public static readonly OpCode Blt_S = new OpCode("blt.s", Code.Blt_S, OperandType.ShortInlineBrTarget, FlowControl.Cond_Branch, OpCodeType.Macro, StackBehaviour.Push0, StackBehaviour.Pop1_pop1);
public static readonly OpCode Bne_Un_S = new OpCode("bne.un.s", Code.Bne_Un_S, OperandType.ShortInlineBrTarget, FlowControl.Cond_Branch, OpCodeType.Macro, StackBehaviour.Push0, StackBehaviour.Pop1_pop1);
public static readonly OpCode Bge_Un_S = new OpCode("bge.un.s", Code.Bge_Un_S, OperandType.ShortInlineBrTarget, FlowControl.Cond_Branch, OpCodeType.Macro, StackBehaviour.Push0, StackBehaviour.Pop1_pop1);
public static readonly OpCode Bgt_Un_S = new OpCode("bgt.un.s", Code.Bgt_Un_S, OperandType.ShortInlineBrTarget, FlowControl.Cond_Branch, OpCodeType.Macro, StackBehaviour.Push0, StackBehaviour.Pop1_pop1);
public static readonly OpCode Ble_Un_S = new OpCode("ble.un.s", Code.Ble_Un_S, OperandType.ShortInlineBrTarget, FlowControl.Cond_Branch, OpCodeType.Macro, StackBehaviour.Push0, StackBehaviour.Pop1_pop1);
public static readonly OpCode Blt_Un_S = new OpCode("blt.un.s", Code.Blt_Un_S, OperandType.ShortInlineBrTarget, FlowControl.Cond_Branch, OpCodeType.Macro, StackBehaviour.Push0, StackBehaviour.Pop1_pop1);
public static readonly OpCode Br = new OpCode("br", Code.Br, OperandType.InlineBrTarget, FlowControl.Branch, OpCodeType.Primitive, StackBehaviour.Push0, StackBehaviour.Pop0);
public static readonly OpCode Brfalse = new OpCode("brfalse", Code.Brfalse, OperandType.InlineBrTarget, FlowControl.Cond_Branch, OpCodeType.Primitive, StackBehaviour.Push0, StackBehaviour.Popi);
public static readonly OpCode Brtrue = new OpCode("brtrue", Code.Brtrue, OperandType.InlineBrTarget, FlowControl.Cond_Branch, OpCodeType.Primitive, StackBehaviour.Push0, StackBehaviour.Popi);
public static readonly OpCode Beq = new OpCode("beq", Code.Beq, OperandType.InlineBrTarget, FlowControl.Cond_Branch, OpCodeType.Macro, StackBehaviour.Push0, StackBehaviour.Pop1_pop1);
public static readonly OpCode Bge = new OpCode("bge", Code.Bge, OperandType.InlineBrTarget, FlowControl.Cond_Branch, OpCodeType.Macro, StackBehaviour.Push0, StackBehaviour.Pop1_pop1);
public static readonly OpCode Bgt = new OpCode("bgt", Code.Bgt, OperandType.InlineBrTarget, FlowControl.Cond_Branch, OpCodeType.Macro, StackBehaviour.Push0, StackBehaviour.Pop1_pop1);
public static readonly OpCode Ble = new OpCode("ble", Code.Ble, OperandType.InlineBrTarget, FlowControl.Cond_Branch, OpCodeType.Macro, StackBehaviour.Push0, StackBehaviour.Pop1_pop1);
public static readonly OpCode Blt = new OpCode("blt", Code.Blt, OperandType.InlineBrTarget, FlowControl.Cond_Branch, OpCodeType.Macro, StackBehaviour.Push0, StackBehaviour.Pop1_pop1);
public static readonly OpCode Bne_Un = new OpCode("bne.un", Code.Bne_Un, OperandType.InlineBrTarget, FlowControl.Cond_Branch, OpCodeType.Macro, StackBehaviour.Push0, StackBehaviour.Pop1_pop1);
public static readonly OpCode Bge_Un = new OpCode("bge.un", Code.Bge_Un, OperandType.InlineBrTarget, FlowControl.Cond_Branch, OpCodeType.Macro, StackBehaviour.Push0, StackBehaviour.Pop1_pop1);
public static readonly OpCode Bgt_Un = new OpCode("bgt.un", Code.Bgt_Un, OperandType.InlineBrTarget, FlowControl.Cond_Branch, OpCodeType.Macro, StackBehaviour.Push0, StackBehaviour.Pop1_pop1);
public static readonly OpCode Ble_Un = new OpCode("ble.un", Code.Ble_Un, OperandType.InlineBrTarget, FlowControl.Cond_Branch, OpCodeType.Macro, StackBehaviour.Push0, StackBehaviour.Pop1_pop1);
public static readonly OpCode Blt_Un = new OpCode("blt.un", Code.Blt_Un, OperandType.InlineBrTarget, FlowControl.Cond_Branch, OpCodeType.Macro, StackBehaviour.Push0, StackBehaviour.Pop1_pop1);
public static readonly OpCode Switch = new OpCode("switch", Code.Switch, OperandType.InlineSwitch, FlowControl.Cond_Branch, OpCodeType.Primitive, StackBehaviour.Push0, StackBehaviour.Popi);
public static readonly OpCode Ldind_I1 = new OpCode("ldind.i1", Code.Ldind_I1, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushi, StackBehaviour.Popi);
public static readonly OpCode Ldind_U1 = new OpCode("ldind.u1", Code.Ldind_U1, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushi, StackBehaviour.Popi);
public static readonly OpCode Ldind_I2 = new OpCode("ldind.i2", Code.Ldind_I2, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushi, StackBehaviour.Popi);
public static readonly OpCode Ldind_U2 = new OpCode("ldind.u2", Code.Ldind_U2, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushi, StackBehaviour.Popi);
public static readonly OpCode Ldind_I4 = new OpCode("ldind.i4", Code.Ldind_I4, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushi, StackBehaviour.Popi);
public static readonly OpCode Ldind_U4 = new OpCode("ldind.u4", Code.Ldind_U4, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushi, StackBehaviour.Popi);
public static readonly OpCode Ldind_I8 = new OpCode("ldind.i8", Code.Ldind_I8, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushi8, StackBehaviour.Popi);
public static readonly OpCode Ldind_I = new OpCode("ldind.i", Code.Ldind_I, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushi, StackBehaviour.Popi);
public static readonly OpCode Ldind_R4 = new OpCode("ldind.r4", Code.Ldind_R4, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushr4, StackBehaviour.Popi);
public static readonly OpCode Ldind_R8 = new OpCode("ldind.r8", Code.Ldind_R8, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushr8, StackBehaviour.Popi);
public static readonly OpCode Ldind_Ref = new OpCode("ldind.ref", Code.Ldind_Ref, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushref, StackBehaviour.Popi);
public static readonly OpCode Stind_Ref = new OpCode("stind.ref", Code.Stind_Ref, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Push0, StackBehaviour.Popi_popi);
public static readonly OpCode Stind_I1 = new OpCode("stind.i1", Code.Stind_I1, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Push0, StackBehaviour.Popi_popi);
public static readonly OpCode Stind_I2 = new OpCode("stind.i2", Code.Stind_I2, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Push0, StackBehaviour.Popi_popi);
public static readonly OpCode Stind_I4 = new OpCode("stind.i4", Code.Stind_I4, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Push0, StackBehaviour.Popi_popi);
public static readonly OpCode Stind_I8 = new OpCode("stind.i8", Code.Stind_I8, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Push0, StackBehaviour.Popi_popi8);
public static readonly OpCode Stind_R4 = new OpCode("stind.r4", Code.Stind_R4, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Push0, StackBehaviour.Popi_popr4);
public static readonly OpCode Stind_R8 = new OpCode("stind.r8", Code.Stind_R8, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Push0, StackBehaviour.Popi_popr8);
public static readonly OpCode Add = new OpCode("add", Code.Add, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Push1, StackBehaviour.Pop1_pop1);
public static readonly OpCode Sub = new OpCode("sub", Code.Sub, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Push1, StackBehaviour.Pop1_pop1);
public static readonly OpCode Mul = new OpCode("mul", Code.Mul, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Push1, StackBehaviour.Pop1_pop1);
public static readonly OpCode Div = new OpCode("div", Code.Div, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Push1, StackBehaviour.Pop1_pop1);
public static readonly OpCode Div_Un = new OpCode("div.un", Code.Div_Un, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Push1, StackBehaviour.Pop1_pop1);
public static readonly OpCode Rem = new OpCode("rem", Code.Rem, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Push1, StackBehaviour.Pop1_pop1);
public static readonly OpCode Rem_Un = new OpCode("rem.un", Code.Rem_Un, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Push1, StackBehaviour.Pop1_pop1);
public static readonly OpCode And = new OpCode("and", Code.And, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Push1, StackBehaviour.Pop1_pop1);
public static readonly OpCode Or = new OpCode("or", Code.Or, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Push1, StackBehaviour.Pop1_pop1);
public static readonly OpCode Xor = new OpCode("xor", Code.Xor, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Push1, StackBehaviour.Pop1_pop1);
public static readonly OpCode Shl = new OpCode("shl", Code.Shl, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Push1, StackBehaviour.Pop1_pop1);
public static readonly OpCode Shr = new OpCode("shr", Code.Shr, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Push1, StackBehaviour.Pop1_pop1);
public static readonly OpCode Shr_Un = new OpCode("shr.un", Code.Shr_Un, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Push1, StackBehaviour.Pop1_pop1);
public static readonly OpCode Neg = new OpCode("neg", Code.Neg, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Push1, StackBehaviour.Pop1);
public static readonly OpCode Not = new OpCode("not", Code.Not, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Push1, StackBehaviour.Pop1);
public static readonly OpCode Conv_I1 = new OpCode("conv.i1", Code.Conv_I1, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushi, StackBehaviour.Pop1);
public static readonly OpCode Conv_I2 = new OpCode("conv.i2", Code.Conv_I2, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushi, StackBehaviour.Pop1);
public static readonly OpCode Conv_I4 = new OpCode("conv.i4", Code.Conv_I4, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushi, StackBehaviour.Pop1);
public static readonly OpCode Conv_I8 = new OpCode("conv.i8", Code.Conv_I8, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushi8, StackBehaviour.Pop1);
public static readonly OpCode Conv_R4 = new OpCode("conv.r4", Code.Conv_R4, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushr4, StackBehaviour.Pop1);
public static readonly OpCode Conv_R8 = new OpCode("conv.r8", Code.Conv_R8, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushr8, StackBehaviour.Pop1);
public static readonly OpCode Conv_U4 = new OpCode("conv.u4", Code.Conv_U4, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushi, StackBehaviour.Pop1);
public static readonly OpCode Conv_U8 = new OpCode("conv.u8", Code.Conv_U8, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushi8, StackBehaviour.Pop1);
public static readonly OpCode Callvirt = new OpCode("callvirt", Code.Callvirt, OperandType.InlineMethod, FlowControl.Call, OpCodeType.Objmodel, StackBehaviour.Varpush, StackBehaviour.Varpop);
public static readonly OpCode Cpobj = new OpCode("cpobj", Code.Cpobj, OperandType.InlineType, FlowControl.Next, OpCodeType.Objmodel, StackBehaviour.Push0, StackBehaviour.Popi_popi);
public static readonly OpCode Ldobj = new OpCode("ldobj", Code.Ldobj, OperandType.InlineType, FlowControl.Next, OpCodeType.Objmodel, StackBehaviour.Push1, StackBehaviour.Popi);
public static readonly OpCode Ldstr = new OpCode("ldstr", Code.Ldstr, OperandType.InlineString, FlowControl.Next, OpCodeType.Objmodel, StackBehaviour.Pushref, StackBehaviour.Pop0);
public static readonly OpCode Newobj = new OpCode("newobj", Code.Newobj, OperandType.InlineMethod, FlowControl.Call, OpCodeType.Objmodel, StackBehaviour.Pushref, StackBehaviour.Varpop);
public static readonly OpCode Castclass = new OpCode("castclass", Code.Castclass, OperandType.InlineType, FlowControl.Next, OpCodeType.Objmodel, StackBehaviour.Pushref, StackBehaviour.Popref);
public static readonly OpCode Isinst = new OpCode("isinst", Code.Isinst, OperandType.InlineType, FlowControl.Next, OpCodeType.Objmodel, StackBehaviour.Pushi, StackBehaviour.Popref);
public static readonly OpCode Conv_R_Un = new OpCode("conv.r.un", Code.Conv_R_Un, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushr8, StackBehaviour.Pop1);
public static readonly OpCode Unbox = new OpCode("unbox", Code.Unbox, OperandType.InlineType, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushi, StackBehaviour.Popref);
public static readonly OpCode Throw = new OpCode("throw", Code.Throw, OperandType.InlineNone, FlowControl.Throw, OpCodeType.Objmodel, StackBehaviour.Push0, StackBehaviour.Popref);
public static readonly OpCode Ldfld = new OpCode("ldfld", Code.Ldfld, OperandType.InlineField, FlowControl.Next, OpCodeType.Objmodel, StackBehaviour.Push1, StackBehaviour.Popref);
public static readonly OpCode Ldflda = new OpCode("ldflda", Code.Ldflda, OperandType.InlineField, FlowControl.Next, OpCodeType.Objmodel, StackBehaviour.Pushi, StackBehaviour.Popref);
public static readonly OpCode Stfld = new OpCode("stfld", Code.Stfld, OperandType.InlineField, FlowControl.Next, OpCodeType.Objmodel, StackBehaviour.Push0, StackBehaviour.Popref_pop1);
public static readonly OpCode Ldsfld = new OpCode("ldsfld", Code.Ldsfld, OperandType.InlineField, FlowControl.Next, OpCodeType.Objmodel, StackBehaviour.Push1, StackBehaviour.Pop0);
public static readonly OpCode Ldsflda = new OpCode("ldsflda", Code.Ldsflda, OperandType.InlineField, FlowControl.Next, OpCodeType.Objmodel, StackBehaviour.Pushi, StackBehaviour.Pop0);
public static readonly OpCode Stsfld = new OpCode("stsfld", Code.Stsfld, OperandType.InlineField, FlowControl.Next, OpCodeType.Objmodel, StackBehaviour.Push0, StackBehaviour.Pop1);
public static readonly OpCode Stobj = new OpCode("stobj", Code.Stobj, OperandType.InlineType, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Push0, StackBehaviour.Popi_pop1);
public static readonly OpCode Conv_Ovf_I1_Un= new OpCode("conv.ovf.i1.un", Code.Conv_Ovf_I1_Un, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushi, StackBehaviour.Pop1);
public static readonly OpCode Conv_Ovf_I2_Un= new OpCode("conv.ovf.i2.un", Code.Conv_Ovf_I2_Un, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushi, StackBehaviour.Pop1);
public static readonly OpCode Conv_Ovf_I4_Un= new OpCode("conv.ovf.i4.un", Code.Conv_Ovf_I4_Un, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushi, StackBehaviour.Pop1);
public static readonly OpCode Conv_Ovf_I8_Un= new OpCode("conv.ovf.i8.un", Code.Conv_Ovf_I8_Un, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushi8, StackBehaviour.Pop1);
public static readonly OpCode Conv_Ovf_U1_Un= new OpCode("conv.ovf.u1.un", Code.Conv_Ovf_U1_Un, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushi, StackBehaviour.Pop1);
public static readonly OpCode Conv_Ovf_U2_Un= new OpCode("conv.ovf.u2.un", Code.Conv_Ovf_U2_Un, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushi, StackBehaviour.Pop1);
public static readonly OpCode Conv_Ovf_U4_Un= new OpCode("conv.ovf.u4.un", Code.Conv_Ovf_U4_Un, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushi, StackBehaviour.Pop1);
public static readonly OpCode Conv_Ovf_U8_Un= new OpCode("conv.ovf.u8.un", Code.Conv_Ovf_U8_Un, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushi8, StackBehaviour.Pop1);
public static readonly OpCode Conv_Ovf_I_Un = new OpCode("conv.ovf.i.un", Code.Conv_Ovf_I_Un, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushi, StackBehaviour.Pop1);
public static readonly OpCode Conv_Ovf_U_Un = new OpCode("conv.ovf.u.un", Code.Conv_Ovf_U_Un, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushi, StackBehaviour.Pop1);
public static readonly OpCode Box = new OpCode("box", Code.Box, OperandType.InlineType, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushref, StackBehaviour.Pop1);
public static readonly OpCode Newarr = new OpCode("newarr", Code.Newarr, OperandType.InlineType, FlowControl.Next, OpCodeType.Objmodel, StackBehaviour.Pushref, StackBehaviour.Popi);
public static readonly OpCode Ldlen = new OpCode("ldlen", Code.Ldlen, OperandType.InlineNone, FlowControl.Next, OpCodeType.Objmodel, StackBehaviour.Pushi, StackBehaviour.Popref);
public static readonly OpCode Ldelema = new OpCode("ldelema", Code.Ldelema, OperandType.InlineType, FlowControl.Next, OpCodeType.Objmodel, StackBehaviour.Pushi, StackBehaviour.Popref_popi);
public static readonly OpCode Ldelem_I1 = new OpCode("ldelem.i1", Code.Ldelem_I1, OperandType.InlineNone, FlowControl.Next, OpCodeType.Objmodel, StackBehaviour.Pushi, StackBehaviour.Popref_popi);
public static readonly OpCode Ldelem_U1 = new OpCode("ldelem.u1", Code.Ldelem_U1, OperandType.InlineNone, FlowControl.Next, OpCodeType.Objmodel, StackBehaviour.Pushi, StackBehaviour.Popref_popi);
public static readonly OpCode Ldelem_I2 = new OpCode("ldelem.i2", Code.Ldelem_I2, OperandType.InlineNone, FlowControl.Next, OpCodeType.Objmodel, StackBehaviour.Pushi, StackBehaviour.Popref_popi);
public static readonly OpCode Ldelem_U2 = new OpCode("ldelem.u2", Code.Ldelem_U2, OperandType.InlineNone, FlowControl.Next, OpCodeType.Objmodel, StackBehaviour.Pushi, StackBehaviour.Popref_popi);
public static readonly OpCode Ldelem_I4 = new OpCode("ldelem.i4", Code.Ldelem_I4, OperandType.InlineNone, FlowControl.Next, OpCodeType.Objmodel, StackBehaviour.Pushi, StackBehaviour.Popref_popi);
public static readonly OpCode Ldelem_U4 = new OpCode("ldelem.u4", Code.Ldelem_U4, OperandType.InlineNone, FlowControl.Next, OpCodeType.Objmodel, StackBehaviour.Pushi, StackBehaviour.Popref_popi);
public static readonly OpCode Ldelem_I8 = new OpCode("ldelem.i8", Code.Ldelem_I8, OperandType.InlineNone, FlowControl.Next, OpCodeType.Objmodel, StackBehaviour.Pushi8, StackBehaviour.Popref_popi);
public static readonly OpCode Ldelem_I = new OpCode("ldelem.i", Code.Ldelem_I, OperandType.InlineNone, FlowControl.Next, OpCodeType.Objmodel, StackBehaviour.Pushi, StackBehaviour.Popref_popi);
public static readonly OpCode Ldelem_R4 = new OpCode("ldelem.r4", Code.Ldelem_R4, OperandType.InlineNone, FlowControl.Next, OpCodeType.Objmodel, StackBehaviour.Pushr4, StackBehaviour.Popref_popi);
public static readonly OpCode Ldelem_R8 = new OpCode("ldelem.r8", Code.Ldelem_R8, OperandType.InlineNone, FlowControl.Next, OpCodeType.Objmodel, StackBehaviour.Pushr8, StackBehaviour.Popref_popi);
public static readonly OpCode Ldelem_Ref = new OpCode("ldelem.ref", Code.Ldelem_Ref, OperandType.InlineNone, FlowControl.Next, OpCodeType.Objmodel, StackBehaviour.Pushref, StackBehaviour.Popref_popi);
public static readonly OpCode Stelem_I = new OpCode("stelem.i", Code.Stelem_I, OperandType.InlineNone, FlowControl.Next, OpCodeType.Objmodel, StackBehaviour.Push0, StackBehaviour.Popref_popi_popi);
public static readonly OpCode Stelem_I1 = new OpCode("stelem.i1", Code.Stelem_I1, OperandType.InlineNone, FlowControl.Next, OpCodeType.Objmodel, StackBehaviour.Push0, StackBehaviour.Popref_popi_popi);
public static readonly OpCode Stelem_I2 = new OpCode("stelem.i2", Code.Stelem_I2, OperandType.InlineNone, FlowControl.Next, OpCodeType.Objmodel, StackBehaviour.Push0, StackBehaviour.Popref_popi_popi);
public static readonly OpCode Stelem_I4 = new OpCode("stelem.i4", Code.Stelem_I4, OperandType.InlineNone, FlowControl.Next, OpCodeType.Objmodel, StackBehaviour.Push0, StackBehaviour.Popref_popi_popi);
public static readonly OpCode Stelem_I8 = new OpCode("stelem.i8", Code.Stelem_I8, OperandType.InlineNone, FlowControl.Next, OpCodeType.Objmodel, StackBehaviour.Push0, StackBehaviour.Popref_popi_popi8);
public static readonly OpCode Stelem_R4 = new OpCode("stelem.r4", Code.Stelem_R4, OperandType.InlineNone, FlowControl.Next, OpCodeType.Objmodel, StackBehaviour.Push0, StackBehaviour.Popref_popi_popr4);
public static readonly OpCode Stelem_R8 = new OpCode("stelem.r8", Code.Stelem_R8, OperandType.InlineNone, FlowControl.Next, OpCodeType.Objmodel, StackBehaviour.Push0, StackBehaviour.Popref_popi_popr8);
public static readonly OpCode Stelem_Ref = new OpCode("stelem.ref", Code.Stelem_Ref, OperandType.InlineNone, FlowControl.Next, OpCodeType.Objmodel, StackBehaviour.Push0, StackBehaviour.Popref_popi_popref);
public static readonly OpCode Ldelem = new OpCode("ldelem", Code.Ldelem, OperandType.InlineType, FlowControl.Next, OpCodeType.Objmodel, StackBehaviour.Push1, StackBehaviour.Popref_popi);
public static readonly OpCode Stelem = new OpCode("stelem", Code.Stelem, OperandType.InlineType, FlowControl.Next, OpCodeType.Objmodel, StackBehaviour.Push0, StackBehaviour.Popref_popi_pop1);
public static readonly OpCode Unbox_Any = new OpCode("unbox.any", Code.Unbox_Any, OperandType.InlineType, FlowControl.Next, OpCodeType.Objmodel, StackBehaviour.Push1, StackBehaviour.Popref);
public static readonly OpCode Conv_Ovf_I1 = new OpCode("conv.ovf.i1", Code.Conv_Ovf_I1, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushi, StackBehaviour.Pop1);
public static readonly OpCode Conv_Ovf_U1 = new OpCode("conv.ovf.u1", Code.Conv_Ovf_U1, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushi, StackBehaviour.Pop1);
public static readonly OpCode Conv_Ovf_I2 = new OpCode("conv.ovf.i2", Code.Conv_Ovf_I2, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushi, StackBehaviour.Pop1);
public static readonly OpCode Conv_Ovf_U2 = new OpCode("conv.ovf.u2", Code.Conv_Ovf_U2, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushi, StackBehaviour.Pop1);
public static readonly OpCode Conv_Ovf_I4 = new OpCode("conv.ovf.i4", Code.Conv_Ovf_I4, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushi, StackBehaviour.Pop1);
public static readonly OpCode Conv_Ovf_U4 = new OpCode("conv.ovf.u4", Code.Conv_Ovf_U4, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushi, StackBehaviour.Pop1);
public static readonly OpCode Conv_Ovf_I8 = new OpCode("conv.ovf.i8", Code.Conv_Ovf_I8, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushi8, StackBehaviour.Pop1);
public static readonly OpCode Conv_Ovf_U8 = new OpCode("conv.ovf.u8", Code.Conv_Ovf_U8, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushi8, StackBehaviour.Pop1);
public static readonly OpCode Refanyval = new OpCode("refanyval", Code.Refanyval, OperandType.InlineType, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushi, StackBehaviour.Pop1);
public static readonly OpCode Ckfinite = new OpCode("ckfinite", Code.Ckfinite, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushr8, StackBehaviour.Pop1);
public static readonly OpCode Mkrefany = new OpCode("mkrefany", Code.Mkrefany, OperandType.InlineType, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Push1, StackBehaviour.Popi);
public static readonly OpCode Ldtoken = new OpCode("ldtoken", Code.Ldtoken, OperandType.InlineTok, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushi, StackBehaviour.Pop0);
public static readonly OpCode Conv_U2 = new OpCode("conv.u2", Code.Conv_U2, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushi, StackBehaviour.Pop1);
public static readonly OpCode Conv_U1 = new OpCode("conv.u1", Code.Conv_U1, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushi, StackBehaviour.Pop1);
public static readonly OpCode Conv_I = new OpCode("conv.i", Code.Conv_I, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushi, StackBehaviour.Pop1);
public static readonly OpCode Conv_Ovf_I = new OpCode("conv.ovf.i", Code.Conv_Ovf_I, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushi, StackBehaviour.Pop1);
public static readonly OpCode Conv_Ovf_U = new OpCode("conv.ovf.u", Code.Conv_Ovf_U, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushi, StackBehaviour.Pop1);
public static readonly OpCode Add_Ovf = new OpCode("add.ovf", Code.Add_Ovf, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Push1, StackBehaviour.Pop1_pop1);
public static readonly OpCode Add_Ovf_Un = new OpCode("add.ovf.un", Code.Add_Ovf_Un, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Push1, StackBehaviour.Pop1_pop1);
public static readonly OpCode Mul_Ovf = new OpCode("mul.ovf", Code.Mul_Ovf, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Push1, StackBehaviour.Pop1_pop1);
public static readonly OpCode Mul_Ovf_Un = new OpCode("mul.ovf.un", Code.Mul_Ovf_Un, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Push1, StackBehaviour.Pop1_pop1);
public static readonly OpCode Sub_Ovf = new OpCode("sub.ovf", Code.Sub_Ovf, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Push1, StackBehaviour.Pop1_pop1);
public static readonly OpCode Sub_Ovf_Un = new OpCode("sub.ovf.un", Code.Sub_Ovf_Un, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Push1, StackBehaviour.Pop1_pop1);
public static readonly OpCode Endfinally = new OpCode("endfinally", Code.Endfinally, OperandType.InlineNone, FlowControl.Return, OpCodeType.Primitive, StackBehaviour.Push0, StackBehaviour.PopAll);
public static readonly OpCode Leave = new OpCode("leave", Code.Leave, OperandType.InlineBrTarget, FlowControl.Branch, OpCodeType.Primitive, StackBehaviour.Push0, StackBehaviour.PopAll);
public static readonly OpCode Leave_S = new OpCode("leave.s", Code.Leave_S, OperandType.ShortInlineBrTarget, FlowControl.Branch, OpCodeType.Primitive, StackBehaviour.Push0, StackBehaviour.PopAll);
public static readonly OpCode Stind_I = new OpCode("stind.i", Code.Stind_I, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Push0, StackBehaviour.Popi_popi);
public static readonly OpCode Conv_U = new OpCode("conv.u", Code.Conv_U, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushi, StackBehaviour.Pop1);
public static readonly OpCode Prefix7 = new OpCode("prefix7", Code.Prefix7, OperandType.InlineNone, FlowControl.Meta, OpCodeType.Nternal, StackBehaviour.Push0, StackBehaviour.Pop0);
public static readonly OpCode Prefix6 = new OpCode("prefix6", Code.Prefix6, OperandType.InlineNone, FlowControl.Meta, OpCodeType.Nternal, StackBehaviour.Push0, StackBehaviour.Pop0);
public static readonly OpCode Prefix5 = new OpCode("prefix5", Code.Prefix5, OperandType.InlineNone, FlowControl.Meta, OpCodeType.Nternal, StackBehaviour.Push0, StackBehaviour.Pop0);
public static readonly OpCode Prefix4 = new OpCode("prefix4", Code.Prefix4, OperandType.InlineNone, FlowControl.Meta, OpCodeType.Nternal, StackBehaviour.Push0, StackBehaviour.Pop0);
public static readonly OpCode Prefix3 = new OpCode("prefix3", Code.Prefix3, OperandType.InlineNone, FlowControl.Meta, OpCodeType.Nternal, StackBehaviour.Push0, StackBehaviour.Pop0);
public static readonly OpCode Prefix2 = new OpCode("prefix2", Code.Prefix2, OperandType.InlineNone, FlowControl.Meta, OpCodeType.Nternal, StackBehaviour.Push0, StackBehaviour.Pop0);
public static readonly OpCode Prefix1 = new OpCode("prefix1", Code.Prefix1, OperandType.InlineNone, FlowControl.Meta, OpCodeType.Nternal, StackBehaviour.Push0, StackBehaviour.Pop0);
public static readonly OpCode Prefixref = new OpCode("prefixref", Code.Prefixref, OperandType.InlineNone, FlowControl.Meta, OpCodeType.Nternal, StackBehaviour.Push0, StackBehaviour.Pop0);
public static readonly OpCode Arglist = new OpCode("arglist", Code.Arglist, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushi, StackBehaviour.Pop0);
public static readonly OpCode Ceq = new OpCode("ceq", Code.Ceq, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushi, StackBehaviour.Pop1_pop1);
public static readonly OpCode Cgt = new OpCode("cgt", Code.Cgt, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushi, StackBehaviour.Pop1_pop1);
public static readonly OpCode Cgt_Un = new OpCode("cgt.un", Code.Cgt_Un, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushi, StackBehaviour.Pop1_pop1);
public static readonly OpCode Clt = new OpCode("clt", Code.Clt, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushi, StackBehaviour.Pop1_pop1);
public static readonly OpCode Clt_Un = new OpCode("clt.un", Code.Clt_Un, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushi, StackBehaviour.Pop1_pop1);
public static readonly OpCode Ldftn = new OpCode("ldftn", Code.Ldftn, OperandType.InlineMethod, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushi, StackBehaviour.Pop0);
public static readonly OpCode Ldvirtftn = new OpCode("ldvirtftn", Code.Ldvirtftn, OperandType.InlineMethod, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushi, StackBehaviour.Popref);
public static readonly OpCode Ldarg = new OpCode("ldarg", Code.Ldarg, OperandType.InlineVar, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Push1, StackBehaviour.Pop0);
public static readonly OpCode Ldarga = new OpCode("ldarga", Code.Ldarga, OperandType.InlineVar, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushi, StackBehaviour.Pop0);
public static readonly OpCode Starg = new OpCode("starg", Code.Starg, OperandType.InlineVar, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Push0, StackBehaviour.Pop1);
public static readonly OpCode Ldloc = new OpCode("ldloc", Code.Ldloc, OperandType.InlineVar, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Push1, StackBehaviour.Pop0);
public static readonly OpCode Ldloca = new OpCode("ldloca", Code.Ldloca, OperandType.InlineVar, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushi, StackBehaviour.Pop0);
public static readonly OpCode Stloc = new OpCode("stloc", Code.Stloc, OperandType.InlineVar, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Push0, StackBehaviour.Pop1);
public static readonly OpCode Localloc = new OpCode("localloc", Code.Localloc, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushi, StackBehaviour.Popi);
public static readonly OpCode Endfilter = new OpCode("endfilter", Code.Endfilter, OperandType.InlineNone, FlowControl.Return, OpCodeType.Primitive, StackBehaviour.Push0, StackBehaviour.Popi);
public static readonly OpCode Unaligned = new OpCode("unaligned.", Code.Unaligned, OperandType.ShortInlineI, FlowControl.Meta, OpCodeType.Prefix, StackBehaviour.Push0, StackBehaviour.Pop0);
public static readonly OpCode Volatile = new OpCode("volatile.", Code.Volatile, OperandType.InlineNone, FlowControl.Meta, OpCodeType.Prefix, StackBehaviour.Push0, StackBehaviour.Pop0);
public static readonly OpCode Tailcall = new OpCode("tail.", Code.Tailcall, OperandType.InlineNone, FlowControl.Meta, OpCodeType.Prefix, StackBehaviour.Push0, StackBehaviour.Pop0);
public static readonly OpCode Initobj = new OpCode("initobj", Code.Initobj, OperandType.InlineType, FlowControl.Next, OpCodeType.Objmodel, StackBehaviour.Push0, StackBehaviour.Popi);
public static readonly OpCode Constrained = new OpCode("constrained.", Code.Constrained, OperandType.InlineType, FlowControl.Meta, OpCodeType.Prefix, StackBehaviour.Push0, StackBehaviour.Pop0);
public static readonly OpCode Cpblk = new OpCode("cpblk", Code.Cpblk, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Push0, StackBehaviour.Popi_popi_popi);
public static readonly OpCode Initblk = new OpCode("initblk", Code.Initblk, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Push0, StackBehaviour.Popi_popi_popi);
public static readonly OpCode No = new OpCode("no.", Code.No, OperandType.ShortInlineI, FlowControl.Meta, OpCodeType.Prefix, StackBehaviour.Push0, StackBehaviour.Pop0);
public static readonly OpCode Rethrow = new OpCode("rethrow", Code.Rethrow, OperandType.InlineNone, FlowControl.Throw, OpCodeType.Objmodel, StackBehaviour.Push0, StackBehaviour.Pop0);
public static readonly OpCode Sizeof = new OpCode("sizeof", Code.Sizeof, OperandType.InlineType, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushi, StackBehaviour.Pop0);
public static readonly OpCode Refanytype = new OpCode("refanytype", Code.Refanytype, OperandType.InlineNone, FlowControl.Next, OpCodeType.Primitive, StackBehaviour.Pushi, StackBehaviour.Pop1);
public static readonly OpCode Readonly = new OpCode("readonly.", Code.Readonly, OperandType.InlineNone, FlowControl.Meta, OpCodeType.Prefix, StackBehaviour.Push0, StackBehaviour.Pop0);
#pragma warning restore
static OpCodes() {
// The OpCode ctor copies itself to one of these arrays. Whatever are still null
// are unsupported opcodes. Set them all to UNKNOWN1 or UNKNOWN2.
for (int i = 0; i < OneByteOpCodes.Length; i++) {
if (OneByteOpCodes[i] is null)
OneByteOpCodes[i] = UNKNOWN1;
}
for (int i = 0; i < TwoByteOpCodes.Length; i++) {
if (TwoByteOpCodes[i] is null)
TwoByteOpCodes[i] = UNKNOWN2;
}
}
}
}

View File

@ -1,53 +0,0 @@
// dnlib: See LICENSE.txt for more info
using dnlib.DotNet.MD;
namespace dnlib.DotNet.Emit {
/// <summary>
/// CIL opcode operand type
/// </summary>
public enum OperandType : byte {
/// <summary>4-byte relative instruction offset</summary>
InlineBrTarget,
/// <summary>4-byte field token (<see cref="Table.Field"/> or <see cref="Table.MemberRef"/>)</summary>
InlineField,
/// <summary>int32</summary>
InlineI,
/// <summary>int64</summary>
InlineI8,
/// <summary>4-byte method token (<see cref="Table.Method"/>, <see cref="Table.MemberRef"/>
/// or <see cref="Table.MethodSpec"/>)</summary>
InlineMethod,
/// <summary>No operand</summary>
InlineNone,
/// <summary>Never used</summary>
InlinePhi,
/// <summary>64-bit real</summary>
InlineR,
/// <summary/>
NOT_USED_8,
/// <summary>4-byte method sig token (<see cref="Table.StandAloneSig"/>)</summary>
InlineSig,
/// <summary>4-byte string token (<c>0x70xxxxxx</c>)</summary>
InlineString,
/// <summary>4-byte count N followed by N 4-byte relative instruction offsets</summary>
InlineSwitch,
/// <summary>4-byte token (<see cref="Table.Field"/>, <see cref="Table.MemberRef"/>,
/// <see cref="Table.Method"/>, <see cref="Table.MethodSpec"/>, <see cref="Table.TypeDef"/>,
/// <see cref="Table.TypeRef"/> or <see cref="Table.TypeSpec"/>)</summary>
InlineTok,
/// <summary>4-byte type token (<see cref="Table.TypeDef"/>, <see cref="Table.TypeRef"/> or
/// <see cref="Table.TypeSpec"/>)</summary>
InlineType,
/// <summary>2-byte param/local index</summary>
InlineVar,
/// <summary>1-byte relative instruction offset</summary>
ShortInlineBrTarget,
/// <summary>1-byte sbyte (<see cref="Code.Ldc_I4_S"/>) or byte (the rest)</summary>
ShortInlineI,
/// <summary>32-bit real</summary>
ShortInlineR,
/// <summary>1-byte param/local index</summary>
ShortInlineVar,
}
}

View File

@ -1,69 +0,0 @@
// dnlib: See LICENSE.txt for more info
namespace dnlib.DotNet.Emit {
/// <summary>
/// CIL opcode stack behavior
/// </summary>
public enum StackBehaviour : byte {
/// <summary/>
Pop0,
/// <summary/>
Pop1,
/// <summary/>
Pop1_pop1,
/// <summary/>
Popi,
/// <summary/>
Popi_pop1,
/// <summary/>
Popi_popi,
/// <summary/>
Popi_popi8,
/// <summary/>
Popi_popi_popi,
/// <summary/>
Popi_popr4,
/// <summary/>
Popi_popr8,
/// <summary/>
Popref,
/// <summary/>
Popref_pop1,
/// <summary/>
Popref_popi,
/// <summary/>
Popref_popi_popi,
/// <summary/>
Popref_popi_popi8,
/// <summary/>
Popref_popi_popr4,
/// <summary/>
Popref_popi_popr8,
/// <summary/>
Popref_popi_popref,
/// <summary/>
Push0,
/// <summary/>
Push1,
/// <summary/>
Push1_push1,
/// <summary/>
Pushi,
/// <summary/>
Pushi8,
/// <summary/>
Pushr4,
/// <summary/>
Pushr8,
/// <summary/>
Pushref,
/// <summary/>
Varpop,
/// <summary/>
Varpush,
/// <summary/>
Popref_popi_pop1,
/// <summary/>
PopAll = 0xFF,
}
}

View File

@ -1,16 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System;
namespace dnlib.DotNet {
/// <summary>
/// Event attributes, see CorHdr.h/CorEventAttr
/// </summary>
[Flags]
public enum EventAttributes : ushort {
/// <summary>event is special. Name describes how.</summary>
SpecialName = 0x0200,
/// <summary>Runtime(metadata internal APIs) should check name encoding.</summary>
RTSpecialName = 0x0400,
}
}

View File

@ -1,416 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using dnlib.DotNet.MD;
using dnlib.DotNet.Pdb;
using dnlib.Threading;
namespace dnlib.DotNet {
/// <summary>
/// A high-level representation of a row in the Event table
/// </summary>
public abstract class EventDef : IHasCustomAttribute, IHasSemantic, IHasCustomDebugInformation, IFullName, IMemberDef {
/// <summary>
/// The row id in its table
/// </summary>
protected uint rid;
#if THREAD_SAFE
readonly Lock theLock = Lock.Create();
#endif
/// <inheritdoc/>
public MDToken MDToken => new MDToken(Table.Event, rid);
/// <inheritdoc/>
public uint Rid {
get => rid;
set => rid = value;
}
/// <inheritdoc/>
public int HasCustomAttributeTag => 10;
/// <inheritdoc/>
public int HasSemanticTag => 0;
/// <summary>
/// From column Event.EventFlags
/// </summary>
public EventAttributes Attributes {
get => (EventAttributes)attributes;
set => attributes = (int)value;
}
/// <summary/>
protected int attributes;
/// <summary>
/// From column Event.Name
/// </summary>
public UTF8String Name {
get => name;
set => name = value;
}
/// <summary>Name</summary>
protected UTF8String name;
/// <summary>
/// From column Event.EventType
/// </summary>
public ITypeDefOrRef EventType {
get => eventType;
set => eventType = value;
}
/// <summary/>
protected ITypeDefOrRef eventType;
/// <summary>
/// Gets all custom attributes
/// </summary>
public CustomAttributeCollection CustomAttributes {
get {
if (customAttributes is null)
InitializeCustomAttributes();
return customAttributes;
}
}
/// <summary/>
protected CustomAttributeCollection customAttributes;
/// <summary>Initializes <see cref="customAttributes"/></summary>
protected virtual void InitializeCustomAttributes() =>
Interlocked.CompareExchange(ref customAttributes, new CustomAttributeCollection(), null);
/// <inheritdoc/>
public int HasCustomDebugInformationTag => 10;
/// <inheritdoc/>
public bool HasCustomDebugInfos => CustomDebugInfos.Count > 0;
/// <summary>
/// Gets all custom debug infos
/// </summary>
public IList<PdbCustomDebugInfo> CustomDebugInfos {
get {
if (customDebugInfos is null)
InitializeCustomDebugInfos();
return customDebugInfos;
}
}
/// <summary/>
protected IList<PdbCustomDebugInfo> customDebugInfos;
/// <summary>Initializes <see cref="customDebugInfos"/></summary>
protected virtual void InitializeCustomDebugInfos() =>
Interlocked.CompareExchange(ref customDebugInfos, new List<PdbCustomDebugInfo>(), null);
/// <summary>
/// Gets/sets the adder method
/// </summary>
public MethodDef AddMethod {
get {
if (otherMethods is null)
InitializeEventMethods();
return addMethod;
}
set {
if (otherMethods is null)
InitializeEventMethods();
addMethod = value;
}
}
/// <summary>
/// Gets/sets the invoker method
/// </summary>
public MethodDef InvokeMethod {
get {
if (otherMethods is null)
InitializeEventMethods();
return invokeMethod;
}
set {
if (otherMethods is null)
InitializeEventMethods();
invokeMethod = value;
}
}
/// <summary>
/// Gets/sets the remover method
/// </summary>
public MethodDef RemoveMethod {
get {
if (otherMethods is null)
InitializeEventMethods();
return removeMethod;
}
set {
if (otherMethods is null)
InitializeEventMethods();
removeMethod = value;
}
}
/// <summary>
/// Gets the other methods
/// </summary>
public IList<MethodDef> OtherMethods {
get {
if (otherMethods is null)
InitializeEventMethods();
return otherMethods;
}
}
void InitializeEventMethods() {
#if THREAD_SAFE
theLock.EnterWriteLock(); try {
#endif
if (otherMethods is null)
InitializeEventMethods_NoLock();
#if THREAD_SAFE
} finally { theLock.ExitWriteLock(); }
#endif
}
/// <summary>
/// Initializes <see cref="otherMethods"/>, <see cref="addMethod"/>,
/// <see cref="invokeMethod"/> and <see cref="removeMethod"/>.
/// </summary>
protected virtual void InitializeEventMethods_NoLock() =>
otherMethods = new List<MethodDef>();
/// <summary/>
protected MethodDef addMethod;
/// <summary/>
protected MethodDef invokeMethod;
/// <summary/>
protected MethodDef removeMethod;
/// <summary/>
protected IList<MethodDef> otherMethods;
/// <summary>Reset <see cref="AddMethod"/>, <see cref="InvokeMethod"/>, <see cref="RemoveMethod"/>, <see cref="OtherMethods"/></summary>
protected void ResetMethods() => otherMethods = null;
/// <summary>
/// <c>true</c> if there are no methods attached to this event
/// </summary>
public bool IsEmpty =>
// The first property access initializes the other fields we access here
AddMethod is null &&
removeMethod is null &&
invokeMethod is null &&
otherMethods.Count == 0;
/// <inheritdoc/>
public bool HasCustomAttributes => CustomAttributes.Count > 0;
/// <summary>
/// <c>true</c> if <see cref="OtherMethods"/> is not empty
/// </summary>
public bool HasOtherMethods => OtherMethods.Count > 0;
/// <summary>
/// Gets/sets the declaring type (owner type)
/// </summary>
public TypeDef DeclaringType {
get => declaringType2;
set {
var currentDeclaringType = DeclaringType2;
if (currentDeclaringType == value)
return;
if (currentDeclaringType is not null)
currentDeclaringType.Events.Remove(this); // Will set DeclaringType2 = null
if (value is not null)
value.Events.Add(this); // Will set DeclaringType2 = value
}
}
/// <inheritdoc/>
ITypeDefOrRef IMemberRef.DeclaringType => declaringType2;
/// <summary>
/// Called by <see cref="DeclaringType"/> and should normally not be called by any user
/// code. Use <see cref="DeclaringType"/> instead. Only call this if you must set the
/// declaring type without inserting it in the declaring type's method list.
/// </summary>
public TypeDef DeclaringType2 {
get => declaringType2;
set => declaringType2 = value;
}
/// <summary/>
protected TypeDef declaringType2;
/// <inheritdoc/>
public ModuleDef Module => declaringType2?.Module;
/// <summary>
/// Gets the full name of the event
/// </summary>
public string FullName => FullNameFactory.EventFullName(declaringType2?.FullName, name, eventType, null, null);
bool IIsTypeOrMethod.IsType => false;
bool IIsTypeOrMethod.IsMethod => false;
bool IMemberRef.IsField => false;
bool IMemberRef.IsTypeSpec => false;
bool IMemberRef.IsTypeRef => false;
bool IMemberRef.IsTypeDef => false;
bool IMemberRef.IsMethodSpec => false;
bool IMemberRef.IsMethodDef => false;
bool IMemberRef.IsMemberRef => false;
bool IMemberRef.IsFieldDef => false;
bool IMemberRef.IsPropertyDef => false;
bool IMemberRef.IsEventDef => true;
bool IMemberRef.IsGenericParam => false;
/// <summary>
/// Set or clear flags in <see cref="attributes"/>
/// </summary>
/// <param name="set"><c>true</c> if flags should be set, <c>false</c> if flags should
/// be cleared</param>
/// <param name="flags">Flags to set or clear</param>
void ModifyAttributes(bool set, EventAttributes flags) {
if (set)
attributes |= (int)flags;
else
attributes &= ~(int)flags;
}
/// <summary>
/// Gets/sets the <see cref="EventAttributes.SpecialName"/> bit
/// </summary>
public bool IsSpecialName {
get => ((EventAttributes)attributes & EventAttributes.SpecialName) != 0;
set => ModifyAttributes(value, EventAttributes.SpecialName);
}
/// <summary>
/// Gets/sets the <see cref="EventAttributes.RTSpecialName"/> bit
/// </summary>
public bool IsRuntimeSpecialName {
get => ((EventAttributes)attributes & EventAttributes.RTSpecialName) != 0;
set => ModifyAttributes(value, EventAttributes.RTSpecialName);
}
/// <inheritdoc/>
public override string ToString() => FullName;
}
/// <summary>
/// An Event row created by the user and not present in the original .NET file
/// </summary>
public class EventDefUser : EventDef {
/// <summary>
/// Default constructor
/// </summary>
public EventDefUser() {
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="name">Name</param>
public EventDefUser(UTF8String name)
: this(name, null, 0) {
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="name">Name</param>
/// <param name="type">Type</param>
public EventDefUser(UTF8String name, ITypeDefOrRef type)
: this(name, type, 0) {
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="name">Name</param>
/// <param name="type">Type</param>
/// <param name="flags">Flags</param>
public EventDefUser(UTF8String name, ITypeDefOrRef type, EventAttributes flags) {
this.name = name;
eventType = type;
attributes = (int)flags;
}
}
/// <summary>
/// Created from a row in the Event table
/// </summary>
sealed class EventDefMD : EventDef, IMDTokenProviderMD {
/// <summary>The module where this instance is located</summary>
readonly ModuleDefMD readerModule;
readonly uint origRid;
/// <inheritdoc/>
public uint OrigRid => origRid;
/// <inheritdoc/>
protected override void InitializeCustomAttributes() {
var list = readerModule.Metadata.GetCustomAttributeRidList(Table.Event, origRid);
var tmp = new CustomAttributeCollection(list.Count, list, (list2, index) => readerModule.ReadCustomAttribute(list[index]));
Interlocked.CompareExchange(ref customAttributes, tmp, null);
}
/// <inheritdoc/>
protected override void InitializeCustomDebugInfos() {
var list = new List<PdbCustomDebugInfo>();
readerModule.InitializeCustomDebugInfos(new MDToken(MDToken.Table, origRid), new GenericParamContext(declaringType2), list);
Interlocked.CompareExchange(ref customDebugInfos, list, null);
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="readerModule">The module which contains this <c>Event</c> row</param>
/// <param name="rid">Row ID</param>
/// <exception cref="ArgumentNullException">If <paramref name="readerModule"/> is <c>null</c></exception>
/// <exception cref="ArgumentException">If <paramref name="rid"/> is invalid</exception>
public EventDefMD(ModuleDefMD readerModule, uint rid) {
#if DEBUG
if (readerModule is null)
throw new ArgumentNullException("readerModule");
if (readerModule.TablesStream.EventTable.IsInvalidRID(rid))
throw new BadImageFormatException($"Event rid {rid} does not exist");
#endif
origRid = rid;
this.rid = rid;
this.readerModule = readerModule;
bool b = readerModule.TablesStream.TryReadEventRow(origRid, out var row);
Debug.Assert(b);
attributes = row.EventFlags;
name = readerModule.StringsStream.ReadNoNull(row.Name);
declaringType2 = readerModule.GetOwnerType(this);
eventType = readerModule.ResolveTypeDefOrRef(row.EventType, new GenericParamContext(declaringType2));
}
internal EventDefMD InitializeAll() {
MemberMDInitializer.Initialize(Attributes);
MemberMDInitializer.Initialize(Name);
MemberMDInitializer.Initialize(EventType);
MemberMDInitializer.Initialize(CustomAttributes);
MemberMDInitializer.Initialize(AddMethod);
MemberMDInitializer.Initialize(InvokeMethod);
MemberMDInitializer.Initialize(RemoveMethod);
MemberMDInitializer.Initialize(OtherMethods);
MemberMDInitializer.Initialize(DeclaringType);
return this;
}
/// <inheritdoc/>
protected override void InitializeEventMethods_NoLock() {
IList<MethodDef> newOtherMethods;
var dt = declaringType2 as TypeDefMD;
if (dt is null)
newOtherMethods = new List<MethodDef>();
else
dt.InitializeEvent(this, out addMethod, out invokeMethod, out removeMethod, out newOtherMethods);
otherMethods = newOtherMethods;
}
}
}

View File

@ -1,690 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System;
using System.Collections.Generic;
using System.Threading;
using dnlib.DotNet.MD;
using dnlib.DotNet.Pdb;
using dnlib.Threading;
namespace dnlib.DotNet {
/// <summary>
/// A high-level representation of a row in the ExportedType table
/// </summary>
public abstract class ExportedType : IHasCustomAttribute, IImplementation, IHasCustomDebugInformation, IType {
/// <summary>
/// The row id in its table
/// </summary>
protected uint rid;
#if THREAD_SAFE
readonly Lock theLock = Lock.Create();
#endif
/// <summary>
/// The owner module
/// </summary>
protected ModuleDef module;
/// <inheritdoc/>
public MDToken MDToken => new MDToken(Table.ExportedType, rid);
/// <inheritdoc/>
public uint Rid {
get => rid;
set => rid = value;
}
/// <inheritdoc/>
public int HasCustomAttributeTag => 17;
/// <inheritdoc/>
public int ImplementationTag => 2;
/// <summary>
/// Gets all custom attributes
/// </summary>
public CustomAttributeCollection CustomAttributes {
get {
if (customAttributes is null)
InitializeCustomAttributes();
return customAttributes;
}
}
/// <summary/>
protected CustomAttributeCollection customAttributes;
/// <summary>Initializes <see cref="customAttributes"/></summary>
protected virtual void InitializeCustomAttributes() =>
Interlocked.CompareExchange(ref customAttributes, new CustomAttributeCollection(), null);
/// <inheritdoc/>
public bool HasCustomAttributes => CustomAttributes.Count > 0;
/// <inheritdoc/>
public int HasCustomDebugInformationTag => 17;
/// <inheritdoc/>
public bool HasCustomDebugInfos => CustomDebugInfos.Count > 0;
/// <summary>
/// Gets all custom debug infos
/// </summary>
public IList<PdbCustomDebugInfo> CustomDebugInfos {
get {
if (customDebugInfos is null)
InitializeCustomDebugInfos();
return customDebugInfos;
}
}
/// <summary/>
protected IList<PdbCustomDebugInfo> customDebugInfos;
/// <summary>Initializes <see cref="customDebugInfos"/></summary>
protected virtual void InitializeCustomDebugInfos() =>
Interlocked.CompareExchange(ref customDebugInfos, new List<PdbCustomDebugInfo>(), null);
/// <inheritdoc/>
public bool IsValueType {
get {
var td = Resolve();
return td is not null && td.IsValueType;
}
}
/// <inheritdoc/>
public bool IsPrimitive => this.IsPrimitive();
/// <inheritdoc/>
string IType.TypeName => TypeName;
/// <inheritdoc/>
public UTF8String Name {
get => typeName;
set => typeName = value;
}
/// <inheritdoc/>
public string ReflectionName => FullNameFactory.Name(this, true, null);
/// <inheritdoc/>
public string Namespace => TypeNamespace;
/// <inheritdoc/>
public string ReflectionNamespace => FullNameFactory.Namespace(this, true, null);
/// <inheritdoc/>
public string FullName => FullNameFactory.FullName(this, false, null, null);
/// <inheritdoc/>
public string ReflectionFullName => FullNameFactory.FullName(this, true, null, null);
/// <inheritdoc/>
public string AssemblyQualifiedName => FullNameFactory.AssemblyQualifiedName(this, null, null);
/// <inheritdoc/>
public IAssembly DefinitionAssembly => FullNameFactory.DefinitionAssembly(this);
/// <inheritdoc/>
public IScope Scope => FullNameFactory.Scope(this);
/// <inheritdoc/>
public ITypeDefOrRef ScopeType => FullNameFactory.ScopeType(this);
/// <summary>
/// Always returns <c>false</c> since a <see cref="ExportedType"/> does not contain any
/// <see cref="GenericVar"/> or <see cref="GenericMVar"/>.
/// </summary>
public bool ContainsGenericParameter => false;
/// <inheritdoc/>
public ModuleDef Module => module;
/// <inheritdoc/>
bool IIsTypeOrMethod.IsMethod => false;
/// <inheritdoc/>
bool IIsTypeOrMethod.IsType => true;
/// <inheritdoc/>
int IGenericParameterProvider.NumberOfGenericParameters => 0;
/// <summary>
/// From column ExportedType.Flags
/// </summary>
public TypeAttributes Attributes {
get => (TypeAttributes)attributes;
set => attributes = (int)value;
}
/// <summary>Attributes</summary>
protected int attributes;
/// <summary>
/// From column ExportedType.TypeDefId
/// </summary>
public uint TypeDefId {
get => typeDefId;
set => typeDefId = value;
}
/// <summary/>
protected uint typeDefId;
/// <summary>
/// From column ExportedType.TypeName
/// </summary>
public UTF8String TypeName {
get => typeName;
set => typeName = value;
}
/// <summary/>
protected UTF8String typeName;
/// <summary>
/// From column ExportedType.TypeNamespace
/// </summary>
public UTF8String TypeNamespace {
get => typeNamespace;
set => typeNamespace = value;
}
/// <summary/>
protected UTF8String typeNamespace;
/// <summary>
/// From column ExportedType.Implementation
/// </summary>
public IImplementation Implementation {
get {
if (!implementation_isInitialized)
InitializeImplementation();
return implementation;
}
set {
#if THREAD_SAFE
theLock.EnterWriteLock(); try {
#endif
implementation = value;
implementation_isInitialized = true;
#if THREAD_SAFE
} finally { theLock.ExitWriteLock(); }
#endif
}
}
/// <summary/>
protected IImplementation implementation;
/// <summary/>
protected bool implementation_isInitialized;
void InitializeImplementation() {
#if THREAD_SAFE
theLock.EnterWriteLock(); try {
#endif
if (implementation_isInitialized)
return;
implementation = GetImplementation_NoLock();
implementation_isInitialized = true;
#if THREAD_SAFE
} finally { theLock.ExitWriteLock(); }
#endif
}
/// <summary>Called to initialize <see cref="implementation"/></summary>
protected virtual IImplementation GetImplementation_NoLock() => null;
/// <summary>
/// <c>true</c> if it's nested within another <see cref="ExportedType"/>
/// </summary>
public bool IsNested => DeclaringType is not null;
/// <summary>
/// Gets the declaring type, if any
/// </summary>
public ExportedType DeclaringType {
get {
if (!implementation_isInitialized)
InitializeImplementation();
return implementation as ExportedType;
}
}
/// <summary>
/// Modify <see cref="attributes"/> property: <see cref="attributes"/> =
/// (<see cref="attributes"/> &amp; <paramref name="andMask"/>) | <paramref name="orMask"/>.
/// </summary>
/// <param name="andMask">Value to <c>AND</c></param>
/// <param name="orMask">Value to OR</param>
void ModifyAttributes(TypeAttributes andMask, TypeAttributes orMask) =>
attributes = (attributes & (int)andMask) | (int)orMask;
/// <summary>
/// Set or clear flags in <see cref="attributes"/>
/// </summary>
/// <param name="set"><c>true</c> if flags should be set, <c>false</c> if flags should
/// be cleared</param>
/// <param name="flags">Flags to set or clear</param>
void ModifyAttributes(bool set, TypeAttributes flags) {
if (set)
attributes |= (int)flags;
else
attributes &= ~(int)flags;
}
/// <summary>
/// Gets/sets the visibility
/// </summary>
public TypeAttributes Visibility {
get => (TypeAttributes)attributes & TypeAttributes.VisibilityMask;
set => ModifyAttributes(~TypeAttributes.VisibilityMask, value & TypeAttributes.VisibilityMask);
}
/// <summary>
/// <c>true</c> if <see cref="TypeAttributes.NotPublic"/> is set
/// </summary>
public bool IsNotPublic => ((TypeAttributes)attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NotPublic;
/// <summary>
/// <c>true</c> if <see cref="TypeAttributes.Public"/> is set
/// </summary>
public bool IsPublic => ((TypeAttributes)attributes & TypeAttributes.VisibilityMask) == TypeAttributes.Public;
/// <summary>
/// <c>true</c> if <see cref="TypeAttributes.NestedPublic"/> is set
/// </summary>
public bool IsNestedPublic => ((TypeAttributes)attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedPublic;
/// <summary>
/// <c>true</c> if <see cref="TypeAttributes.NestedPrivate"/> is set
/// </summary>
public bool IsNestedPrivate => ((TypeAttributes)attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedPrivate;
/// <summary>
/// <c>true</c> if <see cref="TypeAttributes.NestedFamily"/> is set
/// </summary>
public bool IsNestedFamily => ((TypeAttributes)attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamily;
/// <summary>
/// <c>true</c> if <see cref="TypeAttributes.NestedAssembly"/> is set
/// </summary>
public bool IsNestedAssembly => ((TypeAttributes)attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedAssembly;
/// <summary>
/// <c>true</c> if <see cref="TypeAttributes.NestedFamANDAssem"/> is set
/// </summary>
public bool IsNestedFamilyAndAssembly => ((TypeAttributes)attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamANDAssem;
/// <summary>
/// <c>true</c> if <see cref="TypeAttributes.NestedFamORAssem"/> is set
/// </summary>
public bool IsNestedFamilyOrAssembly => ((TypeAttributes)attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamORAssem;
/// <summary>
/// Gets/sets the layout
/// </summary>
public TypeAttributes Layout {
get => (TypeAttributes)attributes & TypeAttributes.LayoutMask;
set => ModifyAttributes(~TypeAttributes.LayoutMask, value & TypeAttributes.LayoutMask);
}
/// <summary>
/// <c>true</c> if <see cref="TypeAttributes.AutoLayout"/> is set
/// </summary>
public bool IsAutoLayout => ((TypeAttributes)attributes & TypeAttributes.LayoutMask) == TypeAttributes.AutoLayout;
/// <summary>
/// <c>true</c> if <see cref="TypeAttributes.SequentialLayout"/> is set
/// </summary>
public bool IsSequentialLayout => ((TypeAttributes)attributes & TypeAttributes.LayoutMask) == TypeAttributes.SequentialLayout;
/// <summary>
/// <c>true</c> if <see cref="TypeAttributes.ExplicitLayout"/> is set
/// </summary>
public bool IsExplicitLayout => ((TypeAttributes)attributes & TypeAttributes.LayoutMask) == TypeAttributes.ExplicitLayout;
/// <summary>
/// Gets/sets the <see cref="TypeAttributes.Interface"/> bit
/// </summary>
public bool IsInterface {
get => ((TypeAttributes)attributes & TypeAttributes.Interface) != 0;
set => ModifyAttributes(value, TypeAttributes.Interface);
}
/// <summary>
/// Gets/sets the <see cref="TypeAttributes.Class"/> bit
/// </summary>
public bool IsClass {
get => ((TypeAttributes)attributes & TypeAttributes.Interface) == 0;
set => ModifyAttributes(!value, TypeAttributes.Interface);
}
/// <summary>
/// Gets/sets the <see cref="TypeAttributes.Abstract"/> bit
/// </summary>
public bool IsAbstract {
get => ((TypeAttributes)attributes & TypeAttributes.Abstract) != 0;
set => ModifyAttributes(value, TypeAttributes.Abstract);
}
/// <summary>
/// Gets/sets the <see cref="TypeAttributes.Sealed"/> bit
/// </summary>
public bool IsSealed {
get => ((TypeAttributes)attributes & TypeAttributes.Sealed) != 0;
set => ModifyAttributes(value, TypeAttributes.Sealed);
}
/// <summary>
/// Gets/sets the <see cref="TypeAttributes.SpecialName"/> bit
/// </summary>
public bool IsSpecialName {
get => ((TypeAttributes)attributes & TypeAttributes.SpecialName) != 0;
set => ModifyAttributes(value, TypeAttributes.SpecialName);
}
/// <summary>
/// Gets/sets the <see cref="TypeAttributes.Import"/> bit
/// </summary>
public bool IsImport {
get => ((TypeAttributes)attributes & TypeAttributes.Import) != 0;
set => ModifyAttributes(value, TypeAttributes.Import);
}
/// <summary>
/// Gets/sets the <see cref="TypeAttributes.Serializable"/> bit
/// </summary>
public bool IsSerializable {
get => ((TypeAttributes)attributes & TypeAttributes.Serializable) != 0;
set => ModifyAttributes(value, TypeAttributes.Serializable);
}
/// <summary>
/// Gets/sets the <see cref="TypeAttributes.WindowsRuntime"/> bit
/// </summary>
public bool IsWindowsRuntime {
get => ((TypeAttributes)attributes & TypeAttributes.WindowsRuntime) != 0;
set => ModifyAttributes(value, TypeAttributes.WindowsRuntime);
}
/// <summary>
/// Gets/sets the string format
/// </summary>
public TypeAttributes StringFormat {
get => (TypeAttributes)attributes & TypeAttributes.StringFormatMask;
set => ModifyAttributes(~TypeAttributes.StringFormatMask, value & TypeAttributes.StringFormatMask);
}
/// <summary>
/// <c>true</c> if <see cref="TypeAttributes.AnsiClass"/> is set
/// </summary>
public bool IsAnsiClass => ((TypeAttributes)attributes & TypeAttributes.StringFormatMask) == TypeAttributes.AnsiClass;
/// <summary>
/// <c>true</c> if <see cref="TypeAttributes.UnicodeClass"/> is set
/// </summary>
public bool IsUnicodeClass => ((TypeAttributes)attributes & TypeAttributes.StringFormatMask) == TypeAttributes.UnicodeClass;
/// <summary>
/// <c>true</c> if <see cref="TypeAttributes.AutoClass"/> is set
/// </summary>
public bool IsAutoClass => ((TypeAttributes)attributes & TypeAttributes.StringFormatMask) == TypeAttributes.AutoClass;
/// <summary>
/// <c>true</c> if <see cref="TypeAttributes.CustomFormatClass"/> is set
/// </summary>
public bool IsCustomFormatClass => ((TypeAttributes)attributes & TypeAttributes.StringFormatMask) == TypeAttributes.CustomFormatClass;
/// <summary>
/// Gets/sets the <see cref="TypeAttributes.BeforeFieldInit"/> bit
/// </summary>
public bool IsBeforeFieldInit {
get => ((TypeAttributes)attributes & TypeAttributes.BeforeFieldInit) != 0;
set => ModifyAttributes(value, TypeAttributes.BeforeFieldInit);
}
/// <summary>
/// Gets/sets the <see cref="TypeAttributes.Forwarder"/> bit. See also <see cref="MovedToAnotherAssembly"/>
/// </summary>
public bool IsForwarder {
get => ((TypeAttributes)attributes & TypeAttributes.Forwarder) != 0;
set => ModifyAttributes(value, TypeAttributes.Forwarder);
}
/// <summary>
/// Gets/sets the <see cref="TypeAttributes.RTSpecialName"/> bit
/// </summary>
public bool IsRuntimeSpecialName {
get => ((TypeAttributes)attributes & TypeAttributes.RTSpecialName) != 0;
set => ModifyAttributes(value, TypeAttributes.RTSpecialName);
}
/// <summary>
/// Gets/sets the <see cref="TypeAttributes.HasSecurity"/> bit
/// </summary>
public bool HasSecurity {
get => ((TypeAttributes)attributes & TypeAttributes.HasSecurity) != 0;
set => ModifyAttributes(value, TypeAttributes.HasSecurity);
}
const int MAX_LOOP_ITERS = 50;
/// <summary>
/// <c>true</c> if this type has been moved to another assembly
/// </summary>
public bool MovedToAnotherAssembly {
get {
var et = this;
for (int i = 0; i < MAX_LOOP_ITERS; i++) {
var impl = et.Implementation;
if (impl is AssemblyRef)
return et.IsForwarder;
et = impl as ExportedType;
if (et is null)
break;
}
return false;
}
}
/// <summary>
/// Resolves the type
/// </summary>
/// <returns>A <see cref="TypeDef"/> instance or <c>null</c> if it couldn't be resolved</returns>
public TypeDef Resolve() => Resolve(null);
/// <summary>
/// Resolves the type
/// </summary>
/// <param name="sourceModule">Source module or <c>null</c></param>
/// <returns>A <see cref="TypeDef"/> instance or <c>null</c> if it couldn't be resolved</returns>
public TypeDef Resolve(ModuleDef sourceModule) {
if (module is null)
return null;
return Resolve(sourceModule, this);
}
static TypeDef Resolve(ModuleDef sourceModule, ExportedType et) {
for (int i = 0; i < MAX_LOOP_ITERS; i++) {
if (et is null || et.module is null)
break;
var resolver = et.module.Context.AssemblyResolver;
var etAsm = resolver.Resolve(et.DefinitionAssembly, sourceModule ?? et.module);
if (etAsm is null)
break;
var td = etAsm.Find(et.FullName, false);
if (td is not null)
return td;
et = FindExportedType(etAsm, et);
}
return null;
}
static ExportedType FindExportedType(AssemblyDef asm, ExportedType et) {
var modules = asm.Modules;
int count = modules.Count;
for (int i = 0; i < count; i++) {
var mod = modules[i];
var exportedTypes = mod.ExportedTypes;
int count2 = exportedTypes.Count;
for (int j = 0; j < count2; j++) {
var et2 = exportedTypes[j];
if (new SigComparer(SigComparerOptions.DontCompareTypeScope).Equals(et, et2))
return et2;
}
}
return null;
}
/// <summary>
/// Resolves the type
/// </summary>
/// <returns>A <see cref="TypeDef"/> instance</returns>
/// <exception cref="TypeResolveException">If the type couldn't be resolved</exception>
public TypeDef ResolveThrow() {
var type = Resolve();
if (type is not null)
return type;
throw new TypeResolveException($"Could not resolve type: {this} ({DefinitionAssembly})");
}
/// <summary>
/// Converts this instance to a <see cref="TypeRef"/>
/// </summary>
/// <returns>A new <see cref="TypeRef"/> instance</returns>
public TypeRef ToTypeRef() {
TypeRef result = null, prev = null;
var mod = module;
IImplementation impl = this;
for (int i = 0; i < MAX_LOOP_ITERS && impl is not null; i++) {
if (impl is ExportedType et) {
var newTr = mod.UpdateRowId(new TypeRefUser(mod, et.TypeNamespace, et.TypeName));
if (result is null)
result = newTr;
if (prev is not null)
prev.ResolutionScope = newTr;
prev = newTr;
impl = et.Implementation;
continue;
}
if (impl is AssemblyRef asmRef) {
// prev is never null when we're here
prev.ResolutionScope = asmRef;
return result;
}
if (impl is FileDef file) {
// prev is never null when we're here
prev.ResolutionScope = FindModule(mod, file);
return result;
}
break;
}
return result;
}
static ModuleDef FindModule(ModuleDef module, FileDef file) {
if (module is null || file is null)
return null;
if (UTF8String.CaseInsensitiveEquals(module.Name, file.Name))
return module;
var asm = module.Assembly;
if (asm is null)
return null;
return asm.FindModule(file.Name);
}
/// <inheritdoc/>
public override string ToString() => FullName;
}
/// <summary>
/// An ExportedType row created by the user and not present in the original .NET file
/// </summary>
public class ExportedTypeUser : ExportedType {
/// <summary>
/// Constructor
/// </summary>
/// <param name="module">Owner module</param>
public ExportedTypeUser(ModuleDef module) => this.module = module;
/// <summary>
/// Constructor
/// </summary>
/// <param name="module">Owner module</param>
/// <param name="typeDefId">TypeDef ID</param>
/// <param name="typeName">Type name</param>
/// <param name="typeNamespace">Type namespace</param>
/// <param name="flags">Flags</param>
/// <param name="implementation">Implementation</param>
public ExportedTypeUser(ModuleDef module, uint typeDefId, UTF8String typeNamespace, UTF8String typeName, TypeAttributes flags, IImplementation implementation) {
this.module = module;
this.typeDefId = typeDefId;
this.typeName = typeName;
this.typeNamespace = typeNamespace;
attributes = (int)flags;
this.implementation = implementation;
implementation_isInitialized = true;
}
}
/// <summary>
/// Created from a row in the ExportedType table
/// </summary>
sealed class ExportedTypeMD : ExportedType, IMDTokenProviderMD {
/// <summary>The module where this instance is located</summary>
readonly ModuleDefMD readerModule;
readonly uint origRid;
readonly uint implementationRid;
/// <inheritdoc/>
public uint OrigRid => origRid;
/// <inheritdoc/>
protected override void InitializeCustomAttributes() {
var list = readerModule.Metadata.GetCustomAttributeRidList(Table.ExportedType, origRid);
var tmp = new CustomAttributeCollection(list.Count, list, (list2, index) => readerModule.ReadCustomAttribute(list[index]));
Interlocked.CompareExchange(ref customAttributes, tmp, null);
}
/// <inheritdoc/>
protected override void InitializeCustomDebugInfos() {
var list = new List<PdbCustomDebugInfo>();
readerModule.InitializeCustomDebugInfos(new MDToken(MDToken.Table, origRid), new GenericParamContext(), list);
Interlocked.CompareExchange(ref customDebugInfos, list, null);
}
/// <inheritdoc/>
protected override IImplementation GetImplementation_NoLock() =>
readerModule.ResolveImplementation(implementationRid);
/// <summary>
/// Constructor
/// </summary>
/// <param name="readerModule">The module which contains this <c>ExportedType</c> row</param>
/// <param name="rid">Row ID</param>
/// <exception cref="ArgumentNullException">If <paramref name="readerModule"/> is <c>null</c></exception>
/// <exception cref="ArgumentException">If <paramref name="rid"/> is invalid</exception>
public ExportedTypeMD(ModuleDefMD readerModule, uint rid) {
#if DEBUG
if (readerModule is null)
throw new ArgumentNullException("readerModule");
if (readerModule.TablesStream.ExportedTypeTable.IsInvalidRID(rid))
throw new BadImageFormatException($"ExportedType rid {rid} does not exist");
#endif
origRid = rid;
this.rid = rid;
this.readerModule = readerModule;
module = readerModule;
bool b = readerModule.TablesStream.TryReadExportedTypeRow(origRid, out var row);
implementationRid = row.Implementation;
attributes = (int)row.Flags;
typeDefId = row.TypeDefId;
typeName = readerModule.StringsStream.ReadNoNull(row.TypeName);
typeNamespace = readerModule.StringsStream.ReadNoNull(row.TypeNamespace);
}
}
}

View File

@ -1,9 +0,0 @@
// dnlib: See LICENSE.txt for more info
namespace dnlib.DotNet {
/// <summary>
/// Extension methods
/// </summary>
public static partial class Extensions {
}
}

View File

@ -1,54 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System;
namespace dnlib.DotNet {
/// <summary>
/// Field flags, see CorHdr.h/CorFieldAttr
/// </summary>
[Flags]
public enum FieldAttributes : ushort {
/// <summary>member access mask - Use this mask to retrieve accessibility information.</summary>
FieldAccessMask = 0x0007,
/// <summary>Member not referenceable.</summary>
PrivateScope = 0x0000,
/// <summary>Member not referenceable.</summary>
CompilerControlled = PrivateScope,
/// <summary>Accessible only by the parent type.</summary>
Private = 0x0001,
/// <summary>Accessible by sub-types only in this Assembly.</summary>
FamANDAssem = 0x0002,
/// <summary>Accessibly by anyone in the Assembly.</summary>
Assembly = 0x0003,
/// <summary>Accessible only by type and sub-types.</summary>
Family = 0x0004,
/// <summary>Accessibly by sub-types anywhere, plus anyone in assembly.</summary>
FamORAssem = 0x0005,
/// <summary>Accessibly by anyone who has visibility to this scope.</summary>
Public = 0x0006,
/// <summary>Defined on type, else per instance.</summary>
Static = 0x0010,
/// <summary>Field may only be initialized, not written to after init.</summary>
InitOnly = 0x0020,
/// <summary>Value is compile time constant.</summary>
Literal = 0x0040,
/// <summary>Field does not have to be serialized when type is remoted.</summary>
NotSerialized = 0x0080,
/// <summary>field is special. Name describes how.</summary>
SpecialName = 0x0200,
/// <summary>Implementation is forwarded through pinvoke.</summary>
PinvokeImpl = 0x2000,
/// <summary>Runtime(metadata internal APIs) should check name encoding.</summary>
RTSpecialName = 0x0400,
/// <summary>Field has marshalling information.</summary>
HasFieldMarshal = 0x1000,
/// <summary>Field has default.</summary>
HasDefault = 0x8000,
/// <summary>Field has RVA.</summary>
HasFieldRVA = 0x0100,
}
}

View File

@ -1,864 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using dnlib.DotNet.MD;
using dnlib.DotNet.Pdb;
using dnlib.PE;
using dnlib.Threading;
namespace dnlib.DotNet {
/// <summary>
/// A high-level representation of a row in the Field table
/// </summary>
public abstract class FieldDef : IHasConstant, IHasCustomAttribute, IHasFieldMarshal, IMemberForwarded, IHasCustomDebugInformation, IField, ITokenOperand, IMemberDef {
/// <summary>
/// The row id in its table
/// </summary>
protected uint rid;
#if THREAD_SAFE
readonly Lock theLock = Lock.Create();
#endif
/// <inheritdoc/>
public MDToken MDToken => new MDToken(Table.Field, rid);
/// <inheritdoc/>
public uint Rid {
get => rid;
set => rid = value;
}
/// <inheritdoc/>
public int HasConstantTag => 0;
/// <inheritdoc/>
public int HasCustomAttributeTag => 1;
/// <inheritdoc/>
public int HasFieldMarshalTag => 0;
/// <inheritdoc/>
public int MemberForwardedTag => 0;
/// <summary>
/// Gets all custom attributes
/// </summary>
public CustomAttributeCollection CustomAttributes {
get {
if (customAttributes is null)
InitializeCustomAttributes();
return customAttributes;
}
}
/// <summary/>
protected CustomAttributeCollection customAttributes;
/// <summary>Initializes <see cref="customAttributes"/></summary>
protected virtual void InitializeCustomAttributes() =>
Interlocked.CompareExchange(ref customAttributes, new CustomAttributeCollection(), null);
/// <inheritdoc/>
public int HasCustomDebugInformationTag => 1;
/// <inheritdoc/>
public bool HasCustomDebugInfos => CustomDebugInfos.Count > 0;
/// <summary>
/// Gets all custom debug infos
/// </summary>
public IList<PdbCustomDebugInfo> CustomDebugInfos {
get {
if (customDebugInfos is null)
InitializeCustomDebugInfos();
return customDebugInfos;
}
}
/// <summary/>
protected IList<PdbCustomDebugInfo> customDebugInfos;
/// <summary>Initializes <see cref="customDebugInfos"/></summary>
protected virtual void InitializeCustomDebugInfos() =>
Interlocked.CompareExchange(ref customDebugInfos, new List<PdbCustomDebugInfo>(), null);
/// <summary>
/// From column Field.Flags
/// </summary>
public FieldAttributes Attributes {
get => (FieldAttributes)attributes;
set => attributes = (int)value;
}
/// <summary>Attributes</summary>
protected int attributes;
/// <summary>
/// From column Field.Name
/// </summary>
public UTF8String Name {
get => name;
set => name = value;
}
/// <summary>Name</summary>
protected UTF8String name;
/// <summary>
/// From column Field.Signature
/// </summary>
public CallingConventionSig Signature {
get => signature;
set => signature = value;
}
/// <summary/>
protected CallingConventionSig signature;
/// <summary>
/// Gets/sets the field layout offset
/// </summary>
public uint? FieldOffset {
get {
if (!fieldOffset_isInitialized)
InitializeFieldOffset();
return fieldOffset;
}
set {
#if THREAD_SAFE
theLock.EnterWriteLock(); try {
#endif
fieldOffset = value;
fieldOffset_isInitialized = true;
#if THREAD_SAFE
} finally { theLock.ExitWriteLock(); }
#endif
}
}
/// <summary/>
protected uint? fieldOffset;
/// <summary/>
protected bool fieldOffset_isInitialized;
void InitializeFieldOffset() {
#if THREAD_SAFE
theLock.EnterWriteLock(); try {
#endif
if (fieldOffset_isInitialized)
return;
fieldOffset = GetFieldOffset_NoLock();
fieldOffset_isInitialized = true;
#if THREAD_SAFE
} finally { theLock.ExitWriteLock(); }
#endif
}
/// <summary>Called to initialize <see cref="fieldOffset"/></summary>
protected virtual uint? GetFieldOffset_NoLock() => null;
/// <inheritdoc/>
public MarshalType MarshalType {
get {
if (!marshalType_isInitialized)
InitializeMarshalType();
return marshalType;
}
set {
#if THREAD_SAFE
theLock.EnterWriteLock(); try {
#endif
marshalType = value;
marshalType_isInitialized = true;
#if THREAD_SAFE
} finally { theLock.ExitWriteLock(); }
#endif
}
}
/// <summary/>
protected MarshalType marshalType;
/// <summary/>
protected bool marshalType_isInitialized;
void InitializeMarshalType() {
#if THREAD_SAFE
theLock.EnterWriteLock(); try {
#endif
if (marshalType_isInitialized)
return;
marshalType = GetMarshalType_NoLock();
marshalType_isInitialized = true;
#if THREAD_SAFE
} finally { theLock.ExitWriteLock(); }
#endif
}
/// <summary>Called to initialize <see cref="marshalType"/></summary>
protected virtual MarshalType GetMarshalType_NoLock() => null;
/// <summary>Reset <see cref="MarshalType"/></summary>
protected void ResetMarshalType() =>
marshalType_isInitialized = false;
/// <summary>
/// Gets/sets the field RVA
/// </summary>
public RVA RVA {
get {
if (!rva_isInitialized)
InitializeRVA();
return rva;
}
set {
#if THREAD_SAFE
theLock.EnterWriteLock(); try {
#endif
rva = value;
rva_isInitialized = true;
#if THREAD_SAFE
} finally { theLock.ExitWriteLock(); }
#endif
}
}
/// <summary/>
protected RVA rva;
/// <summary/>
protected bool rva_isInitialized;
void InitializeRVA() {
#if THREAD_SAFE
theLock.EnterWriteLock(); try {
#endif
if (rva_isInitialized)
return;
rva = GetRVA_NoLock();
rva_isInitialized = true;
#if THREAD_SAFE
} finally { theLock.ExitWriteLock(); }
#endif
}
/// <summary>Called to initialize <see cref="rva"/></summary>
protected virtual RVA GetRVA_NoLock() => 0;
/// <summary>Reset <see cref="RVA"/></summary>
protected void ResetRVA() => rva_isInitialized = false;
/// <summary>
/// Gets/sets the initial value. Be sure to set <see cref="HasFieldRVA"/> to <c>true</c> if
/// you write to this field.
/// </summary>
public byte[] InitialValue {
get {
if (!initialValue_isInitialized)
InitializeInitialValue();
return initialValue;
}
set {
#if THREAD_SAFE
theLock.EnterWriteLock(); try {
#endif
initialValue = value;
initialValue_isInitialized = true;
#if THREAD_SAFE
} finally { theLock.ExitWriteLock(); }
#endif
}
}
/// <summary/>
protected byte[] initialValue;
/// <summary/>
protected bool initialValue_isInitialized;
void InitializeInitialValue() {
#if THREAD_SAFE
theLock.EnterWriteLock(); try {
#endif
if (initialValue_isInitialized)
return;
initialValue = GetInitialValue_NoLock();
initialValue_isInitialized = true;
#if THREAD_SAFE
} finally { theLock.ExitWriteLock(); }
#endif
}
/// <summary>Called to initialize <see cref="initialValue"/></summary>
protected virtual byte[] GetInitialValue_NoLock() => null;
/// <summary>Reset <see cref="InitialValue"/></summary>
protected void ResetInitialValue() => initialValue_isInitialized = false;
/// <inheritdoc/>
public ImplMap ImplMap {
get {
if (!implMap_isInitialized)
InitializeImplMap();
return implMap;
}
set {
#if THREAD_SAFE
theLock.EnterWriteLock(); try {
#endif
implMap = value;
implMap_isInitialized = true;
#if THREAD_SAFE
} finally { theLock.ExitWriteLock(); }
#endif
}
}
/// <summary/>
protected ImplMap implMap;
/// <summary/>
protected bool implMap_isInitialized;
void InitializeImplMap() {
#if THREAD_SAFE
theLock.EnterWriteLock(); try {
#endif
if (implMap_isInitialized)
return;
implMap = GetImplMap_NoLock();
implMap_isInitialized = true;
#if THREAD_SAFE
} finally { theLock.ExitWriteLock(); }
#endif
}
/// <summary>Called to initialize <see cref="implMap"/></summary>
protected virtual ImplMap GetImplMap_NoLock() => null;
/// <inheritdoc/>
public Constant Constant {
get {
if (!constant_isInitialized)
InitializeConstant();
return constant;
}
set {
#if THREAD_SAFE
theLock.EnterWriteLock(); try {
#endif
constant = value;
constant_isInitialized = true;
#if THREAD_SAFE
} finally { theLock.ExitWriteLock(); }
#endif
}
}
/// <summary/>
protected Constant constant;
/// <summary/>
protected bool constant_isInitialized;
void InitializeConstant() {
#if THREAD_SAFE
theLock.EnterWriteLock(); try {
#endif
if (constant_isInitialized)
return;
constant = GetConstant_NoLock();
constant_isInitialized = true;
#if THREAD_SAFE
} finally { theLock.ExitWriteLock(); }
#endif
}
/// <summary>Called to initialize <see cref="constant"/></summary>
protected virtual Constant GetConstant_NoLock() => null;
/// <summary>Reset <see cref="Constant"/></summary>
protected void ResetConstant() => constant_isInitialized = false;
/// <inheritdoc/>
public bool HasCustomAttributes => CustomAttributes.Count > 0;
/// <inheritdoc/>
public bool HasImplMap => ImplMap is not null;
/// <summary>
/// Gets/sets the declaring type (owner type)
/// </summary>
public TypeDef DeclaringType {
get => declaringType2;
set {
var currentDeclaringType = DeclaringType2;
if (currentDeclaringType == value)
return;
if (currentDeclaringType is not null)
currentDeclaringType.Fields.Remove(this); // Will set DeclaringType2 = null
if (value is not null)
value.Fields.Add(this); // Will set DeclaringType2 = value
}
}
/// <inheritdoc/>
ITypeDefOrRef IMemberRef.DeclaringType => declaringType2;
/// <summary>
/// Called by <see cref="DeclaringType"/> and should normally not be called by any user
/// code. Use <see cref="DeclaringType"/> instead. Only call this if you must set the
/// declaring type without inserting it in the declaring type's method list.
/// </summary>
public TypeDef DeclaringType2 {
get => declaringType2;
set => declaringType2 = value;
}
/// <summary/>
protected TypeDef declaringType2;
/// <summary>
/// Gets/sets the <see cref="FieldSig"/>
/// </summary>
public FieldSig FieldSig {
get => signature as FieldSig;
set => signature = value;
}
/// <inheritdoc/>
public ModuleDef Module => declaringType2?.Module;
bool IIsTypeOrMethod.IsType => false;
bool IIsTypeOrMethod.IsMethod => false;
bool IMemberRef.IsField => true;
bool IMemberRef.IsTypeSpec => false;
bool IMemberRef.IsTypeRef => false;
bool IMemberRef.IsTypeDef => false;
bool IMemberRef.IsMethodSpec => false;
bool IMemberRef.IsMethodDef => false;
bool IMemberRef.IsMemberRef => false;
bool IMemberRef.IsFieldDef => true;
bool IMemberRef.IsPropertyDef => false;
bool IMemberRef.IsEventDef => false;
bool IMemberRef.IsGenericParam => false;
/// <summary>
/// <c>true</c> if <see cref="FieldOffset"/> is not <c>null</c>
/// </summary>
public bool HasLayoutInfo => FieldOffset is not null;
/// <summary>
/// <c>true</c> if <see cref="Constant"/> is not <c>null</c>
/// </summary>
public bool HasConstant => Constant is not null;
/// <summary>
/// Gets the constant element type or <see cref="dnlib.DotNet.ElementType.End"/> if there's no constant
/// </summary>
public ElementType ElementType {
get {
var c = Constant;
return c is null ? ElementType.End : c.Type;
}
}
/// <summary>
/// <c>true</c> if <see cref="MarshalType"/> is not <c>null</c>
/// </summary>
public bool HasMarshalType => MarshalType is not null;
/// <summary>
/// Gets/sets the field type
/// </summary>
public TypeSig FieldType {
get => FieldSig.GetFieldType();
set {
var sig = FieldSig;
if (sig is not null)
sig.Type = value;
}
}
/// <summary>
/// Modify <see cref="attributes"/> field: <see cref="attributes"/> =
/// (<see cref="attributes"/> &amp; <paramref name="andMask"/>) | <paramref name="orMask"/>.
/// </summary>
/// <param name="andMask">Value to <c>AND</c></param>
/// <param name="orMask">Value to OR</param>
void ModifyAttributes(FieldAttributes andMask, FieldAttributes orMask) =>
attributes = (attributes & (int)andMask) | (int)orMask;
/// <summary>
/// Set or clear flags in <see cref="attributes"/>
/// </summary>
/// <param name="set"><c>true</c> if flags should be set, <c>false</c> if flags should
/// be cleared</param>
/// <param name="flags">Flags to set or clear</param>
void ModifyAttributes(bool set, FieldAttributes flags) {
if (set)
attributes |= (int)flags;
else
attributes &= ~(int)flags;
}
/// <summary>
/// Gets/sets the field access
/// </summary>
public FieldAttributes Access {
get => (FieldAttributes)attributes & FieldAttributes.FieldAccessMask;
set => ModifyAttributes(~FieldAttributes.FieldAccessMask, value & FieldAttributes.FieldAccessMask);
}
/// <summary>
/// <c>true</c> if <see cref="FieldAttributes.PrivateScope"/> is set
/// </summary>
public bool IsCompilerControlled => IsPrivateScope;
/// <summary>
/// <c>true</c> if <see cref="FieldAttributes.PrivateScope"/> is set
/// </summary>
public bool IsPrivateScope => ((FieldAttributes)attributes & FieldAttributes.FieldAccessMask) == FieldAttributes.PrivateScope;
/// <summary>
/// <c>true</c> if <see cref="FieldAttributes.Private"/> is set
/// </summary>
public bool IsPrivate => ((FieldAttributes)attributes & FieldAttributes.FieldAccessMask) == FieldAttributes.Private;
/// <summary>
/// <c>true</c> if <see cref="FieldAttributes.FamANDAssem"/> is set
/// </summary>
public bool IsFamilyAndAssembly => ((FieldAttributes)attributes & FieldAttributes.FieldAccessMask) == FieldAttributes.FamANDAssem;
/// <summary>
/// <c>true</c> if <see cref="FieldAttributes.Assembly"/> is set
/// </summary>
public bool IsAssembly => ((FieldAttributes)attributes & FieldAttributes.FieldAccessMask) == FieldAttributes.Assembly;
/// <summary>
/// <c>true</c> if <see cref="FieldAttributes.Family"/> is set
/// </summary>
public bool IsFamily => ((FieldAttributes)attributes & FieldAttributes.FieldAccessMask) == FieldAttributes.Family;
/// <summary>
/// <c>true</c> if <see cref="FieldAttributes.FamORAssem"/> is set
/// </summary>
public bool IsFamilyOrAssembly => ((FieldAttributes)attributes & FieldAttributes.FieldAccessMask) == FieldAttributes.FamORAssem;
/// <summary>
/// <c>true</c> if <see cref="FieldAttributes.Public"/> is set
/// </summary>
public bool IsPublic => ((FieldAttributes)attributes & FieldAttributes.FieldAccessMask) == FieldAttributes.Public;
/// <summary>
/// Gets/sets the <see cref="FieldAttributes.Static"/> bit
/// </summary>
public bool IsStatic {
get => ((FieldAttributes)attributes & FieldAttributes.Static) != 0;
set => ModifyAttributes(value, FieldAttributes.Static);
}
/// <summary>
/// Gets/sets the <see cref="FieldAttributes.InitOnly"/> bit
/// </summary>
public bool IsInitOnly {
get => ((FieldAttributes)attributes & FieldAttributes.InitOnly) != 0;
set => ModifyAttributes(value, FieldAttributes.InitOnly);
}
/// <summary>
/// Gets/sets the <see cref="FieldAttributes.Literal"/> bit
/// </summary>
public bool IsLiteral {
get => ((FieldAttributes)attributes & FieldAttributes.Literal) != 0;
set => ModifyAttributes(value, FieldAttributes.Literal);
}
/// <summary>
/// Gets/sets the <see cref="FieldAttributes.NotSerialized"/> bit
/// </summary>
public bool IsNotSerialized {
get => ((FieldAttributes)attributes & FieldAttributes.NotSerialized) != 0;
set => ModifyAttributes(value, FieldAttributes.NotSerialized);
}
/// <summary>
/// Gets/sets the <see cref="FieldAttributes.SpecialName"/> bit
/// </summary>
public bool IsSpecialName {
get => ((FieldAttributes)attributes & FieldAttributes.SpecialName) != 0;
set => ModifyAttributes(value, FieldAttributes.SpecialName);
}
/// <summary>
/// Gets/sets the <see cref="FieldAttributes.PinvokeImpl"/> bit
/// </summary>
public bool IsPinvokeImpl {
get => ((FieldAttributes)attributes & FieldAttributes.PinvokeImpl) != 0;
set => ModifyAttributes(value, FieldAttributes.PinvokeImpl);
}
/// <summary>
/// Gets/sets the <see cref="FieldAttributes.RTSpecialName"/> bit
/// </summary>
public bool IsRuntimeSpecialName {
get => ((FieldAttributes)attributes & FieldAttributes.RTSpecialName) != 0;
set => ModifyAttributes(value, FieldAttributes.RTSpecialName);
}
/// <summary>
/// Gets/sets the <see cref="FieldAttributes.HasFieldMarshal"/> bit
/// </summary>
public bool HasFieldMarshal {
get => ((FieldAttributes)attributes & FieldAttributes.HasFieldMarshal) != 0;
set => ModifyAttributes(value, FieldAttributes.HasFieldMarshal);
}
/// <summary>
/// Gets/sets the <see cref="FieldAttributes.HasDefault"/> bit
/// </summary>
public bool HasDefault {
get => ((FieldAttributes)attributes & FieldAttributes.HasDefault) != 0;
set => ModifyAttributes(value, FieldAttributes.HasDefault);
}
/// <summary>
/// Gets/sets the <see cref="FieldAttributes.HasFieldRVA"/> bit
/// </summary>
public bool HasFieldRVA {
get => ((FieldAttributes)attributes & FieldAttributes.HasFieldRVA) != 0;
set => ModifyAttributes(value, FieldAttributes.HasFieldRVA);
}
/// <summary>
/// Returns the full name of this field
/// </summary>
public string FullName => FullNameFactory.FieldFullName(declaringType2?.FullName, name, FieldSig, null, null);
/// <summary>
/// Gets the size of this field in bytes or <c>0</c> if unknown.
/// </summary>
public uint GetFieldSize() {
if (!GetFieldSize(out uint size))
return 0;
return size;
}
/// <summary>
/// Gets the size of this field in bytes or <c>0</c> if unknown.
/// </summary>
/// <param name="size">Updated with size</param>
/// <returns><c>true</c> if <paramref name="size"/> is valid, <c>false</c> otherwise</returns>
public bool GetFieldSize(out uint size) => GetFieldSize(declaringType2, FieldSig, out size);
/// <summary>
/// Gets the size of this field in bytes or <c>0</c> if unknown.
/// </summary>
/// <param name="declaringType">The declaring type of <c>this</c></param>
/// <param name="fieldSig">The field signature of <c>this</c></param>
/// <param name="size">Updated with size</param>
/// <returns><c>true</c> if <paramref name="size"/> is valid, <c>false</c> otherwise</returns>
protected bool GetFieldSize(TypeDef declaringType, FieldSig fieldSig, out uint size) => GetFieldSize(declaringType, fieldSig, GetPointerSize(declaringType), out size);
/// <summary>
/// Gets the size of this field in bytes or <c>0</c> if unknown.
/// </summary>
/// <param name="declaringType">The declaring type of <c>this</c></param>
/// <param name="fieldSig">The field signature of <c>this</c></param>
/// <param name="ptrSize">Size of a pointer</param>
/// <param name="size">Updated with size</param>
/// <returns><c>true</c> if <paramref name="size"/> is valid, <c>false</c> otherwise</returns>
protected bool GetFieldSize(TypeDef declaringType, FieldSig fieldSig, int ptrSize, out uint size) {
size = 0;
if (fieldSig is null)
return false;
return GetClassSize(declaringType, fieldSig.Type, ptrSize, out size);
}
bool GetClassSize(TypeDef declaringType, TypeSig ts, int ptrSize, out uint size) {
size = 0;
ts = ts.RemovePinnedAndModifiers();
if (ts is null)
return false;
int size2 = ts.ElementType.GetPrimitiveSize(ptrSize);
if (size2 >= 0) {
size = (uint)size2;
return true;
}
var tdrs = ts as TypeDefOrRefSig;
if (tdrs is null)
return false;
var td = tdrs.TypeDef;
if (td is not null)
return TypeDef.GetClassSize(td, out size);
var tr = tdrs.TypeRef;
if (tr is not null)
return TypeDef.GetClassSize(tr.Resolve(), out size);
return false;
}
int GetPointerSize(TypeDef declaringType) {
if (declaringType is null)
return 4;
var module = declaringType.Module;
if (module is null)
return 4;
return module.GetPointerSize();
}
/// <inheritdoc/>
public override string ToString() => FullName;
}
/// <summary>
/// A Field row created by the user and not present in the original .NET file
/// </summary>
public class FieldDefUser : FieldDef {
/// <summary>
/// Default constructor
/// </summary>
public FieldDefUser() {
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="name">Name</param>
public FieldDefUser(UTF8String name)
: this(name, null) {
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="name">Name</param>
/// <param name="signature">Signature</param>
public FieldDefUser(UTF8String name, FieldSig signature)
: this(name, signature, 0) {
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="name">Name</param>
/// <param name="signature">Signature</param>
/// <param name="attributes">Flags</param>
public FieldDefUser(UTF8String name, FieldSig signature, FieldAttributes attributes) {
this.name = name;
this.signature = signature;
this.attributes = (int)attributes;
}
}
/// <summary>
/// Created from a row in the Field table
/// </summary>
sealed class FieldDefMD : FieldDef, IMDTokenProviderMD {
/// <summary>The module where this instance is located</summary>
readonly ModuleDefMD readerModule;
readonly uint origRid;
readonly FieldAttributes origAttributes;
/// <inheritdoc/>
public uint OrigRid => origRid;
/// <inheritdoc/>
protected override void InitializeCustomAttributes() {
var list = readerModule.Metadata.GetCustomAttributeRidList(Table.Field, origRid);
var tmp = new CustomAttributeCollection(list.Count, list, (list2, index) => readerModule.ReadCustomAttribute(list[index]));
Interlocked.CompareExchange(ref customAttributes, tmp, null);
}
/// <inheritdoc/>
protected override void InitializeCustomDebugInfos() {
var list = new List<PdbCustomDebugInfo>();
readerModule.InitializeCustomDebugInfos(new MDToken(MDToken.Table, origRid), new GenericParamContext(declaringType2), list);
Interlocked.CompareExchange(ref customDebugInfos, list, null);
}
/// <inheritdoc/>
protected override uint? GetFieldOffset_NoLock() {
if (readerModule.TablesStream.TryReadFieldLayoutRow(readerModule.Metadata.GetFieldLayoutRid(origRid), out var row))
return row.OffSet;
return null;
}
/// <inheritdoc/>
protected override MarshalType GetMarshalType_NoLock() =>
readerModule.ReadMarshalType(Table.Field, origRid, new GenericParamContext(declaringType2));
/// <inheritdoc/>
protected override RVA GetRVA_NoLock() {
GetFieldRVA_NoLock(out var rva2);
return rva2;
}
/// <inheritdoc/>
protected override byte[] GetInitialValue_NoLock() {
if (!GetFieldRVA_NoLock(out var rva2))
return null;
return ReadInitialValue_NoLock(rva2);
}
/// <inheritdoc/>
protected override ImplMap GetImplMap_NoLock() =>
readerModule.ResolveImplMap(readerModule.Metadata.GetImplMapRid(Table.Field, origRid));
/// <inheritdoc/>
protected override Constant GetConstant_NoLock() =>
readerModule.ResolveConstant(readerModule.Metadata.GetConstantRid(Table.Field, origRid));
/// <summary>
/// Constructor
/// </summary>
/// <param name="readerModule">The module which contains this <c>Field</c> row</param>
/// <param name="rid">Row ID</param>
/// <exception cref="ArgumentNullException">If <paramref name="readerModule"/> is <c>null</c></exception>
/// <exception cref="ArgumentException">If <paramref name="rid"/> is invalid</exception>
public FieldDefMD(ModuleDefMD readerModule, uint rid) {
#if DEBUG
if (readerModule is null)
throw new ArgumentNullException("readerModule");
if (readerModule.TablesStream.FieldTable.IsInvalidRID(rid))
throw new BadImageFormatException($"Field rid {rid} does not exist");
#endif
origRid = rid;
this.rid = rid;
this.readerModule = readerModule;
bool b = readerModule.TablesStream.TryReadFieldRow(origRid, out var row);
Debug.Assert(b);
name = readerModule.StringsStream.ReadNoNull(row.Name);
attributes = row.Flags;
origAttributes = (FieldAttributes)attributes;
declaringType2 = readerModule.GetOwnerType(this);
signature = readerModule.ReadSignature(row.Signature, new GenericParamContext(declaringType2));
}
internal FieldDefMD InitializeAll() {
MemberMDInitializer.Initialize(CustomAttributes);
MemberMDInitializer.Initialize(Attributes);
MemberMDInitializer.Initialize(Name);
MemberMDInitializer.Initialize(Signature);
MemberMDInitializer.Initialize(FieldOffset);
MemberMDInitializer.Initialize(MarshalType);
MemberMDInitializer.Initialize(RVA);
MemberMDInitializer.Initialize(InitialValue);
MemberMDInitializer.Initialize(ImplMap);
MemberMDInitializer.Initialize(Constant);
MemberMDInitializer.Initialize(DeclaringType);
return this;
}
bool GetFieldRVA_NoLock(out RVA rva) {
if ((origAttributes & FieldAttributes.HasFieldRVA) == 0) {
rva = 0;
return false;
}
if (!readerModule.TablesStream.TryReadFieldRVARow(readerModule.Metadata.GetFieldRVARid(origRid), out var row)) {
rva = 0;
return false;
}
rva = (RVA)row.RVA;
return true;
}
byte[] ReadInitialValue_NoLock(RVA rva) {
if (!GetFieldSize(declaringType2, signature as FieldSig, out uint size))
return null;
if (size >= int.MaxValue)
return null;
return readerModule.ReadDataAt(rva, (int)size);
}
}
}

View File

@ -1,16 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System;
namespace dnlib.DotNet {
/// <summary>
/// File row flags. See CorHdr.h/CorFileFlags
/// </summary>
[Flags]
public enum FileAttributes : uint {
/// <summary>This is not a resource file</summary>
ContainsMetadata = 0x0000,
/// <summary>This is a resource file or other non-metadata-containing file</summary>
ContainsNoMetadata = 0x0001,
}
}

View File

@ -1,215 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using dnlib.DotNet.MD;
using dnlib.DotNet.Pdb;
namespace dnlib.DotNet {
/// <summary>
/// A high-level representation of a row in the File table
/// </summary>
public abstract class FileDef : IHasCustomAttribute, IImplementation, IHasCustomDebugInformation, IManagedEntryPoint {
/// <summary>
/// The row id in its table
/// </summary>
protected uint rid;
/// <inheritdoc/>
public MDToken MDToken => new MDToken(Table.File, rid);
/// <inheritdoc/>
public uint Rid {
get => rid;
set => rid = value;
}
/// <inheritdoc/>
public int HasCustomAttributeTag => 16;
/// <inheritdoc/>
public int ImplementationTag => 0;
/// <summary>
/// From column File.Flags
/// </summary>
public FileAttributes Flags {
get => (FileAttributes)attributes;
set => attributes = (int)value;
}
/// <summary>Attributes</summary>
protected int attributes;
/// <summary>
/// From column File.Name
/// </summary>
public UTF8String Name {
get => name;
set => name = value;
}
/// <summary>Name</summary>
protected UTF8String name;
/// <summary>
/// From column File.HashValue
/// </summary>
public byte[] HashValue {
get => hashValue;
set => hashValue = value;
}
/// <summary/>
protected byte[] hashValue;
/// <summary>
/// Gets all custom attributes
/// </summary>
public CustomAttributeCollection CustomAttributes {
get {
if (customAttributes is null)
InitializeCustomAttributes();
return customAttributes;
}
}
/// <summary/>
protected CustomAttributeCollection customAttributes;
/// <summary>Initializes <see cref="customAttributes"/></summary>
protected virtual void InitializeCustomAttributes() =>
Interlocked.CompareExchange(ref customAttributes, new CustomAttributeCollection(), null);
/// <inheritdoc/>
public bool HasCustomAttributes => CustomAttributes.Count > 0;
/// <inheritdoc/>
public int HasCustomDebugInformationTag => 16;
/// <inheritdoc/>
public bool HasCustomDebugInfos => CustomDebugInfos.Count > 0;
/// <summary>
/// Gets all custom debug infos
/// </summary>
public IList<PdbCustomDebugInfo> CustomDebugInfos {
get {
if (customDebugInfos is null)
InitializeCustomDebugInfos();
return customDebugInfos;
}
}
/// <summary/>
protected IList<PdbCustomDebugInfo> customDebugInfos;
/// <summary>Initializes <see cref="customDebugInfos"/></summary>
protected virtual void InitializeCustomDebugInfos() =>
Interlocked.CompareExchange(ref customDebugInfos, new List<PdbCustomDebugInfo>(), null);
/// <summary>
/// Set or clear flags in <see cref="attributes"/>
/// </summary>
/// <param name="set"><c>true</c> if flags should be set, <c>false</c> if flags should
/// be cleared</param>
/// <param name="flags">Flags to set or clear</param>
void ModifyAttributes(bool set, FileAttributes flags) {
if (set)
attributes |= (int)flags;
else
attributes &= ~(int)flags;
}
/// <summary>
/// Gets/sets the <see cref="FileAttributes.ContainsMetadata"/> bit
/// </summary>
public bool ContainsMetadata {
get => ((FileAttributes)attributes & FileAttributes.ContainsNoMetadata) == 0;
set => ModifyAttributes(!value, FileAttributes.ContainsNoMetadata);
}
/// <summary>
/// Gets/sets the <see cref="FileAttributes.ContainsNoMetadata"/> bit
/// </summary>
public bool ContainsNoMetadata {
get => ((FileAttributes)attributes & FileAttributes.ContainsNoMetadata) != 0;
set => ModifyAttributes(value, FileAttributes.ContainsNoMetadata);
}
/// <inheritdoc/>
public string FullName => UTF8String.ToSystemStringOrEmpty(name);
/// <inheritdoc/>
public override string ToString() => FullName;
}
/// <summary>
/// A File row created by the user and not present in the original .NET file
/// </summary>
public class FileDefUser : FileDef {
/// <summary>
/// Default constructor
/// </summary>
public FileDefUser() {
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="name">Name of file</param>
/// <param name="flags">Flags</param>
/// <param name="hashValue">File hash</param>
public FileDefUser(UTF8String name, FileAttributes flags, byte[] hashValue) {
this.name = name;
attributes = (int)flags;
this.hashValue = hashValue;
}
}
/// <summary>
/// Created from a row in the File table
/// </summary>
sealed class FileDefMD : FileDef, IMDTokenProviderMD {
/// <summary>The module where this instance is located</summary>
readonly ModuleDefMD readerModule;
readonly uint origRid;
/// <inheritdoc/>
public uint OrigRid => origRid;
/// <inheritdoc/>
protected override void InitializeCustomAttributes() {
var list = readerModule.Metadata.GetCustomAttributeRidList(Table.File, origRid);
var tmp = new CustomAttributeCollection(list.Count, list, (list2, index) => readerModule.ReadCustomAttribute(list[index]));
Interlocked.CompareExchange(ref customAttributes, tmp, null);
}
/// <inheritdoc/>
protected override void InitializeCustomDebugInfos() {
var list = new List<PdbCustomDebugInfo>();
readerModule.InitializeCustomDebugInfos(new MDToken(MDToken.Table, origRid), new GenericParamContext(), list);
Interlocked.CompareExchange(ref customDebugInfos, list, null);
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="readerModule">The module which contains this <c>File</c> row</param>
/// <param name="rid">Row ID</param>
/// <exception cref="ArgumentNullException">If <paramref name="readerModule"/> is <c>null</c></exception>
/// <exception cref="ArgumentException">If <paramref name="rid"/> is invalid</exception>
public FileDefMD(ModuleDefMD readerModule, uint rid) {
#if DEBUG
if (readerModule is null)
throw new ArgumentNullException("readerModule");
if (readerModule.TablesStream.FileTable.IsInvalidRID(rid))
throw new BadImageFormatException($"File rid {rid} does not exist");
#endif
origRid = rid;
this.rid = rid;
this.readerModule = readerModule;
bool b = readerModule.TablesStream.TryReadFileRow(origRid, out var row);
Debug.Assert(b);
attributes = (int)row.Flags;
name = readerModule.StringsStream.ReadNoNull(row.Name);
hashValue = readerModule.BlobStream.Read(row.HashValue);
}
}
}

View File

@ -1,389 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System;
using System.Collections.Generic;
namespace dnlib.DotNet {
/// <summary>
/// Redirects .NET framework assembly references from older to newer versions
/// </summary>
public static class FrameworkRedirect {
static readonly Dictionary<string, FrameworkRedirectInfo> frmRedir2;
static readonly Dictionary<string, FrameworkRedirectInfo> frmRedir4;
readonly struct FrameworkRedirectInfo {
public readonly PublicKeyToken publicKeyToken;
public readonly Version redirectVersion;
public FrameworkRedirectInfo(string publicKeyToken, string redirectVersion) {
this.publicKeyToken = new PublicKeyToken(publicKeyToken);
this.redirectVersion = new Version(redirectVersion);
}
}
static FrameworkRedirect() {
frmRedir2 = new Dictionary<string, FrameworkRedirectInfo>(StringComparer.OrdinalIgnoreCase);
frmRedir4 = new Dictionary<string, FrameworkRedirectInfo>(StringComparer.OrdinalIgnoreCase);
InitFrameworkRedirectV2();
InitFrameworkRedirectV4();
}
static void InitFrameworkRedirectV2() {
frmRedir2["Accessibility"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "2.0.0.0");
frmRedir2["cscompmgd"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "8.0.0.0");
frmRedir2["CustomMarshalers"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "2.0.0.0");
frmRedir2["IEExecRemote"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "2.0.0.0");
frmRedir2["IEHost"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "2.0.0.0");
frmRedir2["IIEHost"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "2.0.0.0");
frmRedir2["ISymWrapper"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "2.0.0.0");
frmRedir2["Microsoft.JScript"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "8.0.0.0");
frmRedir2["Microsoft.VisualBasic"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "8.0.0.0");
frmRedir2["Microsoft.VisualBasic.Compatibility"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "8.0.0.0");
frmRedir2["Microsoft.VisualBasic.Compatibility.Data"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "8.0.0.0");
frmRedir2["Microsoft.VisualBasic.Vsa"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "8.0.0.0");
frmRedir2["Microsoft.VisualC"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "8.0.0.0");
frmRedir2["Microsoft.Vsa"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "8.0.0.0");
frmRedir2["Microsoft.Vsa.Vb.CodeDOMProcessor"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "8.0.0.0");
frmRedir2["Microsoft_VsaVb"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "8.0.0.0");
frmRedir2["mscorcfg"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "2.0.0.0");
frmRedir2["mscorlib"] = new FrameworkRedirectInfo("b77a5c561934e089", "2.0.0.0");
frmRedir2["System"] = new FrameworkRedirectInfo("b77a5c561934e089", "2.0.0.0");
frmRedir2["System.Configuration"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "2.0.0.0");
frmRedir2["System.Configuration.Install"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "2.0.0.0");
frmRedir2["System.Data"] = new FrameworkRedirectInfo("b77a5c561934e089", "2.0.0.0");
frmRedir2["System.Data.OracleClient"] = new FrameworkRedirectInfo("b77a5c561934e089", "2.0.0.0");
frmRedir2["System.Data.SqlXml"] = new FrameworkRedirectInfo("b77a5c561934e089", "2.0.0.0");
frmRedir2["System.Deployment"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "2.0.0.0");
frmRedir2["System.Design"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "2.0.0.0");
frmRedir2["System.DirectoryServices"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "2.0.0.0");
frmRedir2["System.DirectoryServices.Protocols"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "2.0.0.0");
frmRedir2["System.Drawing"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "2.0.0.0");
frmRedir2["System.Drawing.Design"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "2.0.0.0");
frmRedir2["System.EnterpriseServices"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "2.0.0.0");
frmRedir2["System.Management"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "2.0.0.0");
frmRedir2["System.Messaging"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "2.0.0.0");
frmRedir2["System.Runtime.Remoting"] = new FrameworkRedirectInfo("b77a5c561934e089", "2.0.0.0");
frmRedir2["System.Runtime.Serialization.Formatters.Soap"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "2.0.0.0");
frmRedir2["System.Security"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "2.0.0.0");
frmRedir2["System.ServiceProcess"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "2.0.0.0");
frmRedir2["System.Transactions"] = new FrameworkRedirectInfo("b77a5c561934e089", "2.0.0.0");
frmRedir2["System.Web"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "2.0.0.0");
frmRedir2["System.Web.Mobile"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "2.0.0.0");
frmRedir2["System.Web.RegularExpressions"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "2.0.0.0");
frmRedir2["System.Web.Services"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "2.0.0.0");
frmRedir2["System.Windows.Forms"] = new FrameworkRedirectInfo("b77a5c561934e089", "2.0.0.0");
frmRedir2["System.Xml"] = new FrameworkRedirectInfo("b77a5c561934e089", "2.0.0.0");
frmRedir2["vjscor"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "2.0.0.0");
frmRedir2["VJSharpCodeProvider"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "2.0.0.0");
frmRedir2["vjsJBC"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "2.0.0.0");
frmRedir2["vjslib"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "2.0.0.0");
frmRedir2["vjslibcw"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "2.0.0.0");
frmRedir2["Vjssupuilib"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "2.0.0.0");
frmRedir2["vjsvwaux"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "2.0.0.0");
frmRedir2["vjswfc"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "2.0.0.0");
frmRedir2["VJSWfcBrowserStubLib"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "2.0.0.0");
frmRedir2["vjswfccw"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "2.0.0.0");
frmRedir2["vjswfchtml"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "2.0.0.0");
}
static void InitFrameworkRedirectV4() {
frmRedir4["Accessibility"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["CustomMarshalers"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["ISymWrapper"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["Microsoft.JScript"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "10.0.0.0");
frmRedir4["Microsoft.VisualBasic"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "10.0.0.0");
frmRedir4["Microsoft.VisualBasic.Compatibility"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "10.0.0.0");
frmRedir4["Microsoft.VisualBasic.Compatibility.Data"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "10.0.0.0");
frmRedir4["Microsoft.VisualC"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "10.0.0.0");
frmRedir4["mscorlib"] = new FrameworkRedirectInfo("b77a5c561934e089", "4.0.0.0");
frmRedir4["System"] = new FrameworkRedirectInfo("b77a5c561934e089", "4.0.0.0");
frmRedir4["System.Configuration"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Configuration.Install"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Data"] = new FrameworkRedirectInfo("b77a5c561934e089", "4.0.0.0");
frmRedir4["System.Data.OracleClient"] = new FrameworkRedirectInfo("b77a5c561934e089", "4.0.0.0");
frmRedir4["System.Data.SqlXml"] = new FrameworkRedirectInfo("b77a5c561934e089", "4.0.0.0");
frmRedir4["System.Deployment"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Design"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.DirectoryServices"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.DirectoryServices.Protocols"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Drawing"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Drawing.Design"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.EnterpriseServices"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Management"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Messaging"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Runtime.Remoting"] = new FrameworkRedirectInfo("b77a5c561934e089", "4.0.0.0");
frmRedir4["System.Runtime.Serialization.Formatters.Soap"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Security"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.ServiceProcess"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Transactions"] = new FrameworkRedirectInfo("b77a5c561934e089", "4.0.0.0");
frmRedir4["System.Web"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Web.Mobile"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Web.RegularExpressions"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Web.Services"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Windows.Forms"] = new FrameworkRedirectInfo("b77a5c561934e089", "4.0.0.0");
frmRedir4["System.Xml"] = new FrameworkRedirectInfo("b77a5c561934e089", "4.0.0.0");
frmRedir4["AspNetMMCExt"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["sysglobl"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["Microsoft.Build.Engine"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["Microsoft.Build.Framework"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["PresentationCFFRasterizer"] = new FrameworkRedirectInfo("31bf3856ad364e35", "4.0.0.0");
frmRedir4["PresentationCore"] = new FrameworkRedirectInfo("31bf3856ad364e35", "4.0.0.0");
frmRedir4["PresentationFramework"] = new FrameworkRedirectInfo("31bf3856ad364e35", "4.0.0.0");
frmRedir4["PresentationFramework.Aero"] = new FrameworkRedirectInfo("31bf3856ad364e35", "4.0.0.0");
frmRedir4["PresentationFramework.Classic"] = new FrameworkRedirectInfo("31bf3856ad364e35", "4.0.0.0");
frmRedir4["PresentationFramework.Luna"] = new FrameworkRedirectInfo("31bf3856ad364e35", "4.0.0.0");
frmRedir4["PresentationFramework.Royale"] = new FrameworkRedirectInfo("31bf3856ad364e35", "4.0.0.0");
frmRedir4["PresentationUI"] = new FrameworkRedirectInfo("31bf3856ad364e35", "4.0.0.0");
frmRedir4["ReachFramework"] = new FrameworkRedirectInfo("31bf3856ad364e35", "4.0.0.0");
frmRedir4["System.Printing"] = new FrameworkRedirectInfo("31bf3856ad364e35", "4.0.0.0");
frmRedir4["System.Speech"] = new FrameworkRedirectInfo("31bf3856ad364e35", "4.0.0.0");
frmRedir4["UIAutomationClient"] = new FrameworkRedirectInfo("31bf3856ad364e35", "4.0.0.0");
frmRedir4["UIAutomationClientsideProviders"] = new FrameworkRedirectInfo("31bf3856ad364e35", "4.0.0.0");
frmRedir4["UIAutomationProvider"] = new FrameworkRedirectInfo("31bf3856ad364e35", "4.0.0.0");
frmRedir4["UIAutomationTypes"] = new FrameworkRedirectInfo("31bf3856ad364e35", "4.0.0.0");
frmRedir4["WindowsBase"] = new FrameworkRedirectInfo("31bf3856ad364e35", "4.0.0.0");
frmRedir4["WindowsFormsIntegration"] = new FrameworkRedirectInfo("31bf3856ad364e35", "4.0.0.0");
frmRedir4["SMDiagnostics"] = new FrameworkRedirectInfo("b77a5c561934e089", "4.0.0.0");
frmRedir4["System.IdentityModel"] = new FrameworkRedirectInfo("b77a5c561934e089", "4.0.0.0");
frmRedir4["System.IdentityModel.Selectors"] = new FrameworkRedirectInfo("b77a5c561934e089", "4.0.0.0");
frmRedir4["System.IO.Log"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Runtime.Serialization"] = new FrameworkRedirectInfo("b77a5c561934e089", "4.0.0.0");
frmRedir4["System.ServiceModel"] = new FrameworkRedirectInfo("b77a5c561934e089", "4.0.0.0");
frmRedir4["System.ServiceModel.Install"] = new FrameworkRedirectInfo("b77a5c561934e089", "4.0.0.0");
frmRedir4["System.ServiceModel.WasHosting"] = new FrameworkRedirectInfo("b77a5c561934e089", "4.0.0.0");
frmRedir4["System.Workflow.Activities"] = new FrameworkRedirectInfo("31bf3856ad364e35", "4.0.0.0");
frmRedir4["System.Workflow.ComponentModel"] = new FrameworkRedirectInfo("31bf3856ad364e35", "4.0.0.0");
frmRedir4["System.Workflow.Runtime"] = new FrameworkRedirectInfo("31bf3856ad364e35", "4.0.0.0");
frmRedir4["Microsoft.Transactions.Bridge"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["Microsoft.Transactions.Bridge.Dtc"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.AddIn"] = new FrameworkRedirectInfo("b77a5c561934e089", "4.0.0.0");
frmRedir4["System.AddIn.Contract"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.ComponentModel.Composition"] = new FrameworkRedirectInfo("b77a5c561934e089", "4.0.0.0");
frmRedir4["System.Core"] = new FrameworkRedirectInfo("b77a5c561934e089", "4.0.0.0");
frmRedir4["System.Data.DataSetExtensions"] = new FrameworkRedirectInfo("b77a5c561934e089", "4.0.0.0");
frmRedir4["System.Data.Linq"] = new FrameworkRedirectInfo("b77a5c561934e089", "4.0.0.0");
frmRedir4["System.Xml.Linq"] = new FrameworkRedirectInfo("b77a5c561934e089", "4.0.0.0");
frmRedir4["System.DirectoryServices.AccountManagement"] = new FrameworkRedirectInfo("b77a5c561934e089", "4.0.0.0");
frmRedir4["System.Management.Instrumentation"] = new FrameworkRedirectInfo("b77a5c561934e089", "4.0.0.0");
frmRedir4["System.Net"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.ServiceModel.Web"] = new FrameworkRedirectInfo("31bf3856ad364e35", "4.0.0.0");
frmRedir4["System.Web.Extensions"] = new FrameworkRedirectInfo("31bf3856ad364e35", "4.0.0.0");
frmRedir4["System.Web.Extensions.Design"] = new FrameworkRedirectInfo("31bf3856ad364e35", "4.0.0.0");
frmRedir4["System.Windows.Presentation"] = new FrameworkRedirectInfo("b77a5c561934e089", "4.0.0.0");
frmRedir4["System.WorkflowServices"] = new FrameworkRedirectInfo("31bf3856ad364e35", "4.0.0.0");
frmRedir4["System.ComponentModel.DataAnnotations"] = new FrameworkRedirectInfo("31bf3856ad364e35", "4.0.0.0");
frmRedir4["System.Data.Entity"] = new FrameworkRedirectInfo("b77a5c561934e089", "4.0.0.0");
frmRedir4["System.Data.Entity.Design"] = new FrameworkRedirectInfo("b77a5c561934e089", "4.0.0.0");
frmRedir4["System.Data.Services"] = new FrameworkRedirectInfo("b77a5c561934e089", "4.0.0.0");
frmRedir4["System.Data.Services.Client"] = new FrameworkRedirectInfo("b77a5c561934e089", "4.0.0.0");
frmRedir4["System.Data.Services.Design"] = new FrameworkRedirectInfo("b77a5c561934e089", "4.0.0.0");
frmRedir4["System.Web.Abstractions"] = new FrameworkRedirectInfo("31bf3856ad364e35", "4.0.0.0");
frmRedir4["System.Web.DynamicData"] = new FrameworkRedirectInfo("31bf3856ad364e35", "4.0.0.0");
frmRedir4["System.Web.DynamicData.Design"] = new FrameworkRedirectInfo("31bf3856ad364e35", "4.0.0.0");
frmRedir4["System.Web.Entity"] = new FrameworkRedirectInfo("b77a5c561934e089", "4.0.0.0");
frmRedir4["System.Web.Entity.Design"] = new FrameworkRedirectInfo("b77a5c561934e089", "4.0.0.0");
frmRedir4["System.Web.Routing"] = new FrameworkRedirectInfo("31bf3856ad364e35", "4.0.0.0");
frmRedir4["Microsoft.Build"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["Microsoft.CSharp"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Dynamic"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Numerics"] = new FrameworkRedirectInfo("b77a5c561934e089", "4.0.0.0");
frmRedir4["System.Xaml"] = new FrameworkRedirectInfo("b77a5c561934e089", "4.0.0.0");
frmRedir4["Microsoft.Workflow.Compiler"] = new FrameworkRedirectInfo("31bf3856ad364e35", "4.0.0.0");
frmRedir4["Microsoft.Activities.Build"] = new FrameworkRedirectInfo("31bf3856ad364e35", "4.0.0.0");
frmRedir4["Microsoft.Build.Conversion.v4.0"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["Microsoft.Build.Tasks.v4.0"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["Microsoft.Build.Utilities.v4.0"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["Microsoft.Internal.Tasks.Dataflow"] = new FrameworkRedirectInfo("b77a5c561934e089", "4.0.0.0");
frmRedir4["Microsoft.VisualBasic.Activities.Compiler"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "10.0.0.0");
frmRedir4["Microsoft.VisualC.STLCLR"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "2.0.0.0");
frmRedir4["Microsoft.Windows.ApplicationServer.Applications"] = new FrameworkRedirectInfo("31bf3856ad364e35", "4.0.0.0");
frmRedir4["PresentationBuildTasks"] = new FrameworkRedirectInfo("31bf3856ad364e35", "4.0.0.0");
frmRedir4["PresentationFramework.Aero2"] = new FrameworkRedirectInfo("31bf3856ad364e35", "4.0.0.0");
frmRedir4["PresentationFramework.AeroLite"] = new FrameworkRedirectInfo("31bf3856ad364e35", "4.0.0.0");
frmRedir4["PresentationFramework-SystemCore"] = new FrameworkRedirectInfo("b77a5c561934e089", "4.0.0.0");
frmRedir4["PresentationFramework-SystemData"] = new FrameworkRedirectInfo("b77a5c561934e089", "4.0.0.0");
frmRedir4["PresentationFramework-SystemDrawing"] = new FrameworkRedirectInfo("b77a5c561934e089", "4.0.0.0");
frmRedir4["PresentationFramework-SystemXml"] = new FrameworkRedirectInfo("b77a5c561934e089", "4.0.0.0");
frmRedir4["PresentationFramework-SystemXmlLinq"] = new FrameworkRedirectInfo("b77a5c561934e089", "4.0.0.0");
frmRedir4["System.Activities"] = new FrameworkRedirectInfo("31bf3856ad364e35", "4.0.0.0");
frmRedir4["System.Activities.Core.Presentation"] = new FrameworkRedirectInfo("31bf3856ad364e35", "4.0.0.0");
frmRedir4["System.Activities.DurableInstancing"] = new FrameworkRedirectInfo("31bf3856ad364e35", "4.0.0.0");
frmRedir4["System.Activities.Presentation"] = new FrameworkRedirectInfo("31bf3856ad364e35", "4.0.0.0");
frmRedir4["System.ComponentModel.Composition.Registration"] = new FrameworkRedirectInfo("b77a5c561934e089", "4.0.0.0");
frmRedir4["System.Device"] = new FrameworkRedirectInfo("b77a5c561934e089", "4.0.0.0");
frmRedir4["System.IdentityModel.Services"] = new FrameworkRedirectInfo("b77a5c561934e089", "4.0.0.0");
frmRedir4["System.IO.Compression"] = new FrameworkRedirectInfo("b77a5c561934e089", "4.0.0.0");
frmRedir4["System.IO.Compression.FileSystem"] = new FrameworkRedirectInfo("b77a5c561934e089", "4.0.0.0");
frmRedir4["System.Net.Http"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Net.Http.WebRequest"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Reflection.Context"] = new FrameworkRedirectInfo("b77a5c561934e089", "4.0.0.0");
frmRedir4["System.Runtime.Caching"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Runtime.DurableInstancing"] = new FrameworkRedirectInfo("31bf3856ad364e35", "4.0.0.0");
frmRedir4["System.Runtime.WindowsRuntime"] = new FrameworkRedirectInfo("b77a5c561934e089", "4.0.0.0");
frmRedir4["System.Runtime.WindowsRuntime.UI.Xaml"] = new FrameworkRedirectInfo("b77a5c561934e089", "4.0.0.0");
frmRedir4["System.ServiceModel.Activation"] = new FrameworkRedirectInfo("31bf3856ad364e35", "4.0.0.0");
frmRedir4["System.ServiceModel.Activities"] = new FrameworkRedirectInfo("31bf3856ad364e35", "4.0.0.0");
frmRedir4["System.ServiceModel.Channels"] = new FrameworkRedirectInfo("31bf3856ad364e35", "4.0.0.0");
frmRedir4["System.ServiceModel.Discovery"] = new FrameworkRedirectInfo("31bf3856ad364e35", "4.0.0.0");
frmRedir4["System.ServiceModel.Internals"] = new FrameworkRedirectInfo("31bf3856ad364e35", "4.0.0.0");
frmRedir4["System.ServiceModel.Routing"] = new FrameworkRedirectInfo("31bf3856ad364e35", "4.0.0.0");
frmRedir4["System.ServiceModel.ServiceMoniker40"] = new FrameworkRedirectInfo("b77a5c561934e089", "4.0.0.0");
frmRedir4["System.Web.ApplicationServices"] = new FrameworkRedirectInfo("31bf3856ad364e35", "4.0.0.0");
frmRedir4["System.Web.DataVisualization"] = new FrameworkRedirectInfo("31bf3856ad364e35", "4.0.0.0");
frmRedir4["System.Web.DataVisualization.Design"] = new FrameworkRedirectInfo("31bf3856ad364e35", "4.0.0.0");
frmRedir4["System.Windows.Controls.Ribbon"] = new FrameworkRedirectInfo("b77a5c561934e089", "4.0.0.0");
frmRedir4["System.Windows.Forms.DataVisualization"] = new FrameworkRedirectInfo("31bf3856ad364e35", "4.0.0.0");
frmRedir4["System.Windows.Forms.DataVisualization.Design"] = new FrameworkRedirectInfo("31bf3856ad364e35", "4.0.0.0");
frmRedir4["System.Windows.Input.Manipulations"] = new FrameworkRedirectInfo("b77a5c561934e089", "4.0.0.0");
frmRedir4["System.Xaml.Hosting"] = new FrameworkRedirectInfo("31bf3856ad364e35", "4.0.0.0");
frmRedir4["XamlBuildTask"] = new FrameworkRedirectInfo("31bf3856ad364e35", "4.0.0.0");
frmRedir4["XsdBuildTask"] = new FrameworkRedirectInfo("31bf3856ad364e35", "4.0.0.0");
frmRedir4["System.Collections"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Collections.Concurrent"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.ComponentModel"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.ComponentModel.Annotations"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.ComponentModel.EventBasedAsync"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Diagnostics.Contracts"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Diagnostics.Debug"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Diagnostics.Tools"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Diagnostics.Tracing"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Dynamic.Runtime"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Globalization"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.IO"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Linq"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Linq.Expressions"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Linq.Parallel"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Linq.Queryable"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Net.NetworkInformation"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Net.Primitives"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Net.Requests"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.ObjectModel"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Reflection"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Reflection.Emit"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Reflection.Emit.ILGeneration"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Reflection.Emit.Lightweight"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Reflection.Extensions"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Reflection.Primitives"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Resources.ResourceManager"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Runtime"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Runtime.Extensions"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Runtime.InteropServices"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Runtime.InteropServices.WindowsRuntime"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Runtime.Numerics"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Runtime.Serialization.Json"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Runtime.Serialization.Primitives"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Runtime.Serialization.Xml"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Security.Principal"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.ServiceModel.Duplex"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.ServiceModel.Http"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.ServiceModel.NetTcp"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.ServiceModel.Primitives"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.ServiceModel.Security"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Text.Encoding"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Text.Encoding.Extensions"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Text.RegularExpressions"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Threading"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Threading.Timer"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Threading.Tasks"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Threading.Tasks.Parallel"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Xml.ReaderWriter"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Xml.XDocument"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Xml.XmlSerializer"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Net.Http.Rtc"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Windows"] = new FrameworkRedirectInfo("b03f5f7f11d50a3a", "4.0.0.0");
frmRedir4["System.Xml.Serialization"] = new FrameworkRedirectInfo("b77a5c561934e089", "4.0.0.0");
}
/// <summary>
/// Redirects a .NET Framework assembly from an older version to the correct version
/// loaded at runtime.
/// </summary>
/// <param name="assembly">Current assembly reference that might get updated</param>
/// <param name="sourceModule">Module using the assembly reference</param>
public static void ApplyFrameworkRedirect(ref IAssembly assembly, ModuleDef sourceModule) {
if (TryApplyFrameworkRedirectCore(assembly, sourceModule, out var redirectedAssembly))
assembly = redirectedAssembly;
}
/// <summary>
/// Tries to redirect a .NET Framework assembly from an older version to the correct version
/// loaded at runtime.
/// </summary>
/// <param name="assembly">Assembly reference</param>
/// <param name="sourceModule">Module using the assembly reference</param>
/// <param name="redirectedAssembly">Updated with the redirected assembly if successful</param>
/// <returns></returns>
public static bool TryApplyFrameworkRedirect(IAssembly assembly, ModuleDef sourceModule, out IAssembly redirectedAssembly) =>
TryApplyFrameworkRedirectCore(assembly, sourceModule, out redirectedAssembly);
static bool TryApplyFrameworkRedirectCore(IAssembly assembly, ModuleDef sourceModule, out IAssembly redirectedAssembly) {
if (sourceModule is not null) {
if (sourceModule.IsClr40)
return TryApplyFrameworkRedirect(assembly, frmRedir4, out redirectedAssembly);
if (sourceModule.IsClr20)
return TryApplyFrameworkRedirect(assembly, frmRedir2, out redirectedAssembly);
}
redirectedAssembly = null;
return false;
}
/// <summary>
/// Redirects a .NET Framework 2.0-3.5 assembly from an older version to the correct version
/// loaded at runtime.
/// </summary>
/// <param name="assembly">Current assembly reference that might get updated</param>
public static void ApplyFrameworkRedirectV2(ref IAssembly assembly) {
if (TryApplyFrameworkRedirect(assembly, frmRedir2, out var redirectedAssembly))
assembly = redirectedAssembly;
}
/// <summary>
/// Redirects a .NET Framework 4.0+ assembly from an older version to the correct version
/// loaded at runtime.
/// </summary>
/// <param name="assembly">Current assembly reference that might get updated</param>
public static void ApplyFrameworkRedirectV4(ref IAssembly assembly) {
if (TryApplyFrameworkRedirect(assembly, frmRedir4, out var redirectedAssembly))
assembly = redirectedAssembly;
}
/// <summary>
/// Tries to redirect a .NET Framework 2.0-3.5 assembly from an older version to the correct version
/// loaded at runtime.
/// </summary>
/// <param name="assembly">Assembly reference</param>
/// <param name="redirectedAssembly">Updated with the redirected assembly if successful</param>
/// <returns></returns>
public static bool TryApplyFrameworkRedirectV2(IAssembly assembly, out IAssembly redirectedAssembly) =>
TryApplyFrameworkRedirect(assembly, frmRedir2, out redirectedAssembly);
/// <summary>
/// Tries to redirect a .NET Framework 4.0+ assembly from an older version to the correct version
/// loaded at runtime.
/// </summary>
/// <param name="assembly">Assembly reference</param>
/// <param name="redirectedAssembly">Updated with the redirected assembly if successful</param>
/// <returns></returns>
public static bool TryApplyFrameworkRedirectV4(IAssembly assembly, out IAssembly redirectedAssembly) =>
TryApplyFrameworkRedirect(assembly, frmRedir4, out redirectedAssembly);
static bool TryApplyFrameworkRedirect(IAssembly assembly, Dictionary<string, FrameworkRedirectInfo> frmRedir, out IAssembly redirectedAssembly) {
redirectedAssembly = null;
if (!Utils.LocaleEquals(assembly.Culture, ""))
return false;
if (!frmRedir.TryGetValue(assembly.Name, out var redirect))
return false;
if (PublicKeyBase.TokenCompareTo(assembly.PublicKeyOrToken, redirect.publicKeyToken) != 0)
return false;
if (Utils.CompareTo(assembly.Version, redirect.redirectVersion) == 0)
redirectedAssembly = assembly;
else {
redirectedAssembly = new AssemblyNameInfo(assembly);
redirectedAssembly.Version = redirect.redirectVersion;
}
return true;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,120 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System.Collections.Generic;
namespace dnlib.DotNet {
readonly struct GenericArgumentsStack {
readonly List<IList<TypeSig>> argsStack;
readonly bool isTypeVar;
/// <summary>
/// Constructor
/// </summary>
/// <param name="isTypeVar"><c>true</c> if it's for generic types, <c>false</c> if generic methods</param>
public GenericArgumentsStack(bool isTypeVar) {
argsStack = new List<IList<TypeSig>>();
this.isTypeVar = isTypeVar;
}
/// <summary>
/// Pushes generic arguments
/// </summary>
/// <param name="args">The generic arguments</param>
public void Push(IList<TypeSig> args) => argsStack.Add(args);
/// <summary>
/// Pops generic arguments
/// </summary>
/// <returns>The popped generic arguments</returns>
public IList<TypeSig> Pop() {
int index = argsStack.Count - 1;
var result = argsStack[index];
argsStack.RemoveAt(index);
return result;
}
/// <summary>
/// Resolves a generic argument
/// </summary>
/// <param name="number">Generic variable number</param>
/// <returns>A <see cref="TypeSig"/> or <c>null</c> if none was found</returns>
public TypeSig Resolve(uint number) {
TypeSig result = null;
for (int i = argsStack.Count - 1; i >= 0; i--) {
var args = argsStack[i];
if (number >= args.Count)
return null;
var typeSig = args[(int)number];
var gvar = typeSig as GenericSig;
if (gvar is null || gvar.IsTypeVar != isTypeVar)
return typeSig;
result = gvar;
number = gvar.Number;
}
return result;
}
}
/// <summary>
/// Replaces generic type/method var with its generic argument
/// </summary>
sealed class GenericArguments {
GenericArgumentsStack typeArgsStack = new GenericArgumentsStack(true);
GenericArgumentsStack methodArgsStack = new GenericArgumentsStack(false);
/// <summary>
/// Pushes generic arguments
/// </summary>
/// <param name="typeArgs">The generic arguments</param>
public void PushTypeArgs(IList<TypeSig> typeArgs) => typeArgsStack.Push(typeArgs);
/// <summary>
/// Pops generic arguments
/// </summary>
/// <returns>The popped generic arguments</returns>
public IList<TypeSig> PopTypeArgs() => typeArgsStack.Pop();
/// <summary>
/// Pushes generic arguments
/// </summary>
/// <param name="methodArgs">The generic arguments</param>
public void PushMethodArgs(IList<TypeSig> methodArgs) => methodArgsStack.Push(methodArgs);
/// <summary>
/// Pops generic arguments
/// </summary>
/// <returns>The popped generic arguments</returns>
public IList<TypeSig> PopMethodArgs() => methodArgsStack.Pop();
/// <summary>
/// Replaces a generic type/method var with its generic argument (if any). If
/// <paramref name="typeSig"/> isn't a generic type/method var or if it can't
/// be resolved, it itself is returned. Else the resolved type is returned.
/// </summary>
/// <param name="typeSig">Type signature</param>
/// <returns>New <see cref="TypeSig"/> which is never <c>null</c> unless
/// <paramref name="typeSig"/> is <c>null</c></returns>
public TypeSig Resolve(TypeSig typeSig) {
if (typeSig is null)
return null;
var sig = typeSig;
if (sig is GenericMVar genericMVar) {
var newSig = methodArgsStack.Resolve(genericMVar.Number);
if (newSig is null || newSig == sig)
return sig;
return newSig;
}
if (sig is GenericVar genericVar) {
var newSig = typeArgsStack.Resolve(genericVar.Number);
if (newSig is null || newSig == sig)
return sig;
return newSig;
}
return sig;
}
}
}

View File

@ -1,431 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System;
using System.Diagnostics;
using System.Threading;
using dnlib.Utils;
using dnlib.DotNet.MD;
using dnlib.DotNet.Pdb;
using System.Collections.Generic;
namespace dnlib.DotNet {
/// <summary>
/// A high-level representation of a row in the GenericParam table
/// </summary>
[DebuggerDisplay("{Name.String}")]
public abstract class GenericParam : IHasCustomAttribute, IHasCustomDebugInformation, IMemberDef, IListListener<GenericParamConstraint> {
/// <summary>
/// The row id in its table
/// </summary>
protected uint rid;
/// <inheritdoc/>
public MDToken MDToken => new MDToken(Table.GenericParam, rid);
/// <inheritdoc/>
public uint Rid {
get => rid;
set => rid = value;
}
/// <inheritdoc/>
public int HasCustomAttributeTag => 19;
/// <summary>
/// Gets the owner type/method
/// </summary>
public ITypeOrMethodDef Owner {
get => owner;
internal set => owner = value;
}
/// <summary/>
protected ITypeOrMethodDef owner;
/// <summary>
/// Gets the declaring type or <c>null</c> if none or if <see cref="Owner"/> is
/// not a <see cref="TypeDef"/>
/// </summary>
public TypeDef DeclaringType => owner as TypeDef;
/// <inheritdoc/>
ITypeDefOrRef IMemberRef.DeclaringType => owner as TypeDef;
/// <summary>
/// Gets the declaring method or <c>null</c> if none or if <see cref="Owner"/> is
/// not a <see cref="MethodDef"/>
/// </summary>
public MethodDef DeclaringMethod => owner as MethodDef;
/// <summary>
/// From column GenericParam.Number
/// </summary>
public ushort Number {
get => number;
set => number = value;
}
/// <summary/>
protected ushort number;
/// <summary>
/// From column GenericParam.Flags
/// </summary>
public GenericParamAttributes Flags {
get => (GenericParamAttributes)attributes;
set => attributes = (int)value;
}
/// <summary>Attributes</summary>
protected int attributes;
/// <summary>
/// From column GenericParam.Name
/// </summary>
public UTF8String Name {
get => name;
set => name = value;
}
/// <summary>Name</summary>
protected UTF8String name;
/// <summary>
/// From column GenericParam.Kind (v1.1 only)
/// </summary>
public ITypeDefOrRef Kind {
get => kind;
set => kind = value;
}
/// <summary/>
protected ITypeDefOrRef kind;
/// <summary>
/// Gets the generic param constraints
/// </summary>
public IList<GenericParamConstraint> GenericParamConstraints {
get {
if (genericParamConstraints is null)
InitializeGenericParamConstraints();
return genericParamConstraints;
}
}
/// <summary/>
protected LazyList<GenericParamConstraint> genericParamConstraints;
/// <summary>Initializes <see cref="genericParamConstraints"/></summary>
protected virtual void InitializeGenericParamConstraints() =>
Interlocked.CompareExchange(ref genericParamConstraints, new LazyList<GenericParamConstraint>(this), null);
/// <summary>
/// Gets all custom attributes
/// </summary>
public CustomAttributeCollection CustomAttributes {
get {
if (customAttributes is null)
InitializeCustomAttributes();
return customAttributes;
}
}
/// <summary/>
protected CustomAttributeCollection customAttributes;
/// <summary>Initializes <see cref="customAttributes"/></summary>
protected virtual void InitializeCustomAttributes() =>
Interlocked.CompareExchange(ref customAttributes, new CustomAttributeCollection(), null);
/// <inheritdoc/>
public bool HasCustomAttributes => CustomAttributes.Count > 0;
/// <inheritdoc/>
public int HasCustomDebugInformationTag => 19;
/// <inheritdoc/>
public bool HasCustomDebugInfos => CustomDebugInfos.Count > 0;
/// <summary>
/// Gets all custom debug infos
/// </summary>
public IList<PdbCustomDebugInfo> CustomDebugInfos {
get {
if (customDebugInfos is null)
InitializeCustomDebugInfos();
return customDebugInfos;
}
}
/// <summary/>
protected IList<PdbCustomDebugInfo> customDebugInfos;
/// <summary>Initializes <see cref="customDebugInfos"/></summary>
protected virtual void InitializeCustomDebugInfos() =>
Interlocked.CompareExchange(ref customDebugInfos, new List<PdbCustomDebugInfo>(), null);
/// <summary>
/// <c>true</c> if <see cref="GenericParamConstraints"/> is not empty
/// </summary>
public bool HasGenericParamConstraints => GenericParamConstraints.Count > 0;
/// <inheritdoc/>
public ModuleDef Module => owner?.Module;
/// <inheritdoc/>
public string FullName => UTF8String.ToSystemStringOrEmpty(name);
bool IIsTypeOrMethod.IsType => false;
bool IIsTypeOrMethod.IsMethod => false;
bool IMemberRef.IsField => false;
bool IMemberRef.IsTypeSpec => false;
bool IMemberRef.IsTypeRef => false;
bool IMemberRef.IsTypeDef => false;
bool IMemberRef.IsMethodSpec => false;
bool IMemberRef.IsMethodDef => false;
bool IMemberRef.IsMemberRef => false;
bool IMemberRef.IsFieldDef => false;
bool IMemberRef.IsPropertyDef => false;
bool IMemberRef.IsEventDef => false;
bool IMemberRef.IsGenericParam => true;
/// <summary>
/// Modify <see cref="attributes"/> property: <see cref="attributes"/> =
/// (<see cref="attributes"/> &amp; <paramref name="andMask"/>) | <paramref name="orMask"/>.
/// </summary>
/// <param name="andMask">Value to <c>AND</c></param>
/// <param name="orMask">Value to OR</param>
void ModifyAttributes(GenericParamAttributes andMask, GenericParamAttributes orMask) =>
attributes = (attributes & (int)andMask) | (int)orMask;
/// <summary>
/// Set or clear flags in <see cref="attributes"/>
/// </summary>
/// <param name="set"><c>true</c> if flags should be set, <c>false</c> if flags should
/// be cleared</param>
/// <param name="flags">Flags to set or clear</param>
void ModifyAttributes(bool set, GenericParamAttributes flags) {
if (set)
attributes |= (int)flags;
else
attributes &= ~(int)flags;
}
/// <summary>
/// Gets/sets variance (non, contra, co)
/// </summary>
public GenericParamAttributes Variance {
get => (GenericParamAttributes)attributes & GenericParamAttributes.VarianceMask;
set => ModifyAttributes(~GenericParamAttributes.VarianceMask, value & GenericParamAttributes.VarianceMask);
}
/// <summary>
/// <c>true</c> if <see cref="GenericParamAttributes.NonVariant"/> is set
/// </summary>
public bool IsNonVariant => Variance == GenericParamAttributes.NonVariant;
/// <summary>
/// <c>true</c> if <see cref="GenericParamAttributes.Covariant"/> is set
/// </summary>
public bool IsCovariant => Variance == GenericParamAttributes.Covariant;
/// <summary>
/// <c>true</c> if <see cref="GenericParamAttributes.Contravariant"/> is set
/// </summary>
public bool IsContravariant => Variance == GenericParamAttributes.Contravariant;
/// <summary>
/// Gets/sets the special constraint
/// </summary>
public GenericParamAttributes SpecialConstraint {
get => (GenericParamAttributes)attributes & GenericParamAttributes.SpecialConstraintMask;
set => ModifyAttributes(~GenericParamAttributes.SpecialConstraintMask, value & GenericParamAttributes.SpecialConstraintMask);
}
/// <summary>
/// <c>true</c> if there are no special constraints
/// </summary>
public bool HasNoSpecialConstraint => ((GenericParamAttributes)attributes & GenericParamAttributes.SpecialConstraintMask) == GenericParamAttributes.NoSpecialConstraint;
/// <summary>
/// Gets/sets the <see cref="GenericParamAttributes.ReferenceTypeConstraint"/> bit
/// </summary>
public bool HasReferenceTypeConstraint {
get => ((GenericParamAttributes)attributes & GenericParamAttributes.ReferenceTypeConstraint) != 0;
set => ModifyAttributes(value, GenericParamAttributes.ReferenceTypeConstraint);
}
/// <summary>
/// Gets/sets the <see cref="GenericParamAttributes.NotNullableValueTypeConstraint"/> bit
/// </summary>
public bool HasNotNullableValueTypeConstraint {
get => ((GenericParamAttributes)attributes & GenericParamAttributes.NotNullableValueTypeConstraint) != 0;
set => ModifyAttributes(value, GenericParamAttributes.NotNullableValueTypeConstraint);
}
/// <summary>
/// Gets/sets the <see cref="GenericParamAttributes.DefaultConstructorConstraint"/> bit
/// </summary>
public bool HasDefaultConstructorConstraint {
get => ((GenericParamAttributes)attributes & GenericParamAttributes.DefaultConstructorConstraint) != 0;
set => ModifyAttributes(value, GenericParamAttributes.DefaultConstructorConstraint);
}
/// <inheritdoc/>
void IListListener<GenericParamConstraint>.OnLazyAdd(int index, ref GenericParamConstraint value) => OnLazyAdd2(index, ref value);
internal virtual void OnLazyAdd2(int index, ref GenericParamConstraint value) {
#if DEBUG
if (value.Owner != this)
throw new InvalidOperationException("Added generic param constraint's Owner != this");
#endif
}
/// <inheritdoc/>
void IListListener<GenericParamConstraint>.OnAdd(int index, GenericParamConstraint value) {
if (value.Owner is not null)
throw new InvalidOperationException("Generic param constraint is already owned by another generic param. Set Owner to null first.");
value.Owner = this;
}
/// <inheritdoc/>
void IListListener<GenericParamConstraint>.OnRemove(int index, GenericParamConstraint value) => value.Owner = null;
/// <inheritdoc/>
void IListListener<GenericParamConstraint>.OnResize(int index) {
}
/// <inheritdoc/>
void IListListener<GenericParamConstraint>.OnClear() {
foreach (var gpc in genericParamConstraints.GetEnumerable_NoLock())
gpc.Owner = null;
}
/// <inheritdoc/>
public override string ToString() {
var o = owner;
if (o is TypeDef)
return $"!{number}";
if (o is MethodDef)
return $"!!{number}";
return $"??{number}";
}
}
/// <summary>
/// A GenericParam row created by the user and not present in the original .NET file
/// </summary>
public class GenericParamUser : GenericParam {
/// <summary>
/// Default constructor
/// </summary>
public GenericParamUser() {
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="number">The generic param number</param>
public GenericParamUser(ushort number)
: this(number, 0) {
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="number">The generic param number</param>
/// <param name="flags">Flags</param>
public GenericParamUser(ushort number, GenericParamAttributes flags)
: this(number, flags, UTF8String.Empty) {
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="number">The generic param number</param>
/// <param name="flags">Flags</param>
/// <param name="name">Name</param>
public GenericParamUser(ushort number, GenericParamAttributes flags, UTF8String name) {
genericParamConstraints = new LazyList<GenericParamConstraint>(this);
this.number = number;
attributes = (int)flags;
this.name = name;
}
}
/// <summary>
/// Created from a row in the GenericParam table
/// </summary>
sealed class GenericParamMD : GenericParam, IMDTokenProviderMD {
/// <summary>The module where this instance is located</summary>
readonly ModuleDefMD readerModule;
readonly uint origRid;
/// <inheritdoc/>
public uint OrigRid => origRid;
/// <inheritdoc/>
protected override void InitializeCustomAttributes() {
var list = readerModule.Metadata.GetCustomAttributeRidList(Table.GenericParam, origRid);
var tmp = new CustomAttributeCollection(list.Count, list, (list2, index) => readerModule.ReadCustomAttribute(list[index]));
Interlocked.CompareExchange(ref customAttributes, tmp, null);
}
/// <inheritdoc/>
protected override void InitializeCustomDebugInfos() {
var list = new List<PdbCustomDebugInfo>();
readerModule.InitializeCustomDebugInfos(new MDToken(MDToken.Table, origRid), GetGenericParamContext(owner), list);
Interlocked.CompareExchange(ref customDebugInfos, list, null);
}
/// <inheritdoc/>
protected override void InitializeGenericParamConstraints() {
var list = readerModule.Metadata.GetGenericParamConstraintRidList(origRid);
var tmp = new LazyList<GenericParamConstraint, RidList>(list.Count, this, list, (list2, index) => readerModule.ResolveGenericParamConstraint(list2[index], GetGenericParamContext(owner)));
Interlocked.CompareExchange(ref genericParamConstraints, tmp, null);
}
static GenericParamContext GetGenericParamContext(ITypeOrMethodDef tmOwner) {
if (tmOwner is MethodDef md)
return GenericParamContext.Create(md);
return new GenericParamContext(tmOwner as TypeDef);
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="readerModule">The module which contains this <c>GenericParam</c> row</param>
/// <param name="rid">Row ID</param>
/// <exception cref="ArgumentNullException">If <paramref name="readerModule"/> is <c>null</c></exception>
/// <exception cref="ArgumentException">If <paramref name="rid"/> is invalid</exception>
public GenericParamMD(ModuleDefMD readerModule, uint rid) {
#if DEBUG
if (readerModule is null)
throw new ArgumentNullException("readerModule");
if (readerModule.TablesStream.GenericParamTable.IsInvalidRID(rid))
throw new BadImageFormatException($"GenericParam rid {rid} does not exist");
#endif
origRid = rid;
this.rid = rid;
this.readerModule = readerModule;
bool b = readerModule.TablesStream.TryReadGenericParamRow(origRid, out var row);
Debug.Assert(b);
number = row.Number;
attributes = row.Flags;
name = readerModule.StringsStream.ReadNoNull(row.Name);
owner = readerModule.GetOwner(this);
if (row.Kind != 0)
kind = readerModule.ResolveTypeDefOrRef(row.Kind, GetGenericParamContext(owner));
}
internal GenericParamMD InitializeAll() {
MemberMDInitializer.Initialize(Owner);
MemberMDInitializer.Initialize(Number);
MemberMDInitializer.Initialize(Flags);
MemberMDInitializer.Initialize(Name);
MemberMDInitializer.Initialize(Kind);
MemberMDInitializer.Initialize(CustomAttributes);
MemberMDInitializer.Initialize(GenericParamConstraints);
return this;
}
/// <inheritdoc/>
internal override void OnLazyAdd2(int index, ref GenericParamConstraint value) {
if (value.Owner != this) {
// More than one owner... This module has invalid metadata.
value = readerModule.ForceUpdateRowId(readerModule.ReadGenericParamConstraint(value.Rid, GetGenericParamContext(owner)).InitializeAll());
value.Owner = this;
}
}
}
}

View File

@ -1,31 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System;
namespace dnlib.DotNet {
/// <summary>
/// Generic parameter flags. See CorHdr.h/CorGenericParamAttr
/// </summary>
[Flags]
public enum GenericParamAttributes : ushort {
/// <summary/>
VarianceMask = 0x0003,
/// <summary/>
NonVariant = 0x0000,
/// <summary/>
Covariant = 0x0001,
/// <summary/>
Contravariant = 0x0002,
/// <summary/>
SpecialConstraintMask = 0x001C,
/// <summary/>
NoSpecialConstraint = 0x0000,
/// <summary>type argument must be a reference type</summary>
ReferenceTypeConstraint = 0x0004,
/// <summary>type argument must be a value type but not Nullable</summary>
NotNullableValueTypeConstraint = 0x0008,
/// <summary>type argument must have a public default constructor</summary>
DefaultConstructorConstraint = 0x0010,
}
}

View File

@ -1,174 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using dnlib.DotNet.MD;
using dnlib.DotNet.Pdb;
namespace dnlib.DotNet {
/// <summary>
/// A high-level representation of a row in the GenericParamConstraint table
/// </summary>
public abstract class GenericParamConstraint : IHasCustomAttribute, IHasCustomDebugInformation, IContainsGenericParameter {
/// <summary>
/// The row id in its table
/// </summary>
protected uint rid;
/// <inheritdoc/>
public MDToken MDToken => new MDToken(Table.GenericParamConstraint, rid);
/// <inheritdoc/>
public uint Rid {
get => rid;
set => rid = value;
}
/// <inheritdoc/>
public int HasCustomAttributeTag => 20;
/// <summary>
/// Gets the owner generic param
/// </summary>
public GenericParam Owner {
get => owner;
internal set => owner = value;
}
/// <summary/>
protected GenericParam owner;
/// <summary>
/// From column GenericParamConstraint.Constraint
/// </summary>
public ITypeDefOrRef Constraint {
get => constraint;
set => constraint = value;
}
/// <summary/>
protected ITypeDefOrRef constraint;
/// <summary>
/// Gets all custom attributes
/// </summary>
public CustomAttributeCollection CustomAttributes {
get {
if (customAttributes is null)
InitializeCustomAttributes();
return customAttributes;
}
}
/// <summary/>
protected CustomAttributeCollection customAttributes;
/// <summary>Initializes <see cref="customAttributes"/></summary>
protected virtual void InitializeCustomAttributes() =>
Interlocked.CompareExchange(ref customAttributes, new CustomAttributeCollection(), null);
/// <inheritdoc/>
public bool HasCustomAttributes => CustomAttributes.Count > 0;
/// <inheritdoc/>
public int HasCustomDebugInformationTag => 20;
/// <inheritdoc/>
public bool HasCustomDebugInfos => CustomDebugInfos.Count > 0;
/// <summary>
/// Gets all custom debug infos
/// </summary>
public IList<PdbCustomDebugInfo> CustomDebugInfos {
get {
if (customDebugInfos is null)
InitializeCustomDebugInfos();
return customDebugInfos;
}
}
/// <summary/>
protected IList<PdbCustomDebugInfo> customDebugInfos;
/// <summary>Initializes <see cref="customDebugInfos"/></summary>
protected virtual void InitializeCustomDebugInfos() =>
Interlocked.CompareExchange(ref customDebugInfos, new List<PdbCustomDebugInfo>(), null);
bool IContainsGenericParameter.ContainsGenericParameter => TypeHelper.ContainsGenericParameter(this);
}
/// <summary>
/// A GenericParamConstraintAssembly row created by the user and not present in the original .NET file
/// </summary>
public class GenericParamConstraintUser : GenericParamConstraint {
/// <summary>
/// Default constructor
/// </summary>
public GenericParamConstraintUser() {
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="constraint">The constraint</param>
public GenericParamConstraintUser(ITypeDefOrRef constraint) => this.constraint = constraint;
}
/// <summary>
/// Created from a row in the GenericParamConstraint table
/// </summary>
sealed class GenericParamConstraintMD : GenericParamConstraint, IMDTokenProviderMD, IContainsGenericParameter2 {
/// <summary>The module where this instance is located</summary>
readonly ModuleDefMD readerModule;
readonly uint origRid;
readonly GenericParamContext gpContext;
/// <inheritdoc/>
public uint OrigRid => origRid;
bool IContainsGenericParameter2.ContainsGenericParameter => TypeHelper.ContainsGenericParameter(this);
/// <inheritdoc/>
protected override void InitializeCustomAttributes() {
var list = readerModule.Metadata.GetCustomAttributeRidList(Table.GenericParamConstraint, origRid);
var tmp = new CustomAttributeCollection(list.Count, list, (list2, index) => readerModule.ReadCustomAttribute(list[index]));
Interlocked.CompareExchange(ref customAttributes, tmp, null);
}
/// <inheritdoc/>
protected override void InitializeCustomDebugInfos() {
var list = new List<PdbCustomDebugInfo>();
readerModule.InitializeCustomDebugInfos(new MDToken(MDToken.Table, origRid), gpContext, list);
Interlocked.CompareExchange(ref customDebugInfos, list, null);
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="readerModule">The module which contains this <c>GenericParamConstraint</c> row</param>
/// <param name="rid">Row ID</param>
/// <param name="gpContext">Generic parameter context</param>
/// <exception cref="ArgumentNullException">If <paramref name="readerModule"/> is <c>null</c></exception>
/// <exception cref="ArgumentException">If <paramref name="rid"/> is invalid</exception>
public GenericParamConstraintMD(ModuleDefMD readerModule, uint rid, GenericParamContext gpContext) {
#if DEBUG
if (readerModule is null)
throw new ArgumentNullException("readerModule");
if (readerModule.TablesStream.GenericParamConstraintTable.IsInvalidRID(rid))
throw new BadImageFormatException($"GenericParamConstraint rid {rid} does not exist");
#endif
origRid = rid;
this.rid = rid;
this.readerModule = readerModule;
this.gpContext = gpContext;
bool b = readerModule.TablesStream.TryReadGenericParamConstraintRow(origRid, out var row);
Debug.Assert(b);
constraint = readerModule.ResolveTypeDefOrRef(row.Constraint, gpContext);
owner = readerModule.GetOwner(this);
}
internal GenericParamConstraintMD InitializeAll() {
MemberMDInitializer.Initialize(Owner);
MemberMDInitializer.Initialize(Constraint);
MemberMDInitializer.Initialize(CustomAttributes);
return this;
}
}
}

View File

@ -1,75 +0,0 @@
// dnlib: See LICENSE.txt for more info
namespace dnlib.DotNet {
/// <summary>
/// Generic parameter context
/// </summary>
public readonly struct GenericParamContext {
/// <summary>
/// Type context
/// </summary>
public readonly TypeDef Type;
/// <summary>
/// Method context
/// </summary>
public readonly MethodDef Method;
/// <summary>
/// true if <see cref="Type"/> and <see cref="Method"/> are both <c>null</c>
/// </summary>
public bool IsEmpty => Type is null && Method is null;
/// <summary>
/// Creates a new <see cref="GenericParamContext"/> instance and initializes the
/// <see cref="Type"/> field to <paramref name="method"/>'s <see cref="MethodDef.DeclaringType"/>
/// and the <see cref="Method"/> field to <paramref name="method"/>.
/// </summary>
/// <param name="method">Method</param>
/// <returns>A new <see cref="GenericParamContext"/> instance</returns>
public static GenericParamContext Create(MethodDef method) {
if (method is null)
return new GenericParamContext();
return new GenericParamContext(method.DeclaringType, method);
}
/// <summary>
/// Creates a new <see cref="GenericParamContext"/> instance and initializes the
/// <see cref="Type"/> field to <paramref name="type"/> and the <see cref="Method"/> field
/// to <c>null</c>
/// </summary>
/// <param name="type">Type</param>
/// <returns>A new <see cref="GenericParamContext"/> instance</returns>
public static GenericParamContext Create(TypeDef type) => new GenericParamContext(type);
/// <summary>
/// Constructor
/// </summary>
/// <param name="type">Type context</param>
public GenericParamContext(TypeDef type) {
Type = type;
Method = null;
}
/// <summary>
/// Constructor. The <see cref="Type"/> field is set to <c>null</c> and <c>NOT</c> to
/// <paramref name="method"/>'s <see cref="MethodDef.DeclaringType"/>. Use
/// <see cref="Create(MethodDef)"/> if you want that behavior.
/// </summary>
/// <param name="method">Method context</param>
public GenericParamContext(MethodDef method) {
Type = null;
Method = method;
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="type">Type context</param>
/// <param name="method">Method context</param>
public GenericParamContext(TypeDef type, MethodDef method) {
Type = type;
Method = method;
}
}
}

View File

@ -1,100 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System.Reflection;
namespace dnlib.DotNet {
/// <summary>
/// Resolves assemblies
/// </summary>
public interface IAssemblyResolver {
/// <summary>
/// Finds and returns an <see cref="AssemblyDef"/>
/// </summary>
/// <param name="assembly">The assembly to find</param>
/// <param name="sourceModule">The module that needs to resolve an assembly or <c>null</c></param>
/// <returns>An <see cref="AssemblyDef"/> instance owned by the assembly resolver or
/// <c>null</c> if the assembly couldn't be found.</returns>
AssemblyDef Resolve(IAssembly assembly, ModuleDef sourceModule);
}
public static partial class Extensions {
/// <summary>
/// Finds and returns an <see cref="AssemblyDef"/>
/// </summary>
/// <param name="self">this</param>
/// <param name="assembly">The assembly to find</param>
/// <param name="sourceModule">The module that needs to resolve an assembly or <c>null</c></param>
/// <returns>An <see cref="AssemblyDef"/> instance owned by the assembly resolver or
/// <c>null</c> if the assembly couldn't be found.</returns>
public static AssemblyDef Resolve(this IAssemblyResolver self, AssemblyName assembly, ModuleDef sourceModule) {
if (assembly is null)
return null;
return self.Resolve(new AssemblyNameInfo(assembly), sourceModule);
}
/// <summary>
/// Finds and returns an <see cref="AssemblyDef"/>
/// </summary>
/// <param name="self">this</param>
/// <param name="asmFullName">The assembly to find</param>
/// <param name="sourceModule">The module that needs to resolve an assembly or <c>null</c></param>
/// <returns>An <see cref="AssemblyDef"/> instance owned by the assembly resolver or
/// <c>null</c> if the assembly couldn't be found.</returns>
public static AssemblyDef Resolve(this IAssemblyResolver self, string asmFullName, ModuleDef sourceModule) {
if (asmFullName is null)
return null;
return self.Resolve(new AssemblyNameInfo(asmFullName), sourceModule);
}
/// <summary>
/// Finds and returns an <see cref="AssemblyDef"/>
/// </summary>
/// <param name="self">this</param>
/// <param name="assembly">The assembly to find</param>
/// <param name="sourceModule">The module that needs to resolve an assembly or <c>null</c></param>
/// <returns>An <see cref="AssemblyDef"/> instance owned by the assembly resolver</returns>
/// <exception cref="AssemblyResolveException">If the assembly couldn't be found.</exception>
public static AssemblyDef ResolveThrow(this IAssemblyResolver self, IAssembly assembly, ModuleDef sourceModule) {
if (assembly is null)
return null;
var asm = self.Resolve(assembly, sourceModule);
if (asm is not null)
return asm;
throw new AssemblyResolveException($"Could not resolve assembly: {assembly}");
}
/// <summary>
/// Finds and returns an <see cref="AssemblyDef"/>
/// </summary>
/// <param name="self">this</param>
/// <param name="assembly">The assembly to find</param>
/// <param name="sourceModule">The module that needs to resolve an assembly or <c>null</c></param>
/// <returns>An <see cref="AssemblyDef"/> instance owned by the assembly resolver</returns>
/// <exception cref="AssemblyResolveException">If the assembly couldn't be found.</exception>
public static AssemblyDef ResolveThrow(this IAssemblyResolver self, AssemblyName assembly, ModuleDef sourceModule) {
if (assembly is null)
return null;
var asm = self.Resolve(new AssemblyNameInfo(assembly), sourceModule);
if (asm is not null)
return asm;
throw new AssemblyResolveException($"Could not resolve assembly: {assembly}");
}
/// <summary>
/// Finds and returns an <see cref="AssemblyDef"/>
/// </summary>
/// <param name="self">this</param>
/// <param name="asmFullName">The assembly to find</param>
/// <param name="sourceModule">The module that needs to resolve an assembly or <c>null</c></param>
/// <returns>An <see cref="AssemblyDef"/> instance owned by the assembly resolver</returns>
/// <exception cref="AssemblyResolveException">If the assembly couldn't be found.</exception>
public static AssemblyDef ResolveThrow(this IAssemblyResolver self, string asmFullName, ModuleDef sourceModule) {
if (asmFullName is null)
return null;
var asm = self.Resolve(new AssemblyNameInfo(asmFullName), sourceModule);
if (asm is not null)
return asm;
throw new AssemblyResolveException($"Could not resolve assembly: {asmFullName}");
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,186 +0,0 @@
// dnlib: See LICENSE.txt for more info
namespace dnlib.DotNet {
/// <summary>
/// Access to .NET core library's simple types
/// </summary>
public interface ICorLibTypes {
/// <summary>
/// Gets a <c>System.Void</c>
/// </summary>
CorLibTypeSig Void { get; }
/// <summary>
/// Gets a <c>System.Boolean</c>
/// </summary>
CorLibTypeSig Boolean { get; }
/// <summary>
/// Gets a <c>System.Char</c>
/// </summary>
CorLibTypeSig Char { get; }
/// <summary>
/// Gets a <c>System.SByte</c>
/// </summary>
CorLibTypeSig SByte { get; }
/// <summary>
/// Gets a <c>System.Byte</c>
/// </summary>
CorLibTypeSig Byte { get; }
/// <summary>
/// Gets a <c>System.Int16</c>
/// </summary>
CorLibTypeSig Int16 { get; }
/// <summary>
/// Gets a <c>System.UInt16</c>
/// </summary>
CorLibTypeSig UInt16 { get; }
/// <summary>
/// Gets a <c>System.Int32</c>
/// </summary>
CorLibTypeSig Int32 { get; }
/// <summary>
/// Gets a <c>System.UInt32</c>
/// </summary>
CorLibTypeSig UInt32 { get; }
/// <summary>
/// Gets a <c>System.Int64</c>
/// </summary>
CorLibTypeSig Int64 { get; }
/// <summary>
/// Gets a <c>System.UInt64</c>
/// </summary>
CorLibTypeSig UInt64 { get; }
/// <summary>
/// Gets a <c>System.Single</c>
/// </summary>
CorLibTypeSig Single { get; }
/// <summary>
/// Gets a <c>System.Double</c>
/// </summary>
CorLibTypeSig Double { get; }
/// <summary>
/// Gets a <c>System.String</c>
/// </summary>
CorLibTypeSig String { get; }
/// <summary>
/// Gets a <c>System.TypedReference</c>
/// </summary>
CorLibTypeSig TypedReference { get; }
/// <summary>
/// Gets a <c>System.IntPtr</c>
/// </summary>
CorLibTypeSig IntPtr { get; }
/// <summary>
/// Gets a <c>System.UIntPtr</c>
/// </summary>
CorLibTypeSig UIntPtr { get; }
/// <summary>
/// Gets a <c>System.Object</c>
/// </summary>
CorLibTypeSig Object { get; }
/// <summary>
/// Gets the assembly reference to the core library
/// </summary>
AssemblyRef AssemblyRef { get; }
/// <summary>
/// Gets a <see cref="TypeRef"/> that references a type in the core library assembly
/// </summary>
/// <param name="namespace">Namespace of type (eg. "System")</param>
/// <param name="name">Name of type</param>
/// <returns>A <see cref="TypeRef"/> instance. This instance may be a cached instance.</returns>
TypeRef GetTypeRef(string @namespace, string name);
}
public static partial class Extensions {
/// <summary>
/// Gets a <see cref="CorLibTypeSig"/> if <paramref name="type"/> matches a primitive type.
/// </summary>
/// <param name="self">this</param>
/// <param name="type">The type</param>
/// <returns>A <see cref="CorLibTypeSig"/> or <c>null</c> if it didn't match any primitive type</returns>
public static CorLibTypeSig GetCorLibTypeSig(this ICorLibTypes self, ITypeDefOrRef type) {
CorLibTypeSig corLibType;
if (type is TypeDef td &&
td.DeclaringType is null &&
(corLibType = self.GetCorLibTypeSig(td.Namespace, td.Name, td.DefinitionAssembly)) is not null) {
return corLibType;
}
if (type is TypeRef tr &&
!(tr.ResolutionScope is TypeRef) &&
(corLibType = self.GetCorLibTypeSig(tr.Namespace, tr.Name, tr.DefinitionAssembly)) is not null) {
return corLibType;
}
return null;
}
/// <summary>
/// Gets a <see cref="CorLibTypeSig"/> if <paramref name="namespace"/> and
/// <paramref name="name"/> matches a primitive type.
/// </summary>
/// <param name="self">this</param>
/// <param name="namespace">Namespace</param>
/// <param name="name">Name</param>
/// <param name="defAsm">Definition assembly</param>
/// <returns>A <see cref="CorLibTypeSig"/> or <c>null</c> if it didn't match any primitive type</returns>
public static CorLibTypeSig GetCorLibTypeSig(this ICorLibTypes self, UTF8String @namespace, UTF8String name, IAssembly defAsm) =>
self.GetCorLibTypeSig(UTF8String.ToSystemStringOrEmpty(@namespace), UTF8String.ToSystemStringOrEmpty(name), defAsm);
/// <summary>
/// Gets a <see cref="CorLibTypeSig"/> if <paramref name="namespace"/> and
/// <paramref name="name"/> matches a primitive type.
/// </summary>
/// <param name="self">this</param>
/// <param name="namespace">Namespace</param>
/// <param name="name">Name</param>
/// <param name="defAsm">Definition assembly</param>
/// <returns>A <see cref="CorLibTypeSig"/> or <c>null</c> if it didn't match any primitive type</returns>
public static CorLibTypeSig GetCorLibTypeSig(this ICorLibTypes self, string @namespace, string name, IAssembly defAsm) {
if (@namespace != "System")
return null;
if (defAsm is null || !defAsm.IsCorLib())
return null;
return name switch {
"Void" => self.Void,
"Boolean" => self.Boolean,
"Char" => self.Char,
"SByte" => self.SByte,
"Byte" => self.Byte,
"Int16" => self.Int16,
"UInt16" => self.UInt16,
"Int32" => self.Int32,
"UInt32" => self.UInt32,
"Int64" => self.Int64,
"UInt64" => self.UInt64,
"Single" => self.Single,
"Double" => self.Double,
"String" => self.String,
"TypedReference" => self.TypedReference,
"IntPtr" => self.IntPtr,
"UIntPtr" => self.UIntPtr,
"Object" => self.Object,
_ => null,
};
}
}
}

View File

@ -1,41 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System.Collections.Generic;
namespace dnlib.DotNet {
/// <summary>
/// Custom attribute interface. Implemented by <see cref="SecurityAttribute"/> and
/// <see cref="CustomAttribute"/>
/// </summary>
public interface ICustomAttribute {
/// <summary>
/// Gets the attribute type
/// </summary>
ITypeDefOrRef AttributeType { get; }
/// <summary>
/// Gets the full name of the attribute type
/// </summary>
string TypeFullName { get; }
/// <summary>
/// Gets all named arguments (field and property values)
/// </summary>
IList<CANamedArgument> NamedArguments { get; }
/// <summary>
/// <c>true</c> if <see cref="NamedArguments"/> is not empty
/// </summary>
bool HasNamedArguments { get; }
/// <summary>
/// Gets all <see cref="CANamedArgument"/>s that are field arguments
/// </summary>
IEnumerable<CANamedArgument> Fields { get; }
/// <summary>
/// Gets all <see cref="CANamedArgument"/>s that are property arguments
/// </summary>
IEnumerable<CANamedArgument> Properties { get; }
}
}

View File

@ -1,37 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System.Collections.Generic;
using dnlib.PE;
using dnlib.DotNet.Emit;
namespace dnlib.DotNet {
/// <summary>
/// Interface to decrypt methods
/// </summary>
public interface IMethodDecrypter {
/// <summary>
/// Gets the method's body
/// </summary>
/// <param name="rid"><c>Method</c> rid</param>
/// <param name="rva">The <see cref="RVA"/> found in the method's <c>Method</c> row</param>
/// <param name="parameters">The method's parameters</param>
/// <param name="gpContext">Generic parameter context</param>
/// <param name="methodBody">Updated with the method's <see cref="MethodBody"/> if this
/// method returns <c>true</c></param>
/// <returns><c>true</c> if the method body was decrypted, <c>false</c> if the method isn't
/// encrypted and the default <see cref="MethodDef"/> body reader code should be used.</returns>
bool GetMethodBody(uint rid, RVA rva, IList<Parameter> parameters, GenericParamContext gpContext, out MethodBody methodBody);
}
/// <summary>
/// Interface to decrypt strings
/// </summary>
public interface IStringDecrypter {
/// <summary>
/// Reads a string
/// </summary>
/// <param name="token">String token</param>
/// <returns>A string or <c>null</c> if we should read it from the #US heap</returns>
string ReadUserString(uint token);
}
}

View File

@ -1,435 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System;
using System.Reflection;
using dnlib.DotNet.Writer;
namespace dnlib.DotNet {
/// <summary>
/// <see cref="ILogger"/> events
/// </summary>
public enum LoggerEvent {
/// <summary>
/// An error was detected. An exception should normally be thrown but the error
/// can be ignored.
/// </summary>
Error,
/// <summary>
/// Just a warning and can be ignored.
/// </summary>
Warning,
/// <summary>
/// A normal message
/// </summary>
Info,
/// <summary>
/// A verbose message
/// </summary>
Verbose,
/// <summary>
/// A very verbose message
/// </summary>
VeryVerbose,
}
/// <summary>
/// Simple logger
/// </summary>
public interface ILogger {
/// <summary>
/// Log something
/// </summary>
/// <param name="sender">Caller or <c>null</c></param>
/// <param name="loggerEvent">Logger event</param>
/// <param name="format">Format</param>
/// <param name="args">Arguments</param>
void Log(object sender, LoggerEvent loggerEvent, string format, params object[] args);
/// <summary>
/// <c>true</c> if this event is ignored. If the event is ignored, the caller can
/// choose not to call <see cref="Log"/>. This is useful if it can take time to
/// prepare the message.
/// </summary>
/// <param name="loggerEvent">The logger event</param>
bool IgnoresEvent(LoggerEvent loggerEvent);
}
public static partial class Extensions {
/// <summary>
/// Log an error message
/// </summary>
/// <param name="logger">this</param>
/// <param name="sender">Sender or <c>null</c></param>
/// <param name="message">Message</param>
public static void Error(this ILogger logger, object sender, string message) =>
logger.Log(sender, LoggerEvent.Error, "{0}", message);
/// <summary>
/// Log an error message
/// </summary>
/// <param name="logger">this</param>
/// <param name="sender">Sender or <c>null</c></param>
/// <param name="message">Message</param>
/// <param name="arg1">Message arg #1</param>
public static void Error(this ILogger logger, object sender, string message, object arg1) =>
logger.Log(sender, LoggerEvent.Error, message, arg1);
/// <summary>
/// Log an error message
/// </summary>
/// <param name="logger">this</param>
/// <param name="sender">Sender or <c>null</c></param>
/// <param name="message">Message</param>
/// <param name="arg1">Message arg #1</param>
/// <param name="arg2">Message arg #2</param>
public static void Error(this ILogger logger, object sender, string message, object arg1, object arg2) =>
logger.Log(sender, LoggerEvent.Error, message, arg1, arg2);
/// <summary>
/// Log an error message
/// </summary>
/// <param name="logger">this</param>
/// <param name="sender">Sender or <c>null</c></param>
/// <param name="message">Message</param>
/// <param name="arg1">Message arg #1</param>
/// <param name="arg2">Message arg #2</param>
/// <param name="arg3">Message arg #3</param>
public static void Error(this ILogger logger, object sender, string message, object arg1, object arg2, object arg3) =>
logger.Log(sender, LoggerEvent.Error, message, arg1, arg2, arg3);
/// <summary>
/// Log an error message
/// </summary>
/// <param name="logger">this</param>
/// <param name="sender">Sender or <c>null</c></param>
/// <param name="message">Message</param>
/// <param name="arg1">Message arg #1</param>
/// <param name="arg2">Message arg #2</param>
/// <param name="arg3">Message arg #3</param>
/// <param name="arg4">Message arg #4</param>
public static void Error(this ILogger logger, object sender, string message, object arg1, object arg2, object arg3, object arg4) =>
logger.Log(sender, LoggerEvent.Error, message, arg1, arg2, arg3, arg4);
/// <summary>
/// Log an error message
/// </summary>
/// <param name="logger">this</param>
/// <param name="sender">Sender or <c>null</c></param>
/// <param name="message">Message</param>
/// <param name="args">Message arguments</param>
public static void Error(this ILogger logger, object sender, string message, params object[] args) =>
logger.Log(sender, LoggerEvent.Error, message, args);
/// <summary>
/// Log a warning message
/// </summary>
/// <param name="logger">this</param>
/// <param name="sender">Sender or <c>null</c></param>
/// <param name="message">Message</param>
public static void Warning(this ILogger logger, object sender, string message) =>
logger.Log(sender, LoggerEvent.Warning, "{0}", message);
/// <summary>
/// Log a warning message
/// </summary>
/// <param name="logger">this</param>
/// <param name="sender">Sender or <c>null</c></param>
/// <param name="message">Message</param>
/// <param name="arg1">Message arg #1</param>
public static void Warning(this ILogger logger, object sender, string message, object arg1) =>
logger.Log(sender, LoggerEvent.Warning, message, arg1);
/// <summary>
/// Log a warning message
/// </summary>
/// <param name="logger">this</param>
/// <param name="sender">Sender or <c>null</c></param>
/// <param name="message">Message</param>
/// <param name="arg1">Message arg #1</param>
/// <param name="arg2">Message arg #2</param>
public static void Warning(this ILogger logger, object sender, string message, object arg1, object arg2) =>
logger.Log(sender, LoggerEvent.Warning, message, arg1, arg2);
/// <summary>
/// Log a warning message
/// </summary>
/// <param name="logger">this</param>
/// <param name="sender">Sender or <c>null</c></param>
/// <param name="message">Message</param>
/// <param name="arg1">Message arg #1</param>
/// <param name="arg2">Message arg #2</param>
/// <param name="arg3">Message arg #3</param>
public static void Warning(this ILogger logger, object sender, string message, object arg1, object arg2, object arg3) => logger.Log(sender, LoggerEvent.Warning, message, arg1, arg2, arg3);
/// <summary>
/// Log a warning message
/// </summary>
/// <param name="logger">this</param>
/// <param name="sender">Sender or <c>null</c></param>
/// <param name="message">Message</param>
/// <param name="arg1">Message arg #1</param>
/// <param name="arg2">Message arg #2</param>
/// <param name="arg3">Message arg #3</param>
/// <param name="arg4">Message arg #4</param>
public static void Warning(this ILogger logger, object sender, string message, object arg1, object arg2, object arg3, object arg4) =>
logger.Log(sender, LoggerEvent.Warning, message, arg1, arg2, arg3, arg4);
/// <summary>
/// Log a warning message
/// </summary>
/// <param name="logger">this</param>
/// <param name="sender">Sender or <c>null</c></param>
/// <param name="message">Message</param>
/// <param name="args">Message arguments</param>
public static void Warning(this ILogger logger, object sender, string message, params object[] args) =>
logger.Log(sender, LoggerEvent.Warning, message, args);
/// <summary>
/// Log an info message
/// </summary>
/// <param name="logger">this</param>
/// <param name="sender">Sender or <c>null</c></param>
/// <param name="message">Message</param>
public static void Info(this ILogger logger, object sender, string message) =>
logger.Log(sender, LoggerEvent.Info, "{0}", message);
/// <summary>
/// Log an info message
/// </summary>
/// <param name="logger">this</param>
/// <param name="sender">Sender or <c>null</c></param>
/// <param name="message">Message</param>
/// <param name="arg1">Message arg #1</param>
public static void Info(this ILogger logger, object sender, string message, object arg1) =>
logger.Log(sender, LoggerEvent.Info, message, arg1);
/// <summary>
/// Log an info message
/// </summary>
/// <param name="logger">this</param>
/// <param name="sender">Sender or <c>null</c></param>
/// <param name="message">Message</param>
/// <param name="arg1">Message arg #1</param>
/// <param name="arg2">Message arg #2</param>
public static void Info(this ILogger logger, object sender, string message, object arg1, object arg2) =>
logger.Log(sender, LoggerEvent.Info, message, arg1, arg2);
/// <summary>
/// Log an info message
/// </summary>
/// <param name="logger">this</param>
/// <param name="sender">Sender or <c>null</c></param>
/// <param name="message">Message</param>
/// <param name="arg1">Message arg #1</param>
/// <param name="arg2">Message arg #2</param>
/// <param name="arg3">Message arg #3</param>
public static void Info(this ILogger logger, object sender, string message, object arg1, object arg2, object arg3) =>
logger.Log(sender, LoggerEvent.Info, message, arg1, arg2, arg3);
/// <summary>
/// Log an info message
/// </summary>
/// <param name="logger">this</param>
/// <param name="sender">Sender or <c>null</c></param>
/// <param name="message">Message</param>
/// <param name="arg1">Message arg #1</param>
/// <param name="arg2">Message arg #2</param>
/// <param name="arg3">Message arg #3</param>
/// <param name="arg4">Message arg #4</param>
public static void Info(this ILogger logger, object sender, string message, object arg1, object arg2, object arg3, object arg4) =>
logger.Log(sender, LoggerEvent.Info, message, arg1, arg2, arg3, arg4);
/// <summary>
/// Log an info message
/// </summary>
/// <param name="logger">this</param>
/// <param name="sender">Sender or <c>null</c></param>
/// <param name="message">Message</param>
/// <param name="args">Message arguments</param>
public static void Info(this ILogger logger, object sender, string message, params object[] args) =>
logger.Log(sender, LoggerEvent.Info, message, args);
/// <summary>
/// Log a verbose message
/// </summary>
/// <param name="logger">this</param>
/// <param name="sender">Sender or <c>null</c></param>
/// <param name="message">Message</param>
public static void Verbose(this ILogger logger, object sender, string message) =>
logger.Log(sender, LoggerEvent.Verbose, "{0}", message);
/// <summary>
/// Log a verbose message
/// </summary>
/// <param name="logger">this</param>
/// <param name="sender">Sender or <c>null</c></param>
/// <param name="message">Message</param>
/// <param name="arg1">Message arg #1</param>
public static void Verbose(this ILogger logger, object sender, string message, object arg1) =>
logger.Log(sender, LoggerEvent.Verbose, message, arg1);
/// <summary>
/// Log a verbose message
/// </summary>
/// <param name="logger">this</param>
/// <param name="sender">Sender or <c>null</c></param>
/// <param name="message">Message</param>
/// <param name="arg1">Message arg #1</param>
/// <param name="arg2">Message arg #2</param>
public static void Verbose(this ILogger logger, object sender, string message, object arg1, object arg2) =>
logger.Log(sender, LoggerEvent.Verbose, message, arg1, arg2);
/// <summary>
/// Log a verbose message
/// </summary>
/// <param name="logger">this</param>
/// <param name="sender">Sender or <c>null</c></param>
/// <param name="message">Message</param>
/// <param name="arg1">Message arg #1</param>
/// <param name="arg2">Message arg #2</param>
/// <param name="arg3">Message arg #3</param>
public static void Verbose(this ILogger logger, object sender, string message, object arg1, object arg2, object arg3) =>
logger.Log(sender, LoggerEvent.Verbose, message, arg1, arg2, arg3);
/// <summary>
/// Log a verbose message
/// </summary>
/// <param name="logger">this</param>
/// <param name="sender">Sender or <c>null</c></param>
/// <param name="message">Message</param>
/// <param name="arg1">Message arg #1</param>
/// <param name="arg2">Message arg #2</param>
/// <param name="arg3">Message arg #3</param>
/// <param name="arg4">Message arg #4</param>
public static void Verbose(this ILogger logger, object sender, string message, object arg1, object arg2, object arg3, object arg4) =>
logger.Log(sender, LoggerEvent.Verbose, message, arg1, arg2, arg3, arg4);
/// <summary>
/// Log a verbose message
/// </summary>
/// <param name="logger">this</param>
/// <param name="sender">Sender or <c>null</c></param>
/// <param name="message">Message</param>
/// <param name="args">Message arguments</param>
public static void Verbose(this ILogger logger, object sender, string message, params object[] args) =>
logger.Log(sender, LoggerEvent.Verbose, message, args);
/// <summary>
/// Log a very verbose message
/// </summary>
/// <param name="logger">this</param>
/// <param name="sender">Sender or <c>null</c></param>
/// <param name="message">Message</param>
public static void VeryVerbose(this ILogger logger, object sender, string message) =>
logger.Log(sender, LoggerEvent.VeryVerbose, "{0}", message);
/// <summary>
/// Log a very verbose message
/// </summary>
/// <param name="logger">this</param>
/// <param name="sender">Sender or <c>null</c></param>
/// <param name="message">Message</param>
/// <param name="arg1">Message arg #1</param>
public static void VeryVerbose(this ILogger logger, object sender, string message, object arg1) =>
logger.Log(sender, LoggerEvent.VeryVerbose, message, arg1);
/// <summary>
/// Log a very verbose message
/// </summary>
/// <param name="logger">this</param>
/// <param name="sender">Sender or <c>null</c></param>
/// <param name="message">Message</param>
/// <param name="arg1">Message arg #1</param>
/// <param name="arg2">Message arg #2</param>
public static void VeryVerbose(this ILogger logger, object sender, string message, object arg1, object arg2) =>
logger.Log(sender, LoggerEvent.VeryVerbose, message, arg1, arg2);
/// <summary>
/// Log a very verbose message
/// </summary>
/// <param name="logger">this</param>
/// <param name="sender">Sender or <c>null</c></param>
/// <param name="message">Message</param>
/// <param name="arg1">Message arg #1</param>
/// <param name="arg2">Message arg #2</param>
/// <param name="arg3">Message arg #3</param>
public static void VeryVerbose(this ILogger logger, object sender, string message, object arg1, object arg2, object arg3) =>
logger.Log(sender, LoggerEvent.VeryVerbose, message, arg1, arg2, arg3);
/// <summary>
/// Log a very verbose message
/// </summary>
/// <param name="logger">this</param>
/// <param name="sender">Sender or <c>null</c></param>
/// <param name="message">Message</param>
/// <param name="arg1">Message arg #1</param>
/// <param name="arg2">Message arg #2</param>
/// <param name="arg3">Message arg #3</param>
/// <param name="arg4">Message arg #4</param>
public static void VeryVerbose(this ILogger logger, object sender, string message, object arg1, object arg2, object arg3, object arg4) =>
logger.Log(sender, LoggerEvent.VeryVerbose, message, arg1, arg2, arg3, arg4);
/// <summary>
/// Log a very verbose message
/// </summary>
/// <param name="logger">this</param>
/// <param name="sender">Sender or <c>null</c></param>
/// <param name="message">Message</param>
/// <param name="args">Message arguments</param>
public static void VeryVerbose(this ILogger logger, object sender, string message, params object[] args) =>
logger.Log(sender, LoggerEvent.VeryVerbose, message, args);
}
/// <summary>
/// Dummy logger which ignores all messages, but can optionally throw on errors.
/// </summary>
public sealed class DummyLogger : ILogger {
ConstructorInfo ctor;
/// <summary>
/// It ignores everything and doesn't throw anything.
/// </summary>
public static readonly DummyLogger NoThrowInstance = new DummyLogger();
/// <summary>
/// Throws a <see cref="ModuleWriterException"/> on errors, but ignores anything else.
/// </summary>
public static readonly DummyLogger ThrowModuleWriterExceptionOnErrorInstance = new DummyLogger(typeof(ModuleWriterException));
DummyLogger() {
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="exceptionToThrow">If non-<c>null</c>, this exception type is thrown on
/// errors. It must have a public constructor that takes a <see cref="string"/> as the only
/// argument.</param>
public DummyLogger(Type exceptionToThrow) {
if (exceptionToThrow is not null) {
if (!exceptionToThrow.IsSubclassOf(typeof(Exception)))
throw new ArgumentException($"Not a System.Exception sub class: {exceptionToThrow.GetType()}");
ctor = exceptionToThrow.GetConstructor(new Type[] { typeof(string) });
if (ctor is null)
throw new ArgumentException($"Exception type {exceptionToThrow.GetType()} doesn't have a public constructor that takes a string as the only argument");
}
}
/// <inheritdoc/>
public void Log(object sender, LoggerEvent loggerEvent, string format, params object[] args) {
if (loggerEvent == LoggerEvent.Error && ctor is not null)
throw (Exception)ctor.Invoke(new object[] { string.Format(format, args) });
}
/// <inheritdoc/>
public bool IgnoresEvent(LoggerEvent loggerEvent) {
if (ctor is null)
return true;
return loggerEvent != LoggerEvent.Error;
}
}
}

View File

@ -1,125 +0,0 @@
// dnlib: See LICENSE.txt for more info
namespace dnlib.DotNet {
/// <summary>
/// Resolves types, methods, fields
/// </summary>
public interface IResolver : ITypeResolver, IMemberRefResolver {
}
/// <summary>
/// Resolves types
/// </summary>
public interface ITypeResolver {
/// <summary>
/// Resolves a type
/// </summary>
/// <param name="typeRef">The type</param>
/// <param name="sourceModule">The module that needs to resolve the type or <c>null</c></param>
/// <returns>A <see cref="TypeDef"/> instance or <c>null</c> if it couldn't be resolved</returns>
TypeDef Resolve(TypeRef typeRef, ModuleDef sourceModule);
}
/// <summary>
/// Resolves fields and methods
/// </summary>
public interface IMemberRefResolver {
/// <summary>
/// Resolves a method or a field
/// </summary>
/// <param name="memberRef">A method/field reference</param>
/// <returns>A <see cref="MethodDef"/> or a <see cref="FieldDef"/> instance or <c>null</c>
/// if it couldn't be resolved.</returns>
IMemberForwarded Resolve(MemberRef memberRef);
}
public static partial class Extensions {
/// <summary>
/// Resolves a type
/// </summary>
/// <param name="self">this</param>
/// <param name="typeRef">The type</param>
/// <returns>A <see cref="TypeDef"/> instance or <c>null</c> if it couldn't be resolved</returns>
public static TypeDef Resolve(this ITypeResolver self, TypeRef typeRef) => self.Resolve(typeRef, null);
/// <summary>
/// Resolves a type
/// </summary>
/// <param name="self">this</param>
/// <param name="typeRef">The type</param>
/// <returns>A <see cref="TypeDef"/> instance</returns>
/// <exception cref="TypeResolveException">If the type couldn't be resolved</exception>
public static TypeDef ResolveThrow(this ITypeResolver self, TypeRef typeRef) => self.ResolveThrow(typeRef, null);
/// <summary>
/// Resolves a type
/// </summary>
/// <param name="self">this</param>
/// <param name="typeRef">The type</param>
/// <param name="sourceModule">The module that needs to resolve the type or <c>null</c></param>
/// <returns>A <see cref="TypeDef"/> instance</returns>
/// <exception cref="TypeResolveException">If the type couldn't be resolved</exception>
public static TypeDef ResolveThrow(this ITypeResolver self, TypeRef typeRef, ModuleDef sourceModule) {
var type = self.Resolve(typeRef, sourceModule);
if (type is not null)
return type;
throw new TypeResolveException($"Could not resolve type: {typeRef} ({typeRef?.DefinitionAssembly})");
}
/// <summary>
/// Resolves a method or a field
/// </summary>
/// <param name="self">this</param>
/// <param name="memberRef">A method/field reference</param>
/// <returns>A <see cref="MethodDef"/> or a <see cref="FieldDef"/> instance</returns>
/// <exception cref="MemberRefResolveException">If the method/field couldn't be resolved</exception>
public static IMemberForwarded ResolveThrow(this IMemberRefResolver self, MemberRef memberRef) {
var memberDef = self.Resolve(memberRef);
if (memberDef is not null)
return memberDef;
throw new MemberRefResolveException($"Could not resolve method/field: {memberRef} ({memberRef?.GetDefinitionAssembly()})");
}
/// <summary>
/// Resolves a field
/// </summary>
/// <param name="self">this</param>
/// <param name="memberRef">A field reference</param>
/// <returns>A <see cref="FieldDef"/> instance or <c>null</c> if it couldn't be resolved.</returns>
public static FieldDef ResolveField(this IMemberRefResolver self, MemberRef memberRef) => self.Resolve(memberRef) as FieldDef;
/// <summary>
/// Resolves a field
/// </summary>
/// <param name="self">this</param>
/// <param name="memberRef">A field reference</param>
/// <returns>A <see cref="FieldDef"/> instance or <c>null</c> if it couldn't be resolved.</returns>
/// <exception cref="MemberRefResolveException">If the field couldn't be resolved</exception>
public static FieldDef ResolveFieldThrow(this IMemberRefResolver self, MemberRef memberRef) {
if (self.Resolve(memberRef) is FieldDef field)
return field;
throw new MemberRefResolveException($"Could not resolve field: {memberRef} ({memberRef?.GetDefinitionAssembly()})");
}
/// <summary>
/// Resolves a method
/// </summary>
/// <param name="self">this</param>
/// <param name="memberRef">A method reference</param>
/// <returns>A <see cref="MethodDef"/> instance or <c>null</c> if it couldn't be resolved.</returns>
public static MethodDef ResolveMethod(this IMemberRefResolver self, MemberRef memberRef) => self.Resolve(memberRef) as MethodDef;
/// <summary>
/// Resolves a method
/// </summary>
/// <param name="self">this</param>
/// <param name="memberRef">A method reference</param>
/// <returns>A <see cref="MethodDef"/> instance or <c>null</c> if it couldn't be resolved.</returns>
/// <exception cref="MemberRefResolveException">If the method couldn't be resolved</exception>
public static MethodDef ResolveMethodThrow(this IMemberRefResolver self, MemberRef memberRef) {
if (self.Resolve(memberRef) is MethodDef method)
return method;
throw new MemberRefResolveException($"Could not resolve method: {memberRef} ({memberRef?.GetDefinitionAssembly()})");
}
}
}

View File

@ -1,26 +0,0 @@
// dnlib: See LICENSE.txt for more info
namespace dnlib.DotNet {
/// <summary>
/// Resolves tokens
/// </summary>
public interface ITokenResolver {
/// <summary>
/// Resolves a token
/// </summary>
/// <param name="token">The metadata token</param>
/// <param name="gpContext">Generic parameter context</param>
/// <returns>A <see cref="IMDTokenProvider"/> or <c>null</c> if <paramref name="token"/> is invalid</returns>
IMDTokenProvider ResolveToken(uint token, GenericParamContext gpContext);
}
public static partial class Extensions {
/// <summary>
/// Resolves a token
/// </summary>
/// <param name="self">This</param>
/// <param name="token">The metadata token</param>
/// <returns>A <see cref="IMDTokenProvider"/> or <c>null</c> if <paramref name="token"/> is invalid</returns>
public static IMDTokenProvider ResolveToken(this ITokenResolver self, uint token) => self.ResolveToken(token, new GenericParamContext());
}
}

View File

@ -1,110 +0,0 @@
// dnlib: See LICENSE.txt for more info
namespace dnlib.DotNet {
/// <summary>
/// Interface to get the full name of a type
/// </summary>
public interface IType : IFullName, IOwnerModule, ICodedToken, IGenericParameterProvider, IContainsGenericParameter {
/// <summary>
/// <c>true</c> if it's a value type
/// </summary>
bool IsValueType { get; }
/// <summary>
/// Returns the name of this type
/// </summary>
string TypeName { get; }
/// <summary>
/// Returns the reflection name of this type
/// </summary>
string ReflectionName { get; }
/// <summary>
/// Returns the namespace of this type
/// </summary>
string Namespace { get; }
/// <summary>
/// Returns the reflection namespace of this type
/// </summary>
string ReflectionNamespace { get; }
/// <summary>
/// Returns the reflection name of this type. See also <see cref="AssemblyQualifiedName"/>.
/// </summary>
string ReflectionFullName { get; }
/// <summary>
/// Returns the reflection name of this type, and includes the assembly name where the
/// type is located. It can be passed to <see cref="System.Type.GetType(string)"/> to
/// load the type.
/// </summary>
string AssemblyQualifiedName { get; }
/// <summary>
/// Gets the assembly where this type is defined
/// </summary>
IAssembly DefinitionAssembly { get; }
/// <summary>
/// Gets the scope, which is different from <see cref="DefinitionAssembly"/> since it
/// can differentiate between modules within the same assembly.
/// </summary>
IScope Scope { get; }
/// <summary>
/// Gets the type whose scope is returned by <see cref="Scope"/> and whose assembly
/// is returned by <see cref="DefinitionAssembly"/>. This is always a
/// <see cref="TypeDef"/>, <see cref="TypeRef"/> or <c>null</c>. It can also be a
/// nested <see cref="TypeRef"/>.
/// For example, if this type is a System.String&amp;, then this value is a System.String.
/// If it's a generic instance type (eg. List&lt;int&gt;), then the generic type is
/// returned (eg. List&lt;T&gt;). In other words, the first <see cref="TypeDef"/> or
/// <see cref="TypeRef"/> that is found (without searching generic arguments) is returned.
/// </summary>
ITypeDefOrRef ScopeType { get; }
/// <summary>
/// <c>true</c> if it's an integer or a floating point type
/// </summary>
bool IsPrimitive { get; }
}
/// <summary>
/// Implemented by types and calling convention signatures.
/// </summary>
public interface IContainsGenericParameter {
/// <summary>
/// <c>true</c> if this contains a <see cref="GenericVar"/> or a <see cref="GenericMVar"/>.
/// </summary>
bool ContainsGenericParameter { get; }
}
interface IContainsGenericParameter2 {
bool ContainsGenericParameter { get; }
}
public static partial class Extensions {
/// <summary>
/// Returns <see cref="IType.ScopeType"/>, but if it's a nested <see cref="TypeRef"/>,
/// return the non-nested <see cref="TypeRef"/>
/// </summary>
/// <param name="type">this</param>
/// <returns>The scope type</returns>
public static ITypeDefOrRef GetNonNestedTypeRefScope(this IType type) {
if (type is null)
return null;
var scopeType = type.ScopeType;
var tr = scopeType as TypeRef;
if (tr is null)
return scopeType;
for (int i = 0; i < 100; i++) {
var dt = tr.ResolutionScope as TypeRef;
if (dt is null)
return tr;
tr = dt;
}
return tr;
}
}
}

View File

@ -1,140 +0,0 @@
// dnlib: See LICENSE.txt for more info
namespace dnlib.DotNet {
/// <summary>
/// Finds <see cref="TypeDef"/>s
/// </summary>
public interface ITypeDefFinder {
/// <summary>
/// Finds a <see cref="TypeDef"/>
/// </summary>
/// <param name="fullName">Full name of the type (no assembly information)</param>
/// <param name="isReflectionName"><c>true</c> if it's a reflection name, and nested
/// type names are separated by a <c>+</c> character. If <c>false</c>, nested type names
/// are separated by a <c>/</c> character.</param>
/// <returns>An existing <see cref="TypeDef"/> or <c>null</c> if it wasn't found.</returns>
TypeDef Find(string fullName, bool isReflectionName);
/// <summary>
/// Finds a <see cref="TypeDef"/>. <paramref name="typeRef"/>'s scope (i.e., module or
/// assembly) is ignored when looking up the type.
/// </summary>
/// <param name="typeRef">The type ref</param>
/// <returns>An existing <see cref="TypeDef"/> or <c>null</c> if it wasn't found.</returns>
TypeDef Find(TypeRef typeRef);
}
public static partial class Extensions {
/// <summary>
/// Finds a <see cref="TypeDef"/>. Its scope (i.e., module or assembly) is ignored when
/// looking up the type.
/// </summary>
/// <param name="self">this</param>
/// <param name="typeRef">The type ref</param>
/// <returns>An existing <see cref="TypeDef"/> or <c>null</c> if it wasn't found.</returns>
/// <exception cref="TypeResolveException">If type couldn't be found</exception>
public static TypeDef FindThrow(this ITypeDefFinder self, TypeRef typeRef) {
var type = self.Find(typeRef);
if (type is not null)
return type;
throw new TypeResolveException($"Could not find type: {typeRef}");
}
/// <summary>
/// Finds a <see cref="TypeDef"/>
/// </summary>
/// <param name="self">this</param>
/// <param name="fullName">Full name of the type (no assembly information)</param>
/// <param name="isReflectionName"><c>true</c> if it's a reflection name, and nested
/// type names are separated by a <c>+</c> character. If <c>false</c>, nested type names
/// are separated by a <c>/</c> character.</param>
/// <returns>An existing <see cref="TypeDef"/></returns>
/// <exception cref="TypeResolveException">If type couldn't be found</exception>
public static TypeDef FindThrow(this ITypeDefFinder self, string fullName, bool isReflectionName) {
var type = self.Find(fullName, isReflectionName);
if (type is not null)
return type;
throw new TypeResolveException($"Could not find type: {fullName}");
}
/// <summary>
/// Finds a <see cref="TypeDef"/>
/// </summary>
/// <param name="self">this</param>
/// <param name="fullName">Full name of the type (no assembly information). Nested types are separated by <c>/</c></param>
/// <returns>An existing <see cref="TypeDef"/> or <c>null</c> if it wasn't found.</returns>
public static TypeDef FindNormal(this ITypeDefFinder self, string fullName) => self.Find(fullName, false);
/// <summary>
/// Finds a <see cref="TypeDef"/>
/// </summary>
/// <param name="self">this</param>
/// <param name="fullName">Full name of the type (no assembly information). Nested types are separated by <c>/</c></param>
/// <returns>An existing <see cref="TypeDef"/></returns>
/// <exception cref="TypeResolveException">If type couldn't be found</exception>
public static TypeDef FindNormalThrow(this ITypeDefFinder self, string fullName) {
var type = self.Find(fullName, false);
if (type is not null)
return type;
throw new TypeResolveException($"Could not find type: {fullName}");
}
/// <summary>
/// Finds a <see cref="TypeDef"/>
/// </summary>
/// <param name="self">this</param>
/// <param name="fullName">Full name of the type (no assembly information). Nested types are separated by <c>+</c></param>
/// <returns>An existing <see cref="TypeDef"/> or <c>null</c> if it wasn't found.</returns>
public static TypeDef FindReflection(this ITypeDefFinder self, string fullName) => self.Find(fullName, true);
/// <summary>
/// Finds a <see cref="TypeDef"/>
/// </summary>
/// <param name="self">this</param>
/// <param name="fullName">Full name of the type (no assembly information). Nested types are separated by <c>+</c></param>
/// <returns>An existing <see cref="TypeDef"/></returns>
/// <exception cref="TypeResolveException">If type couldn't be found</exception>
public static TypeDef FindReflectionThrow(this ITypeDefFinder self, string fullName) {
var type = self.Find(fullName, true);
if (type is not null)
return type;
throw new TypeResolveException($"Could not find type: {fullName}");
}
/// <summary>
/// Checks whether a <see cref="TypeDef"/> exists. <paramref name="typeRef"/>'s scope (i.e.,
/// module or assembly) is ignored when looking up the type.
/// </summary>
/// <param name="self">this</param>
/// <param name="typeRef">The type ref</param>
/// <returns><c>true</c> if the <see cref="TypeDef"/> exists, <c>false</c> otherwise</returns>
public static bool TypeExists(this ITypeDefFinder self, TypeRef typeRef) => self.Find(typeRef) is not null;
/// <summary>
/// Checks whether a <see cref="TypeDef"/> exists
/// </summary>
/// <param name="self">this</param>
/// <param name="fullName">Full name of the type (no assembly information)</param>
/// <param name="isReflectionName"><c>true</c> if it's a reflection name, and nested
/// type names are separated by a <c>+</c> character. If <c>false</c>, nested type names
/// are separated by a <c>/</c> character.</param>
/// <returns><c>true</c> if the <see cref="TypeDef"/> exists, <c>false</c> otherwise</returns>
public static bool TypeExists(this ITypeDefFinder self, string fullName, bool isReflectionName) => self.Find(fullName, isReflectionName) is not null;
/// <summary>
/// Checks whether a <see cref="TypeDef"/> exists
/// </summary>
/// <param name="self">this</param>
/// <param name="fullName">Full name of the type (no assembly information). Nested types are separated by <c>/</c></param>
/// <returns><c>true</c> if the <see cref="TypeDef"/> exists, <c>false</c> otherwise</returns>
public static bool TypeExistsNormal(this ITypeDefFinder self, string fullName) => self.Find(fullName, false) is not null;
/// <summary>
/// Checks whether a <see cref="TypeDef"/> exists
/// </summary>
/// <param name="self">this</param>
/// <param name="fullName">Full name of the type (no assembly information). Nested types are separated by <c>+</c></param>
/// <returns><c>true</c> if the <see cref="TypeDef"/> exists, <c>false</c> otherwise</returns>
public static bool TypeExistsReflection(this ITypeDefFinder self, string fullName) => self.Find(fullName, true) is not null;
}
}

View File

@ -1,23 +0,0 @@
// dnlib: See LICENSE.txt for more info
namespace dnlib.DotNet {
/// <summary>
/// Interface to access a local or a parameter
/// </summary>
public interface IVariable {
/// <summary>
/// Gets the variable type
/// </summary>
TypeSig Type { get; }
/// <summary>
/// Gets the 0-based position
/// </summary>
int Index { get; }
/// <summary>
/// Gets/sets the variable name
/// </summary>
string Name { get; set; }
}
}

View File

@ -1,301 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using dnlib.DotNet.MD;
namespace dnlib.DotNet {
/// <summary>
/// A high-level representation of a row in the ImplMap table
/// </summary>
[DebuggerDisplay("{Module} {Name}")]
public abstract class ImplMap : IMDTokenProvider {
/// <summary>
/// The row id in its table
/// </summary>
protected uint rid;
/// <inheritdoc/>
public MDToken MDToken => new MDToken(Table.ImplMap, rid);
/// <inheritdoc/>
public uint Rid {
get => rid;
set => rid = value;
}
/// <summary>
/// From column ImplMap.MappingFlags
/// </summary>
public PInvokeAttributes Attributes {
get => (PInvokeAttributes)attributes;
set => attributes = (int)value;
}
/// <summary>Attributes</summary>
protected int attributes;
/// <summary>
/// From column ImplMap.ImportName
/// </summary>
public UTF8String Name {
get => name;
set => name = value;
}
/// <summary>Name</summary>
protected UTF8String name;
/// <summary>
/// From column ImplMap.ImportScope
/// </summary>
public ModuleRef Module {
get => module;
set => module = value;
}
/// <summary/>
protected ModuleRef module;
/// <summary>
/// Modify <see cref="attributes"/> property: <see cref="attributes"/> =
/// (<see cref="attributes"/> &amp; <paramref name="andMask"/>) | <paramref name="orMask"/>.
/// </summary>
/// <param name="andMask">Value to <c>AND</c></param>
/// <param name="orMask">Value to OR</param>
void ModifyAttributes(PInvokeAttributes andMask, PInvokeAttributes orMask) =>
attributes = (attributes & (int)andMask) | (int)orMask;
/// <summary>
/// Set or clear flags in <see cref="attributes"/>
/// </summary>
/// <param name="set"><c>true</c> if flags should be set, <c>false</c> if flags should
/// be cleared</param>
/// <param name="flags">Flags to set or clear</param>
void ModifyAttributes(bool set, PInvokeAttributes flags) {
if (set)
attributes |= (int)flags;
else
attributes &= ~(int)flags;
}
/// <summary>
/// Gets/sets the <see cref="PInvokeAttributes.NoMangle"/> bit
/// </summary>
public bool IsNoMangle {
get => ((PInvokeAttributes)attributes & PInvokeAttributes.NoMangle) != 0;
set => ModifyAttributes(value, PInvokeAttributes.NoMangle);
}
/// <summary>
/// Gets/sets the char set
/// </summary>
public PInvokeAttributes CharSet {
get => (PInvokeAttributes)attributes & PInvokeAttributes.CharSetMask;
set => ModifyAttributes(~PInvokeAttributes.CharSetMask, value & PInvokeAttributes.CharSetMask);
}
/// <summary>
/// <c>true</c> if <see cref="PInvokeAttributes.CharSetNotSpec"/> is set
/// </summary>
public bool IsCharSetNotSpec => ((PInvokeAttributes)attributes & PInvokeAttributes.CharSetMask) == PInvokeAttributes.CharSetNotSpec;
/// <summary>
/// <c>true</c> if <see cref="PInvokeAttributes.CharSetAnsi"/> is set
/// </summary>
public bool IsCharSetAnsi => ((PInvokeAttributes)attributes & PInvokeAttributes.CharSetMask) == PInvokeAttributes.CharSetAnsi;
/// <summary>
/// <c>true</c> if <see cref="PInvokeAttributes.CharSetUnicode"/> is set
/// </summary>
public bool IsCharSetUnicode => ((PInvokeAttributes)attributes & PInvokeAttributes.CharSetMask) == PInvokeAttributes.CharSetUnicode;
/// <summary>
/// <c>true</c> if <see cref="PInvokeAttributes.CharSetAuto"/> is set
/// </summary>
public bool IsCharSetAuto => ((PInvokeAttributes)attributes & PInvokeAttributes.CharSetMask) == PInvokeAttributes.CharSetAuto;
/// <summary>
/// Gets/sets best fit
/// </summary>
public PInvokeAttributes BestFit {
get => (PInvokeAttributes)attributes & PInvokeAttributes.BestFitMask;
set => ModifyAttributes(~PInvokeAttributes.BestFitMask, value & PInvokeAttributes.BestFitMask);
}
/// <summary>
/// <c>true</c> if <see cref="PInvokeAttributes.BestFitUseAssem"/> is set
/// </summary>
public bool IsBestFitUseAssem => ((PInvokeAttributes)attributes & PInvokeAttributes.BestFitMask) == PInvokeAttributes.BestFitUseAssem;
/// <summary>
/// <c>true</c> if <see cref="PInvokeAttributes.BestFitEnabled"/> is set
/// </summary>
public bool IsBestFitEnabled => ((PInvokeAttributes)attributes & PInvokeAttributes.BestFitMask) == PInvokeAttributes.BestFitEnabled;
/// <summary>
/// <c>true</c> if <see cref="PInvokeAttributes.BestFitDisabled"/> is set
/// </summary>
public bool IsBestFitDisabled => ((PInvokeAttributes)attributes & PInvokeAttributes.BestFitMask) == PInvokeAttributes.BestFitDisabled;
/// <summary>
/// Gets/sets throw on unmappable char
/// </summary>
public PInvokeAttributes ThrowOnUnmappableChar {
get => (PInvokeAttributes)attributes & PInvokeAttributes.ThrowOnUnmappableCharMask;
set => ModifyAttributes(~PInvokeAttributes.ThrowOnUnmappableCharMask, value & PInvokeAttributes.ThrowOnUnmappableCharMask);
}
/// <summary>
/// <c>true</c> if <see cref="PInvokeAttributes.ThrowOnUnmappableCharUseAssem"/> is set
/// </summary>
public bool IsThrowOnUnmappableCharUseAssem => ((PInvokeAttributes)attributes & PInvokeAttributes.ThrowOnUnmappableCharMask) == PInvokeAttributes.ThrowOnUnmappableCharUseAssem;
/// <summary>
/// <c>true</c> if <see cref="PInvokeAttributes.ThrowOnUnmappableCharEnabled"/> is set
/// </summary>
public bool IsThrowOnUnmappableCharEnabled => ((PInvokeAttributes)attributes & PInvokeAttributes.ThrowOnUnmappableCharMask) == PInvokeAttributes.ThrowOnUnmappableCharEnabled;
/// <summary>
/// <c>true</c> if <see cref="PInvokeAttributes.ThrowOnUnmappableCharDisabled"/> is set
/// </summary>
public bool IsThrowOnUnmappableCharDisabled => ((PInvokeAttributes)attributes & PInvokeAttributes.ThrowOnUnmappableCharMask) == PInvokeAttributes.ThrowOnUnmappableCharDisabled;
/// <summary>
/// Gets/sets the <see cref="PInvokeAttributes.SupportsLastError"/> bit
/// </summary>
public bool SupportsLastError {
get => ((PInvokeAttributes)attributes & PInvokeAttributes.SupportsLastError) != 0;
set => ModifyAttributes(value, PInvokeAttributes.SupportsLastError);
}
/// <summary>
/// Gets/sets calling convention
/// </summary>
public PInvokeAttributes CallConv {
get => (PInvokeAttributes)attributes & PInvokeAttributes.CallConvMask;
set => ModifyAttributes(~PInvokeAttributes.CallConvMask, value & PInvokeAttributes.CallConvMask);
}
/// <summary>
/// <c>true</c> if <see cref="PInvokeAttributes.CallConvWinapi"/> is set
/// </summary>
public bool IsCallConvWinapi => ((PInvokeAttributes)attributes & PInvokeAttributes.CallConvMask) == PInvokeAttributes.CallConvWinapi;
/// <summary>
/// <c>true</c> if <see cref="PInvokeAttributes.CallConvCdecl"/> is set
/// </summary>
public bool IsCallConvCdecl => ((PInvokeAttributes)attributes & PInvokeAttributes.CallConvMask) == PInvokeAttributes.CallConvCdecl;
/// <summary>
/// <c>true</c> if <see cref="PInvokeAttributes.CallConvStdcall"/> is set
/// </summary>
public bool IsCallConvStdcall => ((PInvokeAttributes)attributes & PInvokeAttributes.CallConvMask) == PInvokeAttributes.CallConvStdcall;
/// <summary>
/// <c>true</c> if <see cref="PInvokeAttributes.CallConvThiscall"/> is set
/// </summary>
public bool IsCallConvThiscall => ((PInvokeAttributes)attributes & PInvokeAttributes.CallConvMask) == PInvokeAttributes.CallConvThiscall;
/// <summary>
/// <c>true</c> if <see cref="PInvokeAttributes.CallConvFastcall"/> is set
/// </summary>
public bool IsCallConvFastcall => ((PInvokeAttributes)attributes & PInvokeAttributes.CallConvMask) == PInvokeAttributes.CallConvFastcall;
/// <summary>
/// Checks whether this <see cref="ImplMap"/> is a certain P/Invoke method
/// </summary>
/// <param name="dllName">Name of the DLL</param>
/// <param name="funcName">Name of the function within the DLL</param>
/// <returns><c>true</c> if it's the specified P/Invoke method, else <c>false</c></returns>
public bool IsPinvokeMethod(string dllName, string funcName) => IsPinvokeMethod(dllName, funcName, IsWindows());
/// <summary>
/// Checks whether this <see cref="ImplMap"/> is a certain P/Invoke method
/// </summary>
/// <param name="dllName">Name of the DLL</param>
/// <param name="funcName">Name of the function within the DLL</param>
/// <param name="treatAsWindows">Treat as Windows</param>
/// <returns><c>true</c> if it's the specified P/Invoke method, else <c>false</c></returns>
public bool IsPinvokeMethod(string dllName, string funcName, bool treatAsWindows) {
if (name != funcName)
return false;
var mod = module;
if (mod is null)
return false;
return GetDllName(dllName, treatAsWindows).Equals(GetDllName(mod.Name, treatAsWindows), StringComparison.OrdinalIgnoreCase);
}
static string GetDllName(string dllName, bool treatAsWindows) {
if (treatAsWindows)
dllName = dllName.TrimEnd(trimChars);
if (dllName.EndsWith(".dll", StringComparison.OrdinalIgnoreCase))
return dllName.Substring(0, dllName.Length - 4);
return dllName;
}
static bool IsWindows() =>
#if NETSTANDARD || NETCOREAPP
RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
#else
Path.DirectorySeparatorChar == '\\' || Path.AltDirectorySeparatorChar == '\\';
#endif
static readonly char[] trimChars = { ' ' };
}
/// <summary>
/// An ImplMap row created by the user and not present in the original .NET file
/// </summary>
public class ImplMapUser : ImplMap {
/// <summary>
/// Default constructor
/// </summary>
public ImplMapUser() {
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="scope">Scope</param>
/// <param name="name">Name</param>
/// <param name="flags">Flags</param>
public ImplMapUser(ModuleRef scope, UTF8String name, PInvokeAttributes flags) {
module = scope;
this.name = name;
attributes = (int)flags;
}
}
/// <summary>
/// Created from a row in the ImplMap table
/// </summary>
sealed class ImplMapMD : ImplMap, IMDTokenProviderMD {
readonly uint origRid;
/// <inheritdoc/>
public uint OrigRid => origRid;
/// <summary>
/// Constructor
/// </summary>
/// <param name="readerModule">The module which contains this <c>ImplMap</c> row</param>
/// <param name="rid">Row ID</param>
/// <exception cref="ArgumentNullException">If <paramref name="readerModule"/> is <c>null</c></exception>
/// <exception cref="ArgumentException">If <paramref name="rid"/> is invalid</exception>
public ImplMapMD(ModuleDefMD readerModule, uint rid) {
#if DEBUG
if (readerModule is null)
throw new ArgumentNullException("readerModule");
if (readerModule.TablesStream.ImplMapTable.IsInvalidRID(rid))
throw new BadImageFormatException($"ImplMap rid {rid} does not exist");
#endif
origRid = rid;
this.rid = rid;
bool b = readerModule.TablesStream.TryReadImplMapRow(origRid, out var row);
Debug.Assert(b);
attributes = row.MappingFlags;
name = readerModule.StringsStream.ReadNoNull(row.ImportName);
module = readerModule.ResolveModuleRef(row.ImportScope);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,157 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using dnlib.DotNet.MD;
using dnlib.DotNet.Pdb;
namespace dnlib.DotNet {
/// <summary>
/// A high-level representation of a row in the InterfaceImpl table
/// </summary>
[DebuggerDisplay("{Interface}")]
public abstract class InterfaceImpl : IHasCustomAttribute, IContainsGenericParameter, IHasCustomDebugInformation {
/// <summary>
/// The row id in its table
/// </summary>
protected uint rid;
/// <inheritdoc/>
public MDToken MDToken => new MDToken(Table.InterfaceImpl, rid);
/// <inheritdoc/>
public uint Rid {
get => rid;
set => rid = value;
}
/// <inheritdoc/>
public int HasCustomAttributeTag => 5;
/// <summary>
/// From column InterfaceImpl.Interface
/// </summary>
public ITypeDefOrRef Interface {
get => @interface;
set => @interface = value;
}
/// <summary/>
protected ITypeDefOrRef @interface;
/// <summary>
/// Gets all custom attributes
/// </summary>
public CustomAttributeCollection CustomAttributes {
get {
if (customAttributes is null)
InitializeCustomAttributes();
return customAttributes;
}
}
/// <summary/>
protected CustomAttributeCollection customAttributes;
/// <summary>Initializes <see cref="customAttributes"/></summary>
protected virtual void InitializeCustomAttributes() =>
Interlocked.CompareExchange(ref customAttributes, new CustomAttributeCollection(), null);
/// <inheritdoc/>
public bool HasCustomAttributes => CustomAttributes.Count > 0;
/// <inheritdoc/>
public int HasCustomDebugInformationTag => 5;
/// <inheritdoc/>
public bool HasCustomDebugInfos => CustomDebugInfos.Count > 0;
/// <summary>
/// Gets all custom debug infos
/// </summary>
public IList<PdbCustomDebugInfo> CustomDebugInfos {
get {
if (customDebugInfos is null)
InitializeCustomDebugInfos();
return customDebugInfos;
}
}
/// <summary/>
protected IList<PdbCustomDebugInfo> customDebugInfos;
/// <summary>Initializes <see cref="customDebugInfos"/></summary>
protected virtual void InitializeCustomDebugInfos() =>
Interlocked.CompareExchange(ref customDebugInfos, new List<PdbCustomDebugInfo>(), null);
bool IContainsGenericParameter.ContainsGenericParameter => TypeHelper.ContainsGenericParameter(this);
}
/// <summary>
/// An InterfaceImpl row created by the user and not present in the original .NET file
/// </summary>
public class InterfaceImplUser : InterfaceImpl {
/// <summary>
/// Default constructor
/// </summary>
public InterfaceImplUser() {
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="interface">The interface the type implements</param>
public InterfaceImplUser(ITypeDefOrRef @interface) => this.@interface = @interface;
}
/// <summary>
/// Created from a row in the InterfaceImpl table
/// </summary>
sealed class InterfaceImplMD : InterfaceImpl, IMDTokenProviderMD, IContainsGenericParameter2 {
/// <summary>The module where this instance is located</summary>
readonly ModuleDefMD readerModule;
readonly uint origRid;
readonly GenericParamContext gpContext;
/// <inheritdoc/>
public uint OrigRid => origRid;
bool IContainsGenericParameter2.ContainsGenericParameter => TypeHelper.ContainsGenericParameter(this);
/// <inheritdoc/>
protected override void InitializeCustomAttributes() {
var list = readerModule.Metadata.GetCustomAttributeRidList(Table.InterfaceImpl, origRid);
var tmp = new CustomAttributeCollection(list.Count, list, (list2, index) => readerModule.ReadCustomAttribute(list[index]));
Interlocked.CompareExchange(ref customAttributes, tmp, null);
}
/// <inheritdoc/>
protected override void InitializeCustomDebugInfos() {
var list = new List<PdbCustomDebugInfo>();
readerModule.InitializeCustomDebugInfos(new MDToken(MDToken.Table, origRid), gpContext, list);
Interlocked.CompareExchange(ref customDebugInfos, list, null);
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="readerModule">The module which contains this <c>InterfaceImpl</c> row</param>
/// <param name="rid">Row ID</param>
/// <param name="gpContext">Generic parameter context</param>
/// <exception cref="ArgumentNullException">If <paramref name="readerModule"/> is <c>null</c></exception>
/// <exception cref="ArgumentException">If <paramref name="rid"/> is invalid</exception>
public InterfaceImplMD(ModuleDefMD readerModule, uint rid, GenericParamContext gpContext) {
#if DEBUG
if (readerModule is null)
throw new ArgumentNullException("readerModule");
if (readerModule.TablesStream.InterfaceImplTable.IsInvalidRID(rid))
throw new BadImageFormatException($"InterfaceImpl rid {rid} does not exist");
#endif
origRid = rid;
this.rid = rid;
this.readerModule = readerModule;
this.gpContext = gpContext;
bool b = readerModule.TablesStream.TryReadInterfaceImplRow(origRid, out var row);
Debug.Assert(b);
@interface = readerModule.ResolveTypeDefOrRef(row.Interface, gpContext);
}
}
}

View File

@ -1,73 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System;
using dnlib.IO;
namespace dnlib.DotNet.MD {
/// <summary>
/// Represents the #Blob stream
/// </summary>
public sealed class BlobStream : HeapStream {
/// <inheritdoc/>
public BlobStream() {
}
/// <inheritdoc/>
public BlobStream(DataReaderFactory mdReaderFactory, uint metadataBaseOffset, StreamHeader streamHeader)
: base(mdReaderFactory, metadataBaseOffset, streamHeader) {
}
/// <summary>
/// Reads data
/// </summary>
/// <param name="offset">Offset of data</param>
/// <returns>The data or <c>null</c> if invalid offset</returns>
public byte[] Read(uint offset) {
// The CLR has a special check for offset 0. It always interprets it as
// 0-length data, even if that first byte isn't 0 at all.
if (offset == 0)
return Array2.Empty<byte>();
if (!TryCreateReader(offset, out var reader))
return null;
return reader.ToArray();
}
/// <summary>
/// Reads data just like <see cref="Read"/>, but returns an empty array if
/// offset is invalid
/// </summary>
/// <param name="offset">Offset of data</param>
/// <returns>The data</returns>
public byte[] ReadNoNull(uint offset) => Read(offset) ?? Array2.Empty<byte>();
/// <summary>
/// Creates a reader that can access a blob
/// </summary>
/// <param name="offset">Offset of blob</param>
/// <returns>A new stream</returns>
public DataReader CreateReader(uint offset) {
if (TryCreateReader(offset, out var reader))
return reader;
return default;
}
/// <summary>
/// Creates a reader that can access a blob or returns false on failure
/// </summary>
/// <param name="offset">Offset of blob</param>
/// <param name="reader">Updated with the reader</param>
/// <returns></returns>
public bool TryCreateReader(uint offset, out DataReader reader) {
reader = dataReader;
if (!IsValidOffset(offset))
return false;
reader.Position = offset;
if (!reader.TryReadCompressedUInt32(out uint length))
return false;
if (!reader.CanRead(length))
return false;
reader = reader.Slice(reader.Position, length);
return true;
}
}
}

View File

@ -1,214 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System;
namespace dnlib.DotNet.MD {
/// <summary>
/// Contains all possible coded token classes
/// </summary>
public sealed class CodedToken {
/// <summary>TypeDefOrRef coded token</summary>
public static readonly CodedToken TypeDefOrRef = new CodedToken(2, new Table[3] {
Table.TypeDef, Table.TypeRef, Table.TypeSpec,
});
/// <summary>HasConstant coded token</summary>
public static readonly CodedToken HasConstant = new CodedToken(2, new Table[3] {
Table.Field, Table.Param, Table.Property,
});
/// <summary>HasCustomAttribute coded token</summary>
public static readonly CodedToken HasCustomAttribute = new CodedToken(5, new Table[24] {
Table.Method, Table.Field, Table.TypeRef, Table.TypeDef,
Table.Param, Table.InterfaceImpl, Table.MemberRef, Table.Module,
Table.DeclSecurity, Table.Property, Table.Event, Table.StandAloneSig,
Table.ModuleRef, Table.TypeSpec, Table.Assembly, Table.AssemblyRef,
Table.File, Table.ExportedType, Table.ManifestResource, Table.GenericParam,
Table.GenericParamConstraint, Table.MethodSpec, 0, 0,
});
/// <summary>HasFieldMarshal coded token</summary>
public static readonly CodedToken HasFieldMarshal = new CodedToken(1, new Table[2] {
Table.Field, Table.Param,
});
/// <summary>HasDeclSecurity coded token</summary>
public static readonly CodedToken HasDeclSecurity = new CodedToken(2, new Table[3] {
Table.TypeDef, Table.Method, Table.Assembly,
});
/// <summary>MemberRefParent coded token</summary>
public static readonly CodedToken MemberRefParent = new CodedToken(3, new Table[5] {
Table.TypeDef, Table.TypeRef, Table.ModuleRef, Table.Method,
Table.TypeSpec,
});
/// <summary>HasSemantic coded token</summary>
public static readonly CodedToken HasSemantic = new CodedToken(1, new Table[2] {
Table.Event, Table.Property,
});
/// <summary>MethodDefOrRef coded token</summary>
public static readonly CodedToken MethodDefOrRef = new CodedToken(1, new Table[2] {
Table.Method, Table.MemberRef,
});
/// <summary>MemberForwarded coded token</summary>
public static readonly CodedToken MemberForwarded = new CodedToken(1, new Table[2] {
Table.Field, Table.Method,
});
/// <summary>Implementation coded token</summary>
public static readonly CodedToken Implementation = new CodedToken(2, new Table[3] {
Table.File, Table.AssemblyRef, Table.ExportedType,
});
/// <summary>CustomAttributeType coded token</summary>
public static readonly CodedToken CustomAttributeType = new CodedToken(3, new Table[5] {
0, 0, Table.Method, Table.MemberRef, 0,
});
/// <summary>ResolutionScope coded token</summary>
public static readonly CodedToken ResolutionScope = new CodedToken(2, new Table[4] {
Table.Module, Table.ModuleRef, Table.AssemblyRef, Table.TypeRef,
});
/// <summary>TypeOrMethodDef coded token</summary>
public static readonly CodedToken TypeOrMethodDef = new CodedToken(1, new Table[2] {
Table.TypeDef, Table.Method,
});
/// <summary>HasCustomDebugInformation coded token</summary>
public static readonly CodedToken HasCustomDebugInformation = new CodedToken(5, new Table[27] {
Table.Method, Table.Field, Table.TypeRef, Table.TypeDef,
Table.Param, Table.InterfaceImpl, Table.MemberRef, Table.Module,
Table.DeclSecurity, Table.Property, Table.Event, Table.StandAloneSig,
Table.ModuleRef, Table.TypeSpec, Table.Assembly, Table.AssemblyRef,
Table.File, Table.ExportedType, Table.ManifestResource, Table.GenericParam,
Table.GenericParamConstraint, Table.MethodSpec, Table.Document, Table.LocalScope,
Table.LocalVariable, Table.LocalConstant, Table.ImportScope,
});
readonly Table[] tableTypes;
readonly int bits;
readonly int mask;
/// <summary>
/// Returns all types of tables
/// </summary>
public Table[] TableTypes => tableTypes;
/// <summary>
/// Returns the number of bits that is used to encode table type
/// </summary>
public int Bits => bits;
/// <summary>
/// Constructor
/// </summary>
/// <param name="bits">Number of bits used to encode token type</param>
/// <param name="tableTypes">All table types</param>
internal CodedToken(int bits, Table[] tableTypes) {
this.bits = bits;
mask = (1 << bits) - 1;
this.tableTypes = tableTypes;
}
/// <summary>
/// Encodes a token
/// </summary>
/// <param name="token">The token</param>
/// <returns>Coded token</returns>
/// <seealso cref="Encode(MDToken,out uint)"/>
public uint Encode(MDToken token) => Encode(token.Raw);
/// <summary>
/// Encodes a token
/// </summary>
/// <param name="token">The token</param>
/// <returns>Coded token</returns>
/// <seealso cref="Encode(uint,out uint)"/>
public uint Encode(uint token) {
Encode(token, out uint codedToken);
return codedToken;
}
/// <summary>
/// Encodes a token
/// </summary>
/// <param name="token">The token</param>
/// <param name="codedToken">Coded token</param>
/// <returns><c>true</c> if successful</returns>
public bool Encode(MDToken token, out uint codedToken) => Encode(token.Raw, out codedToken);
/// <summary>
/// Encodes a token
/// </summary>
/// <param name="token">The token</param>
/// <param name="codedToken">Coded token</param>
/// <returns><c>true</c> if successful</returns>
public bool Encode(uint token, out uint codedToken) {
int index = Array.IndexOf(tableTypes, MDToken.ToTable(token));
if (index < 0) {
codedToken = uint.MaxValue;
return false;
}
// This shift can never overflow a uint since bits < 8 (it's at most 5), and
// ToRid() returns an integer <= 0x00FFFFFF.
codedToken = (MDToken.ToRID(token) << bits) | (uint)index;
return true;
}
/// <summary>
/// Decodes a coded token
/// </summary>
/// <param name="codedToken">The coded token</param>
/// <returns>Decoded token or 0 on failure</returns>
/// <seealso cref="Decode(uint,out MDToken)"/>
public MDToken Decode2(uint codedToken) {
Decode(codedToken, out uint token);
return new MDToken(token);
}
/// <summary>
/// Decodes a coded token
/// </summary>
/// <param name="codedToken">The coded token</param>
/// <returns>Decoded token or 0 on failure</returns>
/// <seealso cref="Decode(uint,out uint)"/>
public uint Decode(uint codedToken) {
Decode(codedToken, out uint token);
return token;
}
/// <summary>
/// Decodes a coded token
/// </summary>
/// <param name="codedToken">The coded token</param>
/// <param name="token">Decoded token</param>
/// <returns><c>true</c> if successful</returns>
public bool Decode(uint codedToken, out MDToken token) {
bool result = Decode(codedToken, out uint decodedToken);
token = new MDToken(decodedToken);
return result;
}
/// <summary>
/// Decodes a coded token
/// </summary>
/// <param name="codedToken">The coded token</param>
/// <param name="token">Decoded token</param>
/// <returns><c>true</c> if successful</returns>
public bool Decode(uint codedToken, out uint token) {
uint rid = codedToken >> bits;
int index = (int)(codedToken & mask);
if (rid > MDToken.RID_MAX || index >= tableTypes.Length) {
token = 0;
return false;
}
token = ((uint)tableTypes[index] << MDToken.TABLE_SHIFT) | rid;
return true;
}
}
}

View File

@ -1,119 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System;
using System.Diagnostics;
using dnlib.DotNet.Writer;
using dnlib.IO;
namespace dnlib.DotNet.MD {
/// <summary>
/// Info about one column in a MD table
/// </summary>
[DebuggerDisplay("{offset} {size} {name}")]
public sealed class ColumnInfo {
readonly byte index;
byte offset;
readonly ColumnSize columnSize;
byte size;
readonly string name;
/// <summary>
/// Gets the column index
/// </summary>
public int Index => index;
/// <summary>
/// Returns the column offset within the table row
/// </summary>
public int Offset {
get => offset;
internal set => offset = (byte)value;
}
/// <summary>
/// Returns the column size
/// </summary>
public int Size {
get => size;
internal set => size = (byte)value;
}
/// <summary>
/// Returns the column name
/// </summary>
public string Name => name;
/// <summary>
/// Returns the ColumnSize enum value
/// </summary>
public ColumnSize ColumnSize => columnSize;
/// <summary>
/// Constructor
/// </summary>
/// <param name="index">Column index</param>
/// <param name="name">The column name</param>
/// <param name="columnSize">Column size</param>
public ColumnInfo(byte index, string name, ColumnSize columnSize) {
this.index = index;
this.name = name;
this.columnSize = columnSize;
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="index">Column index</param>
/// <param name="name">The column name</param>
/// <param name="columnSize">Column size</param>
/// <param name="offset">Offset of column</param>
/// <param name="size">Size of column</param>
public ColumnInfo(byte index, string name, ColumnSize columnSize, byte offset, byte size) {
this.index = index;
this.name = name;
this.columnSize = columnSize;
this.offset = offset;
this.size = size;
}
/// <summary>
/// Reads the column
/// </summary>
/// <param name="reader">A reader positioned on this column</param>
/// <returns>The column value</returns>
public uint Read(ref DataReader reader) =>
size switch {
1 => reader.ReadByte(),
2 => reader.ReadUInt16(),
4 => reader.ReadUInt32(),
_ => throw new InvalidOperationException("Invalid column size"),
};
internal uint Unsafe_Read24(ref DataReader reader) {
Debug.Assert(size == 2 || size == 4);
return size == 2 ? reader.Unsafe_ReadUInt16() : reader.Unsafe_ReadUInt32();
}
/// <summary>
/// Writes a column
/// </summary>
/// <param name="writer">The writer position on this column</param>
/// <param name="value">The column value</param>
public void Write(DataWriter writer, uint value) {
switch (size) {
case 1: writer.WriteByte((byte)value); break;
case 2: writer.WriteUInt16((ushort)value); break;
case 4: writer.WriteUInt32(value); break;
default: throw new InvalidOperationException("Invalid column size");
}
}
internal void Write24(DataWriter writer, uint value) {
Debug.Assert(size == 2 || size == 4);
if (size == 2)
writer.WriteUInt16((ushort)value);
else
writer.WriteUInt32(value);
}
}
}

View File

@ -1,159 +0,0 @@
// dnlib: See LICENSE.txt for more info
namespace dnlib.DotNet.MD {
/// <summary>
/// MD table column size
/// </summary>
public enum ColumnSize : byte {
/// <summary>RID into Module table</summary>
Module,
/// <summary>RID into TypeRef table</summary>
TypeRef,
/// <summary>RID into TypeDef table</summary>
TypeDef,
/// <summary>RID into FieldPtr table</summary>
FieldPtr,
/// <summary>RID into Field table</summary>
Field,
/// <summary>RID into MethodPtr table</summary>
MethodPtr,
/// <summary>RID into Method table</summary>
Method,
/// <summary>RID into ParamPtr table</summary>
ParamPtr,
/// <summary>RID into Param table</summary>
Param,
/// <summary>RID into InterfaceImpl table</summary>
InterfaceImpl,
/// <summary>RID into MemberRef table</summary>
MemberRef,
/// <summary>RID into Constant table</summary>
Constant,
/// <summary>RID into CustomAttribute table</summary>
CustomAttribute,
/// <summary>RID into FieldMarshal table</summary>
FieldMarshal,
/// <summary>RID into DeclSecurity table</summary>
DeclSecurity,
/// <summary>RID into ClassLayout table</summary>
ClassLayout,
/// <summary>RID into FieldLayout table</summary>
FieldLayout,
/// <summary>RID into StandAloneSig table</summary>
StandAloneSig,
/// <summary>RID into EventMap table</summary>
EventMap,
/// <summary>RID into EventPtr table</summary>
EventPtr,
/// <summary>RID into Event table</summary>
Event,
/// <summary>RID into PropertyMap table</summary>
PropertyMap,
/// <summary>RID into PropertyPtr table</summary>
PropertyPtr,
/// <summary>RID into Property table</summary>
Property,
/// <summary>RID into MethodSemantics table</summary>
MethodSemantics,
/// <summary>RID into MethodImpl table</summary>
MethodImpl,
/// <summary>RID into ModuleRef table</summary>
ModuleRef,
/// <summary>RID into TypeSpec table</summary>
TypeSpec,
/// <summary>RID into ImplMap table</summary>
ImplMap,
/// <summary>RID into FieldRVA table</summary>
FieldRVA,
/// <summary>RID into ENCLog table</summary>
ENCLog,
/// <summary>RID into ENCMap table</summary>
ENCMap,
/// <summary>RID into Assembly table</summary>
Assembly,
/// <summary>RID into AssemblyProcessor table</summary>
AssemblyProcessor,
/// <summary>RID into AssemblyOS table</summary>
AssemblyOS,
/// <summary>RID into AssemblyRef table</summary>
AssemblyRef,
/// <summary>RID into AssemblyRefProcessor table</summary>
AssemblyRefProcessor,
/// <summary>RID into AssemblyRefOS table</summary>
AssemblyRefOS,
/// <summary>RID into File table</summary>
File,
/// <summary>RID into ExportedType table</summary>
ExportedType,
/// <summary>RID into ManifestResource table</summary>
ManifestResource,
/// <summary>RID into NestedClass table</summary>
NestedClass,
/// <summary>RID into GenericParam table</summary>
GenericParam,
/// <summary>RID into MethodSpec table</summary>
MethodSpec,
/// <summary>RID into GenericParamConstraint table</summary>
GenericParamConstraint,
/// <summary>RID into Document table</summary>
Document = 0x30,
/// <summary>RID into MethodDebugInformation table</summary>
MethodDebugInformation,
/// <summary>RID into LocalScope table</summary>
LocalScope,
/// <summary>RID into LocalVariable table</summary>
LocalVariable,
/// <summary>RID into LocalConstant table</summary>
LocalConstant,
/// <summary>RID into ImportScope table</summary>
ImportScope,
/// <summary>RID into StateMachineMethod table</summary>
StateMachineMethod,
/// <summary>RID into CustomDebugInformation table</summary>
CustomDebugInformation,
/// <summary>8-bit byte</summary>
Byte = 0x40,
/// <summary>16-bit signed int</summary>
Int16,
/// <summary>16-bit unsigned int</summary>
UInt16,
/// <summary>32-bit signed int</summary>
Int32,
/// <summary>32-bit unsigned int</summary>
UInt32,
/// <summary>Index into #Strings stream</summary>
Strings,
/// <summary>Index into #GUID stream</summary>
GUID,
/// <summary>Index into #Blob stream</summary>
Blob,
/// <summary>TypeDefOrRef encoded token</summary>
TypeDefOrRef,
/// <summary>HasConstant encoded token</summary>
HasConstant,
/// <summary>HasCustomAttribute encoded token</summary>
HasCustomAttribute,
/// <summary>HasFieldMarshal encoded token</summary>
HasFieldMarshal,
/// <summary>HasDeclSecurity encoded token</summary>
HasDeclSecurity,
/// <summary>MemberRefParent encoded token</summary>
MemberRefParent,
/// <summary>HasSemantic encoded token</summary>
HasSemantic,
/// <summary>MethodDefOrRef encoded token</summary>
MethodDefOrRef,
/// <summary>MemberForwarded encoded token</summary>
MemberForwarded,
/// <summary>Implementation encoded token</summary>
Implementation,
/// <summary>CustomAttributeType encoded token</summary>
CustomAttributeType,
/// <summary>ResolutionScope encoded token</summary>
ResolutionScope,
/// <summary>TypeOrMethodDef encoded token</summary>
TypeOrMethodDef,
/// <summary>HasCustomDebugInformation encoded token</summary>
HasCustomDebugInformation,
}
}

View File

@ -1,46 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System;
namespace dnlib.DotNet.MD {
/// <summary>
/// See COMIMAGE_FLAGS_XXX in CorHdr.h in the Windows SDK
/// </summary>
[Flags]
public enum ComImageFlags : uint {
/// <summary>
/// See COMIMAGE_FLAGS_ILONLY in the Windows SDK
/// </summary>
ILOnly = 1,
/// <summary>
/// See COMIMAGE_FLAGS_32BITREQUIRED in the Windows SDK
/// </summary>
Bit32Required = 2,
/// <summary>
/// Set if a native header exists (COMIMAGE_FLAGS_IL_LIBRARY)
/// </summary>
ILLibrary = 4,
/// <summary>
/// See COMIMAGE_FLAGS_STRONGNAMESIGNED in the Windows SDK
/// </summary>
StrongNameSigned = 8,
/// <summary>
/// See COMIMAGE_FLAGS_NATIVE_ENTRYPOINT in the Windows SDK
/// </summary>
NativeEntryPoint = 0x10,
/// <summary>
/// See COMIMAGE_FLAGS_TRACKDEBUGDATA in the Windows SDK
/// </summary>
TrackDebugData = 0x10000,
/// <summary>
/// See COMIMAGE_FLAGS_32BITPREFERRED in the Windows SDK
/// </summary>
Bit32Preferred = 0x20000,
}
}

View File

@ -1,178 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System;
using System.Collections.Generic;
using dnlib.IO;
using dnlib.PE;
namespace dnlib.DotNet.MD {
/// <summary>
/// Used when a #~ stream is present in the metadata
/// </summary>
sealed class CompressedMetadata : MetadataBase {
readonly CLRRuntimeReaderKind runtime;
/// <inheritdoc/>
public override bool IsCompressed => true;
/// <inheritdoc/>
public CompressedMetadata(IPEImage peImage, ImageCor20Header cor20Header, MetadataHeader mdHeader, CLRRuntimeReaderKind runtime)
: base(peImage, cor20Header, mdHeader) {
this.runtime = runtime;
}
/// <inheritdoc/>
internal CompressedMetadata(MetadataHeader mdHeader, bool isStandalonePortablePdb, CLRRuntimeReaderKind runtime)
: base(mdHeader, isStandalonePortablePdb) {
this.runtime = runtime;
}
/// <inheritdoc/>
protected override void InitializeInternal(DataReaderFactory mdReaderFactory, uint metadataBaseOffset) {
DotNetStream dns = null;
var newAllStreams = new List<DotNetStream>(allStreams);
bool forceAllBig = false;
try {
for (int i = mdHeader.StreamHeaders.Count - 1; i >= 0; i--) {
var sh = mdHeader.StreamHeaders[i];
switch (sh.Name) {
case "#Strings":
if (stringsStream is null) {
stringsStream = new StringsStream(mdReaderFactory, metadataBaseOffset, sh);
newAllStreams.Add(stringsStream);
continue;
}
break;
case "#US":
if (usStream is null) {
usStream = new USStream(mdReaderFactory, metadataBaseOffset, sh);
newAllStreams.Add(usStream);
continue;
}
break;
case "#Blob":
if (blobStream is null) {
blobStream = new BlobStream(mdReaderFactory, metadataBaseOffset, sh);
newAllStreams.Add(blobStream);
continue;
}
break;
case "#GUID":
if (guidStream is null) {
guidStream = new GuidStream(mdReaderFactory, metadataBaseOffset, sh);
newAllStreams.Add(guidStream);
continue;
}
break;
case "#~":
if (tablesStream is null) {
tablesStream = new TablesStream(mdReaderFactory, metadataBaseOffset, sh, runtime);
newAllStreams.Add(tablesStream);
continue;
}
break;
case "#Pdb":
if (isStandalonePortablePdb && pdbStream is null) {
pdbStream = new PdbStream(mdReaderFactory, metadataBaseOffset, sh);
newAllStreams.Add(pdbStream);
continue;
}
break;
case "#JTD":
if (runtime == CLRRuntimeReaderKind.Mono) {
forceAllBig = true;
continue;
}
break;
}
dns = new CustomDotNetStream(mdReaderFactory, metadataBaseOffset, sh);
newAllStreams.Add(dns);
dns = null;
}
}
finally {
dns?.Dispose();
newAllStreams.Reverse();
allStreams = newAllStreams;
}
if (tablesStream is null)
throw new BadImageFormatException("Missing MD stream");
if (pdbStream is not null)
tablesStream.Initialize(pdbStream.TypeSystemTableRows, forceAllBig);
else
tablesStream.Initialize(null, forceAllBig);
}
/// <inheritdoc/>
public override RidList GetFieldRidList(uint typeDefRid) => GetRidList(tablesStream.TypeDefTable, typeDefRid, 4, tablesStream.FieldTable);
/// <inheritdoc/>
public override RidList GetMethodRidList(uint typeDefRid) => GetRidList(tablesStream.TypeDefTable, typeDefRid, 5, tablesStream.MethodTable);
/// <inheritdoc/>
public override RidList GetParamRidList(uint methodRid) => GetRidList(tablesStream.MethodTable, methodRid, 5, tablesStream.ParamTable);
/// <inheritdoc/>
public override RidList GetEventRidList(uint eventMapRid) => GetRidList(tablesStream.EventMapTable, eventMapRid, 1, tablesStream.EventTable);
/// <inheritdoc/>
public override RidList GetPropertyRidList(uint propertyMapRid) => GetRidList(tablesStream.PropertyMapTable, propertyMapRid, 1, tablesStream.PropertyTable);
/// <inheritdoc/>
public override RidList GetLocalVariableRidList(uint localScopeRid) => GetRidList(tablesStream.LocalScopeTable, localScopeRid, 2, tablesStream.LocalVariableTable);
/// <inheritdoc/>
public override RidList GetLocalConstantRidList(uint localScopeRid) => GetRidList(tablesStream.LocalScopeTable, localScopeRid, 3, tablesStream.LocalConstantTable);
/// <summary>
/// Gets a rid list (eg. field list)
/// </summary>
/// <param name="tableSource">Source table, eg. <c>TypeDef</c></param>
/// <param name="tableSourceRid">Row ID in <paramref name="tableSource"/></param>
/// <param name="colIndex">Column index in <paramref name="tableSource"/>, eg. 4 for <c>TypeDef.FieldList</c></param>
/// <param name="tableDest">Destination table, eg. <c>Field</c></param>
/// <returns>A new <see cref="RidList"/> instance</returns>
RidList GetRidList(MDTable tableSource, uint tableSourceRid, int colIndex, MDTable tableDest) {
var column = tableSource.TableInfo.Columns[colIndex];
if (!tablesStream.TryReadColumn24(tableSource, tableSourceRid, column, out uint startRid))
return RidList.Empty;
bool hasNext = tablesStream.TryReadColumn24(tableSource, tableSourceRid + 1, column, out uint nextListRid);
uint lastRid = tableDest.Rows + 1;
if (startRid == 0 || startRid >= lastRid)
return RidList.Empty;
uint endRid = !hasNext || (nextListRid == 0 && tableSourceRid + 1 == tableSource.Rows && tableDest.Rows == 0xFFFF) ? lastRid : nextListRid;
if (endRid < startRid)
endRid = startRid;
if (endRid > lastRid)
endRid = lastRid;
return RidList.Create(startRid, endRid - startRid);
}
/// <inheritdoc/>
protected override uint BinarySearch(MDTable tableSource, int keyColIndex, uint key) {
var keyColumn = tableSource.TableInfo.Columns[keyColIndex];
uint ridLo = 1, ridHi = tableSource.Rows;
while (ridLo <= ridHi) {
uint rid = (ridLo + ridHi) / 2;
if (!tablesStream.TryReadColumn24(tableSource, rid, keyColumn, out uint key2))
break; // Never happens since rid is valid
if (key == key2)
return rid;
if (key2 > key)
ridHi = rid - 1;
else
ridLo = rid + 1;
}
return 0;
}
}
}

View File

@ -1,25 +0,0 @@
// dnlib: See LICENSE.txt for more info
using dnlib.IO;
namespace dnlib.DotNet.MD {
/// <summary>
/// A custom .NET metadata stream
/// </summary>
public class CustomDotNetStream : DotNetStream {
/// <summary>
/// Constructor
/// </summary>
public CustomDotNetStream() { }
/// <summary>
/// Constructor
/// </summary>
/// <param name="mdReaderFactory">Data reader factory</param>
/// <param name="metadataBaseOffset">Offset of metadata</param>
/// <param name="streamHeader">The stream header</param>
public CustomDotNetStream(DataReaderFactory mdReaderFactory, uint metadataBaseOffset, StreamHeader streamHeader)
: base(mdReaderFactory, metadataBaseOffset, streamHeader) {
}
}
}

View File

@ -1,154 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System;
using System.Diagnostics;
using dnlib.IO;
namespace dnlib.DotNet.MD {
/// <summary>
/// .NET metadata stream
/// </summary>
[DebuggerDisplay("{dataReader.Length} {streamHeader.Name}")]
public abstract class DotNetStream : IFileSection, IDisposable {
/// <summary>
/// Reader that can access the whole stream.
///
/// NOTE: Always copy this field to a local variable before using it since it must be thread safe.
/// </summary>
protected DataReader dataReader;
/// <summary>
/// <c>null</c> if it wasn't present in the file
/// </summary>
StreamHeader streamHeader;
DataReaderFactory mdReaderFactory;
uint metadataBaseOffset;
/// <inheritdoc/>
public FileOffset StartOffset => (FileOffset)dataReader.StartOffset;
/// <inheritdoc/>
public FileOffset EndOffset => (FileOffset)dataReader.EndOffset;
/// <summary>
/// Gets the length of this stream in the metadata
/// </summary>
public uint StreamLength => dataReader.Length;
/// <summary>
/// Gets the stream header
/// </summary>
public StreamHeader StreamHeader => streamHeader;
/// <summary>
/// Gets the name of the stream
/// </summary>
public string Name => streamHeader is null ? string.Empty : streamHeader.Name;
/// <summary>
/// Gets a data reader that can read the full stream
/// </summary>
/// <returns></returns>
public DataReader CreateReader() => dataReader;
/// <summary>
/// Default constructor
/// </summary>
protected DotNetStream() {
streamHeader = null;
dataReader = default;
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="mdReaderFactory">Data reader factory</param>
/// <param name="metadataBaseOffset">Offset of metadata</param>
/// <param name="streamHeader">The stream header</param>
protected DotNetStream(DataReaderFactory mdReaderFactory, uint metadataBaseOffset, StreamHeader streamHeader) {
this.mdReaderFactory = mdReaderFactory;
mdReaderFactory.DataReaderInvalidated += DataReaderFactory_DataReaderInvalidated;
this.mdReaderFactory = mdReaderFactory;
this.metadataBaseOffset = metadataBaseOffset;
this.streamHeader = streamHeader;
RecreateReader(mdReaderFactory, metadataBaseOffset, streamHeader, notifyThisClass: false);
}
void DataReaderFactory_DataReaderInvalidated(object sender, EventArgs e) => RecreateReader(mdReaderFactory, metadataBaseOffset, streamHeader, notifyThisClass: true);
void RecreateReader(DataReaderFactory mdReaderFactory, uint metadataBaseOffset, StreamHeader streamHeader, bool notifyThisClass) {
if (mdReaderFactory is null || streamHeader is null)
dataReader = default;
else
dataReader = mdReaderFactory.CreateReader(metadataBaseOffset + streamHeader.Offset, streamHeader.StreamSize);
if (notifyThisClass)
OnReaderRecreated();
}
/// <summary>
/// Called after <see cref="dataReader"/> gets recreated
/// </summary>
protected virtual void OnReaderRecreated() { }
/// <inheritdoc/>
public void Dispose() {
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Dispose method
/// </summary>
/// <param name="disposing"><c>true</c> if called by <see cref="Dispose()"/></param>
protected virtual void Dispose(bool disposing) {
if (disposing) {
var mdReaderFactory = this.mdReaderFactory;
if (mdReaderFactory is not null)
mdReaderFactory.DataReaderInvalidated -= DataReaderFactory_DataReaderInvalidated;
streamHeader = null;
this.mdReaderFactory = null;
}
}
/// <summary>
/// Checks whether an index is valid
/// </summary>
/// <param name="index">The index</param>
/// <returns><c>true</c> if the index is valid</returns>
public virtual bool IsValidIndex(uint index) => IsValidOffset(index);
/// <summary>
/// Check whether an offset is within the stream
/// </summary>
/// <param name="offset">Stream offset</param>
/// <returns><c>true</c> if the offset is valid</returns>
public bool IsValidOffset(uint offset) => offset == 0 || offset < dataReader.Length;
/// <summary>
/// Check whether an offset is within the stream
/// </summary>
/// <param name="offset">Stream offset</param>
/// <param name="size">Size of data</param>
/// <returns><c>true</c> if the offset is valid</returns>
public bool IsValidOffset(uint offset, int size) {
if (size == 0)
return IsValidOffset(offset);
return size > 0 && (ulong)offset + (uint)size <= dataReader.Length;
}
}
/// <summary>
/// Base class of #US, #Strings, #Blob, and #GUID classes
/// </summary>
public abstract class HeapStream : DotNetStream {
/// <inheritdoc/>
protected HeapStream() {
}
/// <inheritdoc/>
protected HeapStream(DataReaderFactory mdReaderFactory, uint metadataBaseOffset, StreamHeader streamHeader)
: base(mdReaderFactory, metadataBaseOffset, streamHeader) {
}
}
}

View File

@ -1,408 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System;
using System.Collections.Generic;
namespace dnlib.DotNet.MD {
/// <summary>
/// Initializes .NET table row sizes
/// </summary>
public sealed class DotNetTableSizes {
bool bigStrings;
bool bigGuid;
bool bigBlob;
bool forceAllBig;
TableInfo[] tableInfos;
internal static bool IsSystemTable(Table table) => table < Table.Document;
/// <summary>
/// Initializes the table sizes
/// </summary>
/// <param name="bigStrings"><c>true</c> if #Strings size >= 0x10000</param>
/// <param name="bigGuid"><c>true</c> if #GUID size >= 0x10000</param>
/// <param name="bigBlob"><c>true</c> if #Blob size >= 0x10000</param>
/// <param name="systemRowCounts">Count of rows in each table</param>
/// <param name="debugRowCounts">Count of rows in each table (debug tables)</param>
public void InitializeSizes(bool bigStrings, bool bigGuid, bool bigBlob, IList<uint> systemRowCounts, IList<uint> debugRowCounts) =>
InitializeSizes(bigStrings, bigGuid, bigBlob, systemRowCounts, debugRowCounts, false);
/// <summary>
/// Initializes the table sizes
/// </summary>
/// <param name="bigStrings"><c>true</c> if #Strings size >= 0x10000</param>
/// <param name="bigGuid"><c>true</c> if #GUID size >= 0x10000</param>
/// <param name="bigBlob"><c>true</c> if #Blob size >= 0x10000</param>
/// <param name="systemRowCounts">Count of rows in each table</param>
/// <param name="debugRowCounts">Count of rows in each table (debug tables)</param>
/// <param name="forceAllBig">Force all columns to 4 bytes instead of 2 or 4 bytes</param>
internal void InitializeSizes(bool bigStrings, bool bigGuid, bool bigBlob, IList<uint> systemRowCounts, IList<uint> debugRowCounts, bool forceAllBig) {
this.bigStrings = bigStrings || forceAllBig;
this.bigGuid = bigGuid || forceAllBig;
this.bigBlob = bigBlob || forceAllBig;
this.forceAllBig = forceAllBig;
foreach (var tableInfo in tableInfos) {
var rowCounts = IsSystemTable(tableInfo.Table) ? systemRowCounts : debugRowCounts;
int colOffset = 0;
foreach (var colInfo in tableInfo.Columns) {
colInfo.Offset = colOffset;
var colSize = GetSize(colInfo.ColumnSize, rowCounts);
colInfo.Size = colSize;
colOffset += colSize;
}
tableInfo.RowSize = colOffset;
}
}
int GetSize(ColumnSize columnSize, IList<uint> rowCounts) {
if (ColumnSize.Module <= columnSize && columnSize <= ColumnSize.CustomDebugInformation) {
int table = (int)(columnSize - ColumnSize.Module);
uint count = table >= rowCounts.Count ? 0 : rowCounts[table];
return forceAllBig || count > 0xFFFF ? 4 : 2;
}
else if (ColumnSize.TypeDefOrRef <= columnSize && columnSize <= ColumnSize.HasCustomDebugInformation) {
var info = columnSize switch {
ColumnSize.TypeDefOrRef => CodedToken.TypeDefOrRef,
ColumnSize.HasConstant => CodedToken.HasConstant,
ColumnSize.HasCustomAttribute => CodedToken.HasCustomAttribute,
ColumnSize.HasFieldMarshal => CodedToken.HasFieldMarshal,
ColumnSize.HasDeclSecurity => CodedToken.HasDeclSecurity,
ColumnSize.MemberRefParent => CodedToken.MemberRefParent,
ColumnSize.HasSemantic => CodedToken.HasSemantic,
ColumnSize.MethodDefOrRef => CodedToken.MethodDefOrRef,
ColumnSize.MemberForwarded => CodedToken.MemberForwarded,
ColumnSize.Implementation => CodedToken.Implementation,
ColumnSize.CustomAttributeType => CodedToken.CustomAttributeType,
ColumnSize.ResolutionScope => CodedToken.ResolutionScope,
ColumnSize.TypeOrMethodDef => CodedToken.TypeOrMethodDef,
ColumnSize.HasCustomDebugInformation => CodedToken.HasCustomDebugInformation,
_ => throw new InvalidOperationException($"Invalid ColumnSize: {columnSize}"),
};
uint maxRows = 0;
foreach (var tableType in info.TableTypes) {
int index = (int)tableType;
var tableRows = index >= rowCounts.Count ? 0 : rowCounts[index];
if (tableRows > maxRows)
maxRows = tableRows;
}
// Can't overflow since maxRows <= 0x00FFFFFF and info.Bits < 8
uint finalRows = maxRows << info.Bits;
return forceAllBig || finalRows > 0xFFFF ? 4 : 2;
}
else {
switch (columnSize) {
case ColumnSize.Byte: return 1;
case ColumnSize.Int16: return 2;
case ColumnSize.UInt16: return 2;
case ColumnSize.Int32: return 4;
case ColumnSize.UInt32: return 4;
case ColumnSize.Strings:return forceAllBig || bigStrings ? 4 : 2;
case ColumnSize.GUID: return forceAllBig || bigGuid ? 4 : 2;
case ColumnSize.Blob: return forceAllBig || bigBlob ? 4 : 2;
}
}
throw new InvalidOperationException($"Invalid ColumnSize: {columnSize}");
}
/// <summary>
/// Creates the table infos
/// </summary>
/// <param name="majorVersion">Major table version</param>
/// <param name="minorVersion">Minor table version</param>
/// <returns>All table infos (not completely initialized)</returns>
public TableInfo[] CreateTables(byte majorVersion, byte minorVersion) =>
CreateTables(majorVersion, minorVersion, out int maxPresentTables);
internal const int normalMaxTables = (int)Table.CustomDebugInformation + 1;
/// <summary>
/// Creates the table infos
/// </summary>
/// <param name="majorVersion">Major table version</param>
/// <param name="minorVersion">Minor table version</param>
/// <param name="maxPresentTables">Initialized to max present tables (eg. 42 or 45)</param>
/// <returns>All table infos (not completely initialized)</returns>
public TableInfo[] CreateTables(byte majorVersion, byte minorVersion, out int maxPresentTables) {
maxPresentTables = (majorVersion == 1 && minorVersion == 0) ? (int)Table.NestedClass + 1 : normalMaxTables;
var tableInfos = new TableInfo[normalMaxTables];
tableInfos[(int)Table.Module] = new TableInfo(Table.Module, "Module", new ColumnInfo[] {
new ColumnInfo(0, "Generation", ColumnSize.UInt16),
new ColumnInfo(1, "Name", ColumnSize.Strings),
new ColumnInfo(2, "Mvid", ColumnSize.GUID),
new ColumnInfo(3, "EncId", ColumnSize.GUID),
new ColumnInfo(4, "EncBaseId", ColumnSize.GUID),
});
tableInfos[(int)Table.TypeRef] = new TableInfo(Table.TypeRef, "TypeRef", new ColumnInfo[] {
new ColumnInfo(0, "ResolutionScope", ColumnSize.ResolutionScope),
new ColumnInfo(1, "Name", ColumnSize.Strings),
new ColumnInfo(2, "Namespace", ColumnSize.Strings),
});
tableInfos[(int)Table.TypeDef] = new TableInfo(Table.TypeDef, "TypeDef", new ColumnInfo[] {
new ColumnInfo(0, "Flags", ColumnSize.UInt32),
new ColumnInfo(1, "Name", ColumnSize.Strings),
new ColumnInfo(2, "Namespace", ColumnSize.Strings),
new ColumnInfo(3, "Extends", ColumnSize.TypeDefOrRef),
new ColumnInfo(4, "FieldList", ColumnSize.Field),
new ColumnInfo(5, "MethodList", ColumnSize.Method),
});
tableInfos[(int)Table.FieldPtr] = new TableInfo(Table.FieldPtr, "FieldPtr", new ColumnInfo[] {
new ColumnInfo(0, "Field", ColumnSize.Field),
});
tableInfos[(int)Table.Field] = new TableInfo(Table.Field, "Field", new ColumnInfo[] {
new ColumnInfo(0, "Flags", ColumnSize.UInt16),
new ColumnInfo(1, "Name", ColumnSize.Strings),
new ColumnInfo(2, "Signature", ColumnSize.Blob),
});
tableInfos[(int)Table.MethodPtr] = new TableInfo(Table.MethodPtr, "MethodPtr", new ColumnInfo[] {
new ColumnInfo(0, "Method", ColumnSize.Method),
});
tableInfos[(int)Table.Method] = new TableInfo(Table.Method, "Method", new ColumnInfo[] {
new ColumnInfo(0, "RVA", ColumnSize.UInt32),
new ColumnInfo(1, "ImplFlags", ColumnSize.UInt16),
new ColumnInfo(2, "Flags", ColumnSize.UInt16),
new ColumnInfo(3, "Name", ColumnSize.Strings),
new ColumnInfo(4, "Signature", ColumnSize.Blob),
new ColumnInfo(5, "ParamList", ColumnSize.Param),
});
tableInfos[(int)Table.ParamPtr] = new TableInfo(Table.ParamPtr, "ParamPtr", new ColumnInfo[] {
new ColumnInfo(0, "Param", ColumnSize.Param),
});
tableInfos[(int)Table.Param] = new TableInfo(Table.Param, "Param", new ColumnInfo[] {
new ColumnInfo(0, "Flags", ColumnSize.UInt16),
new ColumnInfo(1, "Sequence", ColumnSize.UInt16),
new ColumnInfo(2, "Name", ColumnSize.Strings),
});
tableInfos[(int)Table.InterfaceImpl] = new TableInfo(Table.InterfaceImpl, "InterfaceImpl", new ColumnInfo[] {
new ColumnInfo(0, "Class", ColumnSize.TypeDef),
new ColumnInfo(1, "Interface", ColumnSize.TypeDefOrRef),
});
tableInfos[(int)Table.MemberRef] = new TableInfo(Table.MemberRef, "MemberRef", new ColumnInfo[] {
new ColumnInfo(0, "Class", ColumnSize.MemberRefParent),
new ColumnInfo(1, "Name", ColumnSize.Strings),
new ColumnInfo(2, "Signature", ColumnSize.Blob),
});
tableInfos[(int)Table.Constant] = new TableInfo(Table.Constant, "Constant", new ColumnInfo[] {
new ColumnInfo(0, "Type", ColumnSize.Byte),
new ColumnInfo(1, "Padding", ColumnSize.Byte),
new ColumnInfo(2, "Parent", ColumnSize.HasConstant),
new ColumnInfo(3, "Value", ColumnSize.Blob),
});
tableInfos[(int)Table.CustomAttribute] = new TableInfo(Table.CustomAttribute, "CustomAttribute", new ColumnInfo[] {
new ColumnInfo(0, "Parent", ColumnSize.HasCustomAttribute),
new ColumnInfo(1, "Type", ColumnSize.CustomAttributeType),
new ColumnInfo(2, "Value", ColumnSize.Blob),
});
tableInfos[(int)Table.FieldMarshal] = new TableInfo(Table.FieldMarshal, "FieldMarshal", new ColumnInfo[] {
new ColumnInfo(0, "Parent", ColumnSize.HasFieldMarshal),
new ColumnInfo(1, "NativeType", ColumnSize.Blob),
});
tableInfos[(int)Table.DeclSecurity] = new TableInfo(Table.DeclSecurity, "DeclSecurity", new ColumnInfo[] {
new ColumnInfo(0, "Action", ColumnSize.Int16),
new ColumnInfo(1, "Parent", ColumnSize.HasDeclSecurity),
new ColumnInfo(2, "PermissionSet", ColumnSize.Blob),
});
tableInfos[(int)Table.ClassLayout] = new TableInfo(Table.ClassLayout, "ClassLayout", new ColumnInfo[] {
new ColumnInfo(0, "PackingSize", ColumnSize.UInt16),
new ColumnInfo(1, "ClassSize", ColumnSize.UInt32),
new ColumnInfo(2, "Parent", ColumnSize.TypeDef),
});
tableInfos[(int)Table.FieldLayout] = new TableInfo(Table.FieldLayout, "FieldLayout", new ColumnInfo[] {
new ColumnInfo(0, "OffSet", ColumnSize.UInt32),
new ColumnInfo(1, "Field", ColumnSize.Field),
});
tableInfos[(int)Table.StandAloneSig] = new TableInfo(Table.StandAloneSig, "StandAloneSig", new ColumnInfo[] {
new ColumnInfo(0, "Signature", ColumnSize.Blob),
});
tableInfos[(int)Table.EventMap] = new TableInfo(Table.EventMap, "EventMap", new ColumnInfo[] {
new ColumnInfo(0, "Parent", ColumnSize.TypeDef),
new ColumnInfo(1, "EventList", ColumnSize.Event),
});
tableInfos[(int)Table.EventPtr] = new TableInfo(Table.EventPtr, "EventPtr", new ColumnInfo[] {
new ColumnInfo(0, "Event", ColumnSize.Event),
});
tableInfos[(int)Table.Event] = new TableInfo(Table.Event, "Event", new ColumnInfo[] {
new ColumnInfo(0, "EventFlags", ColumnSize.UInt16),
new ColumnInfo(1, "Name", ColumnSize.Strings),
new ColumnInfo(2, "EventType", ColumnSize.TypeDefOrRef),
});
tableInfos[(int)Table.PropertyMap] = new TableInfo(Table.PropertyMap, "PropertyMap", new ColumnInfo[] {
new ColumnInfo(0, "Parent", ColumnSize.TypeDef),
new ColumnInfo(1, "PropertyList", ColumnSize.Property),
});
tableInfos[(int)Table.PropertyPtr] = new TableInfo(Table.PropertyPtr, "PropertyPtr", new ColumnInfo[] {
new ColumnInfo(0, "Property", ColumnSize.Property),
});
tableInfos[(int)Table.Property] = new TableInfo(Table.Property, "Property", new ColumnInfo[] {
new ColumnInfo(0, "PropFlags", ColumnSize.UInt16),
new ColumnInfo(1, "Name", ColumnSize.Strings),
new ColumnInfo(2, "Type", ColumnSize.Blob),
});
tableInfos[(int)Table.MethodSemantics] = new TableInfo(Table.MethodSemantics, "MethodSemantics", new ColumnInfo[] {
new ColumnInfo(0, "Semantic", ColumnSize.UInt16),
new ColumnInfo(1, "Method", ColumnSize.Method),
new ColumnInfo(2, "Association", ColumnSize.HasSemantic),
});
tableInfos[(int)Table.MethodImpl] = new TableInfo(Table.MethodImpl, "MethodImpl", new ColumnInfo[] {
new ColumnInfo(0, "Class", ColumnSize.TypeDef),
new ColumnInfo(1, "MethodBody", ColumnSize.MethodDefOrRef),
new ColumnInfo(2, "MethodDeclaration", ColumnSize.MethodDefOrRef),
});
tableInfos[(int)Table.ModuleRef] = new TableInfo(Table.ModuleRef, "ModuleRef", new ColumnInfo[] {
new ColumnInfo(0, "Name", ColumnSize.Strings),
});
tableInfos[(int)Table.TypeSpec] = new TableInfo(Table.TypeSpec, "TypeSpec", new ColumnInfo[] {
new ColumnInfo(0, "Signature", ColumnSize.Blob),
});
tableInfos[(int)Table.ImplMap] = new TableInfo(Table.ImplMap, "ImplMap", new ColumnInfo[] {
new ColumnInfo(0, "MappingFlags", ColumnSize.UInt16),
new ColumnInfo(1, "MemberForwarded", ColumnSize.MemberForwarded),
new ColumnInfo(2, "ImportName", ColumnSize.Strings),
new ColumnInfo(3, "ImportScope", ColumnSize.ModuleRef),
});
tableInfos[(int)Table.FieldRVA] = new TableInfo(Table.FieldRVA, "FieldRVA", new ColumnInfo[] {
new ColumnInfo(0, "RVA", ColumnSize.UInt32),
new ColumnInfo(1, "Field", ColumnSize.Field),
});
tableInfos[(int)Table.ENCLog] = new TableInfo(Table.ENCLog, "ENCLog", new ColumnInfo[] {
new ColumnInfo(0, "Token", ColumnSize.UInt32),
new ColumnInfo(1, "FuncCode", ColumnSize.UInt32),
});
tableInfos[(int)Table.ENCMap] = new TableInfo(Table.ENCMap, "ENCMap", new ColumnInfo[] {
new ColumnInfo(0, "Token", ColumnSize.UInt32),
});
tableInfos[(int)Table.Assembly] = new TableInfo(Table.Assembly, "Assembly", new ColumnInfo[] {
new ColumnInfo(0, "HashAlgId", ColumnSize.UInt32),
new ColumnInfo(1, "MajorVersion", ColumnSize.UInt16),
new ColumnInfo(2, "MinorVersion", ColumnSize.UInt16),
new ColumnInfo(3, "BuildNumber", ColumnSize.UInt16),
new ColumnInfo(4, "RevisionNumber", ColumnSize.UInt16),
new ColumnInfo(5, "Flags", ColumnSize.UInt32),
new ColumnInfo(6, "PublicKey", ColumnSize.Blob),
new ColumnInfo(7, "Name", ColumnSize.Strings),
new ColumnInfo(8, "Locale", ColumnSize.Strings),
});
tableInfos[(int)Table.AssemblyProcessor] = new TableInfo(Table.AssemblyProcessor, "AssemblyProcessor", new ColumnInfo[] {
new ColumnInfo(0, "Processor", ColumnSize.UInt32),
});
tableInfos[(int)Table.AssemblyOS] = new TableInfo(Table.AssemblyOS, "AssemblyOS", new ColumnInfo[] {
new ColumnInfo(0, "OSPlatformId", ColumnSize.UInt32),
new ColumnInfo(1, "OSMajorVersion", ColumnSize.UInt32),
new ColumnInfo(2, "OSMinorVersion", ColumnSize.UInt32),
});
tableInfos[(int)Table.AssemblyRef] = new TableInfo(Table.AssemblyRef, "AssemblyRef", new ColumnInfo[] {
new ColumnInfo(0, "MajorVersion", ColumnSize.UInt16),
new ColumnInfo(1, "MinorVersion", ColumnSize.UInt16),
new ColumnInfo(2, "BuildNumber", ColumnSize.UInt16),
new ColumnInfo(3, "RevisionNumber", ColumnSize.UInt16),
new ColumnInfo(4, "Flags", ColumnSize.UInt32),
new ColumnInfo(5, "PublicKeyOrToken", ColumnSize.Blob),
new ColumnInfo(6, "Name", ColumnSize.Strings),
new ColumnInfo(7, "Locale", ColumnSize.Strings),
new ColumnInfo(8, "HashValue", ColumnSize.Blob),
});
tableInfos[(int)Table.AssemblyRefProcessor] = new TableInfo(Table.AssemblyRefProcessor, "AssemblyRefProcessor", new ColumnInfo[] {
new ColumnInfo(0, "Processor", ColumnSize.UInt32),
new ColumnInfo(1, "AssemblyRef", ColumnSize.AssemblyRef),
});
tableInfos[(int)Table.AssemblyRefOS] = new TableInfo(Table.AssemblyRefOS, "AssemblyRefOS", new ColumnInfo[] {
new ColumnInfo(0, "OSPlatformId", ColumnSize.UInt32),
new ColumnInfo(1, "OSMajorVersion", ColumnSize.UInt32),
new ColumnInfo(2, "OSMinorVersion", ColumnSize.UInt32),
new ColumnInfo(3, "AssemblyRef", ColumnSize.AssemblyRef),
});
tableInfos[(int)Table.File] = new TableInfo(Table.File, "File", new ColumnInfo[] {
new ColumnInfo(0, "Flags", ColumnSize.UInt32),
new ColumnInfo(1, "Name", ColumnSize.Strings),
new ColumnInfo(2, "HashValue", ColumnSize.Blob),
});
tableInfos[(int)Table.ExportedType] = new TableInfo(Table.ExportedType, "ExportedType", new ColumnInfo[] {
new ColumnInfo(0, "Flags", ColumnSize.UInt32),
new ColumnInfo(1, "TypeDefId", ColumnSize.UInt32),
new ColumnInfo(2, "TypeName", ColumnSize.Strings),
new ColumnInfo(3, "TypeNamespace", ColumnSize.Strings),
new ColumnInfo(4, "Implementation", ColumnSize.Implementation),
});
tableInfos[(int)Table.ManifestResource] = new TableInfo(Table.ManifestResource, "ManifestResource", new ColumnInfo[] {
new ColumnInfo(0, "Offset", ColumnSize.UInt32),
new ColumnInfo(1, "Flags", ColumnSize.UInt32),
new ColumnInfo(2, "Name", ColumnSize.Strings),
new ColumnInfo(3, "Implementation", ColumnSize.Implementation),
});
tableInfos[(int)Table.NestedClass] = new TableInfo(Table.NestedClass, "NestedClass", new ColumnInfo[] {
new ColumnInfo(0, "NestedClass", ColumnSize.TypeDef),
new ColumnInfo(1, "EnclosingClass", ColumnSize.TypeDef),
});
if (majorVersion == 1 && minorVersion == 1) {
tableInfos[(int)Table.GenericParam] = new TableInfo(Table.GenericParam, "GenericParam", new ColumnInfo[] {
new ColumnInfo(0, "Number", ColumnSize.UInt16),
new ColumnInfo(1, "Flags", ColumnSize.UInt16),
new ColumnInfo(2, "Owner", ColumnSize.TypeOrMethodDef),
new ColumnInfo(3, "Name", ColumnSize.Strings),
new ColumnInfo(4, "Kind", ColumnSize.TypeDefOrRef),
});
}
else {
tableInfos[(int)Table.GenericParam] = new TableInfo(Table.GenericParam, "GenericParam", new ColumnInfo[] {
new ColumnInfo(0, "Number", ColumnSize.UInt16),
new ColumnInfo(1, "Flags", ColumnSize.UInt16),
new ColumnInfo(2, "Owner", ColumnSize.TypeOrMethodDef),
new ColumnInfo(3, "Name", ColumnSize.Strings),
});
}
tableInfos[(int)Table.MethodSpec] = new TableInfo(Table.MethodSpec, "MethodSpec", new ColumnInfo[] {
new ColumnInfo(0, "Method", ColumnSize.MethodDefOrRef),
new ColumnInfo(1, "Instantiation", ColumnSize.Blob),
});
tableInfos[(int)Table.GenericParamConstraint] = new TableInfo(Table.GenericParamConstraint, "GenericParamConstraint", new ColumnInfo[] {
new ColumnInfo(0, "Owner", ColumnSize.GenericParam),
new ColumnInfo(1, "Constraint", ColumnSize.TypeDefOrRef),
});
tableInfos[0x2D] = new TableInfo((Table)0x2D, string.Empty, new ColumnInfo[] { });
tableInfos[0x2E] = new TableInfo((Table)0x2E, string.Empty, new ColumnInfo[] { });
tableInfos[0x2F] = new TableInfo((Table)0x2F, string.Empty, new ColumnInfo[] { });
tableInfos[(int)Table.Document] = new TableInfo(Table.Document, "Document", new ColumnInfo[] {
new ColumnInfo(0, "Name", ColumnSize.Blob),
new ColumnInfo(1, "HashAlgorithm", ColumnSize.GUID),
new ColumnInfo(2, "Hash", ColumnSize.Blob),
new ColumnInfo(3, "Language", ColumnSize.GUID),
});
tableInfos[(int)Table.MethodDebugInformation] = new TableInfo(Table.MethodDebugInformation, "MethodDebugInformation", new ColumnInfo[] {
new ColumnInfo(0, "Document", ColumnSize.Document),
new ColumnInfo(1, "SequencePoints", ColumnSize.Blob),
});
tableInfos[(int)Table.LocalScope] = new TableInfo(Table.LocalScope, "LocalScope", new ColumnInfo[] {
new ColumnInfo(0, "Method", ColumnSize.Method),
new ColumnInfo(1, "ImportScope", ColumnSize.ImportScope),
new ColumnInfo(2, "VariableList", ColumnSize.LocalVariable),
new ColumnInfo(3, "ConstantList", ColumnSize.LocalConstant),
new ColumnInfo(4, "StartOffset", ColumnSize.UInt32),
new ColumnInfo(5, "Length", ColumnSize.UInt32),
});
tableInfos[(int)Table.LocalVariable] = new TableInfo(Table.LocalVariable, "LocalVariable", new ColumnInfo[] {
new ColumnInfo(0, "Attributes", ColumnSize.UInt16),
new ColumnInfo(1, "Index", ColumnSize.UInt16),
new ColumnInfo(2, "Name", ColumnSize.Strings),
});
tableInfos[(int)Table.LocalConstant] = new TableInfo(Table.LocalConstant, "LocalConstant", new ColumnInfo[] {
new ColumnInfo(0, "Name", ColumnSize.Strings),
new ColumnInfo(1, "Signature", ColumnSize.Blob),
});
tableInfos[(int)Table.ImportScope] = new TableInfo(Table.ImportScope, "ImportScope", new ColumnInfo[] {
new ColumnInfo(0, "Parent", ColumnSize.ImportScope),
new ColumnInfo(1, "Imports", ColumnSize.Blob),
});
tableInfos[(int)Table.StateMachineMethod] = new TableInfo(Table.StateMachineMethod, "StateMachineMethod", new ColumnInfo[] {
new ColumnInfo(0, "MoveNextMethod", ColumnSize.Method),
new ColumnInfo(1, "KickoffMethod", ColumnSize.Method),
});
tableInfos[(int)Table.CustomDebugInformation] = new TableInfo(Table.CustomDebugInformation, "CustomDebugInformation", new ColumnInfo[] {
new ColumnInfo(0, "Parent", ColumnSize.HasCustomDebugInformation),
new ColumnInfo(1, "Kind", ColumnSize.GUID),
new ColumnInfo(2, "Value", ColumnSize.Blob),
});
return this.tableInfos = tableInfos;
}
}
}

View File

@ -1,518 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System;
using System.Collections.Generic;
using System.Diagnostics;
using dnlib.IO;
using dnlib.PE;
using dnlib.Threading;
namespace dnlib.DotNet.MD {
/// <summary>
/// Used when a #- stream is present in the metadata
/// </summary>
sealed class ENCMetadata : MetadataBase {
static readonly UTF8String DeletedName = "_Deleted";
bool hasMethodPtr, hasFieldPtr, hasParamPtr, hasEventPtr, hasPropertyPtr;
bool hasDeletedFields;
bool hasDeletedNonFields;
readonly CLRRuntimeReaderKind runtime;
readonly Dictionary<Table, SortedTable> sortedTables = new Dictionary<Table, SortedTable>();
#if THREAD_SAFE
readonly Lock theLock = Lock.Create();
#endif
/// <inheritdoc/>
public override bool IsCompressed => false;
/// <inheritdoc/>
public ENCMetadata(IPEImage peImage, ImageCor20Header cor20Header, MetadataHeader mdHeader, CLRRuntimeReaderKind runtime)
: base(peImage, cor20Header, mdHeader) {
this.runtime = runtime;
}
/// <inheritdoc/>
internal ENCMetadata(MetadataHeader mdHeader, bool isStandalonePortablePdb, CLRRuntimeReaderKind runtime)
: base(mdHeader, isStandalonePortablePdb) {
this.runtime = runtime;
}
/// <inheritdoc/>
protected override void InitializeInternal(DataReaderFactory mdReaderFactory, uint metadataBaseOffset) {
DotNetStream dns = null;
bool forceAllBig = false;
try {
if (runtime == CLRRuntimeReaderKind.Mono) {
var newAllStreams = new List<DotNetStream>(allStreams);
for (int i = mdHeader.StreamHeaders.Count - 1; i >= 0; i--) {
var sh = mdHeader.StreamHeaders[i];
switch (sh.Name) {
case "#Strings":
if (stringsStream is null) {
stringsStream = new StringsStream(mdReaderFactory, metadataBaseOffset, sh);
newAllStreams.Add(stringsStream);
continue;
}
break;
case "#US":
if (usStream is null) {
usStream = new USStream(mdReaderFactory, metadataBaseOffset, sh);
newAllStreams.Add(usStream);
continue;
}
break;
case "#Blob":
if (blobStream is null) {
blobStream = new BlobStream(mdReaderFactory, metadataBaseOffset, sh);
newAllStreams.Add(blobStream);
continue;
}
break;
case "#GUID":
if (guidStream is null) {
guidStream = new GuidStream(mdReaderFactory, metadataBaseOffset, sh);
newAllStreams.Add(guidStream);
continue;
}
break;
case "#~":
case "#-":
if (tablesStream is null) {
tablesStream = new TablesStream(mdReaderFactory, metadataBaseOffset, sh, runtime);
newAllStreams.Add(tablesStream);
continue;
}
break;
case "#Pdb":
if (isStandalonePortablePdb && pdbStream is null) {
pdbStream = new PdbStream(mdReaderFactory, metadataBaseOffset, sh);
newAllStreams.Add(pdbStream);
continue;
}
break;
case "#JTD":
forceAllBig = true;
continue;
}
dns = new CustomDotNetStream(mdReaderFactory, metadataBaseOffset, sh);
newAllStreams.Add(dns);
dns = null;
}
newAllStreams.Reverse();
allStreams = newAllStreams;
}
else {
Debug.Assert(runtime == CLRRuntimeReaderKind.CLR);
foreach (var sh in mdHeader.StreamHeaders) {
switch (sh.Name.ToUpperInvariant()) {
case "#STRINGS":
if (stringsStream is null) {
stringsStream = new StringsStream(mdReaderFactory, metadataBaseOffset, sh);
allStreams.Add(stringsStream);
continue;
}
break;
case "#US":
if (usStream is null) {
usStream = new USStream(mdReaderFactory, metadataBaseOffset, sh);
allStreams.Add(usStream);
continue;
}
break;
case "#BLOB":
if (blobStream is null) {
blobStream = new BlobStream(mdReaderFactory, metadataBaseOffset, sh);
allStreams.Add(blobStream);
continue;
}
break;
case "#GUID":
if (guidStream is null) {
guidStream = new GuidStream(mdReaderFactory, metadataBaseOffset, sh);
allStreams.Add(guidStream);
continue;
}
break;
case "#~": // Only if #Schema is used
case "#-":
if (tablesStream is null) {
tablesStream = new TablesStream(mdReaderFactory, metadataBaseOffset, sh, runtime);
allStreams.Add(tablesStream);
continue;
}
break;
case "#PDB":
// Case sensitive comparison since it's a stream that's not read by the CLR,
// only by other libraries eg. System.Reflection.Metadata.
if (isStandalonePortablePdb && pdbStream is null && sh.Name == "#Pdb") {
pdbStream = new PdbStream(mdReaderFactory, metadataBaseOffset, sh);
allStreams.Add(pdbStream);
continue;
}
break;
case "#JTD":
forceAllBig = true;
continue;
}
dns = new CustomDotNetStream(mdReaderFactory, metadataBaseOffset, sh);
allStreams.Add(dns);
dns = null;
}
}
}
finally {
dns?.Dispose();
}
if (tablesStream is null)
throw new BadImageFormatException("Missing MD stream");
if (pdbStream is not null)
tablesStream.Initialize(pdbStream.TypeSystemTableRows, forceAllBig);
else
tablesStream.Initialize(null, forceAllBig);
// The pointer tables are used iff row count != 0
hasFieldPtr = !tablesStream.FieldPtrTable.IsEmpty;
hasMethodPtr = !tablesStream.MethodPtrTable.IsEmpty;
hasParamPtr = !tablesStream.ParamPtrTable.IsEmpty;
hasEventPtr = !tablesStream.EventPtrTable.IsEmpty;
hasPropertyPtr = !tablesStream.PropertyPtrTable.IsEmpty;
switch (runtime) {
case CLRRuntimeReaderKind.CLR:
hasDeletedFields = tablesStream.HasDelete;
hasDeletedNonFields = tablesStream.HasDelete;
break;
case CLRRuntimeReaderKind.Mono:
hasDeletedFields = true;
hasDeletedNonFields = false;
break;
default:
throw new InvalidOperationException();
}
}
/// <inheritdoc/>
public override RidList GetTypeDefRidList() {
if (!hasDeletedNonFields)
return base.GetTypeDefRidList();
uint rows = tablesStream.TypeDefTable.Rows;
var list = new List<uint>((int)rows);
for (uint rid = 1; rid <= rows; rid++) {
if (!tablesStream.TryReadTypeDefRow(rid, out var row))
continue; // Should never happen since rid is valid
// RTSpecialName is ignored by the CLR. It's only the name that indicates
// whether it's been deleted.
// It's not possible to delete the global type (<Module>)
if (rid != 1 && stringsStream.ReadNoNull(row.Name).StartsWith(DeletedName))
continue; // ignore this deleted row
list.Add(rid);
}
return RidList.Create(list);
}
/// <inheritdoc/>
public override RidList GetExportedTypeRidList() {
if (!hasDeletedNonFields)
return base.GetExportedTypeRidList();
uint rows = tablesStream.ExportedTypeTable.Rows;
var list = new List<uint>((int)rows);
for (uint rid = 1; rid <= rows; rid++) {
if (!tablesStream.TryReadExportedTypeRow(rid, out var row))
continue; // Should never happen since rid is valid
// RTSpecialName is ignored by the CLR. It's only the name that indicates
// whether it's been deleted.
if (stringsStream.ReadNoNull(row.TypeName).StartsWith(DeletedName))
continue; // ignore this deleted row
list.Add(rid);
}
return RidList.Create(list);
}
/// <summary>
/// Converts a logical <c>Field</c> rid to a physical <c>Field</c> rid
/// </summary>
/// <param name="listRid">A valid rid</param>
/// <returns>Converted rid or any invalid rid value if <paramref name="listRid"/> is invalid</returns>
uint ToFieldRid(uint listRid) {
if (!hasFieldPtr)
return listRid;
return tablesStream.TryReadColumn24(tablesStream.FieldPtrTable, listRid, 0, out uint listValue) ? listValue : 0;
}
/// <summary>
/// Converts a logical <c>Method</c> rid to a physical <c>Method</c> rid
/// </summary>
/// <param name="listRid">A valid rid</param>
/// <returns>Converted rid or any invalid rid value if <paramref name="listRid"/> is invalid</returns>
uint ToMethodRid(uint listRid) {
if (!hasMethodPtr)
return listRid;
return tablesStream.TryReadColumn24(tablesStream.MethodPtrTable, listRid, 0, out uint listValue) ? listValue : 0;
}
/// <summary>
/// Converts a logical <c>Param</c> rid to a physical <c>Param</c> rid
/// </summary>
/// <param name="listRid">A valid rid</param>
/// <returns>Converted rid or any invalid rid value if <paramref name="listRid"/> is invalid</returns>
uint ToParamRid(uint listRid) {
if (!hasParamPtr)
return listRid;
return tablesStream.TryReadColumn24(tablesStream.ParamPtrTable, listRid, 0, out uint listValue) ? listValue : 0;
}
/// <summary>
/// Converts a logical <c>Event</c> rid to a physical <c>Event</c> rid
/// </summary>
/// <param name="listRid">A valid rid</param>
/// <returns>Converted rid or any invalid rid value if <paramref name="listRid"/> is invalid</returns>
uint ToEventRid(uint listRid) {
if (!hasEventPtr)
return listRid;
return tablesStream.TryReadColumn24(tablesStream.EventPtrTable, listRid, 0, out uint listValue) ? listValue : 0;
}
/// <summary>
/// Converts a logical <c>Property</c> rid to a physical <c>Property</c> rid
/// </summary>
/// <param name="listRid">A valid rid</param>
/// <returns>Converted rid or any invalid rid value if <paramref name="listRid"/> is invalid</returns>
uint ToPropertyRid(uint listRid) {
if (!hasPropertyPtr)
return listRid;
return tablesStream.TryReadColumn24(tablesStream.PropertyPtrTable, listRid, 0, out uint listValue) ? listValue : 0;
}
/// <inheritdoc/>
public override RidList GetFieldRidList(uint typeDefRid) {
var list = GetRidList(tablesStream.TypeDefTable, typeDefRid, 4, tablesStream.FieldTable);
if (list.Count == 0 || (!hasFieldPtr && !hasDeletedFields))
return list;
var destTable = tablesStream.FieldTable;
var newList = new List<uint>(list.Count);
for (int i = 0; i < list.Count; i++) {
var rid = ToFieldRid(list[i]);
if (destTable.IsInvalidRID(rid))
continue;
if (hasDeletedFields) {
// It's a deleted row if RTSpecialName is set and name is "_Deleted"
if (!tablesStream.TryReadFieldRow(rid, out var row))
continue; // Should never happen since rid is valid
if (runtime == CLRRuntimeReaderKind.CLR) {
if ((row.Flags & (uint)FieldAttributes.RTSpecialName) != 0) {
if (stringsStream.ReadNoNull(row.Name).StartsWith(DeletedName))
continue; // ignore this deleted row
}
}
else {
if ((row.Flags & (uint)(FieldAttributes.SpecialName | FieldAttributes.RTSpecialName)) == (uint)(FieldAttributes.SpecialName | FieldAttributes.RTSpecialName)) {
if (stringsStream.ReadNoNull(row.Name) == DeletedName)
continue; // ignore this deleted row
}
}
}
// It's a valid non-deleted rid so add it
newList.Add(rid);
}
return RidList.Create(newList);
}
/// <inheritdoc/>
public override RidList GetMethodRidList(uint typeDefRid) {
var list = GetRidList(tablesStream.TypeDefTable, typeDefRid, 5, tablesStream.MethodTable);
if (list.Count == 0 || (!hasMethodPtr && !hasDeletedNonFields))
return list;
var destTable = tablesStream.MethodTable;
var newList = new List<uint>(list.Count);
for (int i = 0; i < list.Count; i++) {
var rid = ToMethodRid(list[i]);
if (destTable.IsInvalidRID(rid))
continue;
if (hasDeletedNonFields) {
// It's a deleted row if RTSpecialName is set and name is "_Deleted"
if (!tablesStream.TryReadMethodRow(rid, out var row))
continue; // Should never happen since rid is valid
if ((row.Flags & (uint)MethodAttributes.RTSpecialName) != 0) {
if (stringsStream.ReadNoNull(row.Name).StartsWith(DeletedName))
continue; // ignore this deleted row
}
}
// It's a valid non-deleted rid so add it
newList.Add(rid);
}
return RidList.Create(newList);
}
/// <inheritdoc/>
public override RidList GetParamRidList(uint methodRid) {
var list = GetRidList(tablesStream.MethodTable, methodRid, 5, tablesStream.ParamTable);
if (list.Count == 0 || !hasParamPtr)
return list;
var destTable = tablesStream.ParamTable;
var newList = new List<uint>(list.Count);
for (int i = 0; i < list.Count; i++) {
var rid = ToParamRid(list[i]);
if (destTable.IsInvalidRID(rid))
continue;
newList.Add(rid);
}
return RidList.Create(newList);
}
/// <inheritdoc/>
public override RidList GetEventRidList(uint eventMapRid) {
var list = GetRidList(tablesStream.EventMapTable, eventMapRid, 1, tablesStream.EventTable);
if (list.Count == 0 || (!hasEventPtr && !hasDeletedNonFields))
return list;
var destTable = tablesStream.EventTable;
var newList = new List<uint>(list.Count);
for (int i = 0; i < list.Count; i++) {
var rid = ToEventRid(list[i]);
if (destTable.IsInvalidRID(rid))
continue;
if (hasDeletedNonFields) {
// It's a deleted row if RTSpecialName is set and name is "_Deleted"
if (!tablesStream.TryReadEventRow(rid, out var row))
continue; // Should never happen since rid is valid
if ((row.EventFlags & (uint)EventAttributes.RTSpecialName) != 0) {
if (stringsStream.ReadNoNull(row.Name).StartsWith(DeletedName))
continue; // ignore this deleted row
}
}
// It's a valid non-deleted rid so add it
newList.Add(rid);
}
return RidList.Create(newList);
}
/// <inheritdoc/>
public override RidList GetPropertyRidList(uint propertyMapRid) {
var list = GetRidList(tablesStream.PropertyMapTable, propertyMapRid, 1, tablesStream.PropertyTable);
if (list.Count == 0 || (!hasPropertyPtr && !hasDeletedNonFields))
return list;
var destTable = tablesStream.PropertyTable;
var newList = new List<uint>(list.Count);
for (int i = 0; i < list.Count; i++) {
var rid = ToPropertyRid(list[i]);
if (destTable.IsInvalidRID(rid))
continue;
if (hasDeletedNonFields) {
// It's a deleted row if RTSpecialName is set and name is "_Deleted"
if (!tablesStream.TryReadPropertyRow(rid, out var row))
continue; // Should never happen since rid is valid
if ((row.PropFlags & (uint)PropertyAttributes.RTSpecialName) != 0) {
if (stringsStream.ReadNoNull(row.Name).StartsWith(DeletedName))
continue; // ignore this deleted row
}
}
// It's a valid non-deleted rid so add it
newList.Add(rid);
}
return RidList.Create(newList);
}
/// <inheritdoc/>
public override RidList GetLocalVariableRidList(uint localScopeRid) => GetRidList(tablesStream.LocalScopeTable, localScopeRid, 2, tablesStream.LocalVariableTable);
/// <inheritdoc/>
public override RidList GetLocalConstantRidList(uint localScopeRid) => GetRidList(tablesStream.LocalScopeTable, localScopeRid, 3, tablesStream.LocalConstantTable);
/// <summary>
/// Gets a rid list (eg. field list)
/// </summary>
/// <param name="tableSource">Source table, eg. <c>TypeDef</c></param>
/// <param name="tableSourceRid">Row ID in <paramref name="tableSource"/></param>
/// <param name="colIndex">Column index in <paramref name="tableSource"/>, eg. 4 for <c>TypeDef.FieldList</c></param>
/// <param name="tableDest">Destination table, eg. <c>Field</c></param>
/// <returns>A new <see cref="RidList"/> instance</returns>
RidList GetRidList(MDTable tableSource, uint tableSourceRid, int colIndex, MDTable tableDest) {
var column = tableSource.TableInfo.Columns[colIndex];
if (!tablesStream.TryReadColumn24(tableSource, tableSourceRid, column, out uint startRid))
return RidList.Empty;
bool hasNext = tablesStream.TryReadColumn24(tableSource, tableSourceRid + 1, column, out uint nextListRid);
uint lastRid = tableDest.Rows + 1;
if (startRid == 0 || startRid >= lastRid)
return RidList.Empty;
uint endRid = hasNext && nextListRid != 0 ? nextListRid : lastRid;
if (endRid < startRid)
endRid = startRid;
if (endRid > lastRid)
endRid = lastRid;
return RidList.Create(startRid, endRid - startRid);
}
/// <inheritdoc/>
protected override uint BinarySearch(MDTable tableSource, int keyColIndex, uint key) {
var keyColumn = tableSource.TableInfo.Columns[keyColIndex];
uint ridLo = 1, ridHi = tableSource.Rows;
while (ridLo <= ridHi) {
uint rid = (ridLo + ridHi) / 2;
if (!tablesStream.TryReadColumn24(tableSource, rid, keyColumn, out uint key2))
break; // Never happens since rid is valid
if (key == key2)
return rid;
if (key2 > key)
ridHi = rid - 1;
else
ridLo = rid + 1;
}
if (tableSource.Table == Table.GenericParam && !tablesStream.IsSorted(tableSource))
return LinearSearch(tableSource, keyColIndex, key);
return 0;
}
uint LinearSearch(MDTable tableSource, int keyColIndex, uint key) {
if (tableSource is null)
return 0;
var keyColumn = tableSource.TableInfo.Columns[keyColIndex];
for (uint rid = 1; rid <= tableSource.Rows; rid++) {
if (!tablesStream.TryReadColumn24(tableSource, rid, keyColumn, out uint key2))
break; // Never happens since rid is valid
if (key == key2)
return rid;
}
return 0;
}
/// <inheritdoc/>
protected override RidList FindAllRowsUnsorted(MDTable tableSource, int keyColIndex, uint key) {
if (tablesStream.IsSorted(tableSource))
return FindAllRows(tableSource, keyColIndex, key);
SortedTable sortedTable;
#if THREAD_SAFE
theLock.EnterWriteLock(); try {
#endif
if (!sortedTables.TryGetValue(tableSource.Table, out sortedTable))
sortedTables[tableSource.Table] = sortedTable = new SortedTable(tableSource, keyColIndex);
#if THREAD_SAFE
} finally { theLock.ExitWriteLock(); }
#endif
return sortedTable.FindAllRows(key);
}
}
}

View File

@ -1,36 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System;
using dnlib.IO;
namespace dnlib.DotNet.MD {
/// <summary>
/// Represents the #GUID stream
/// </summary>
public sealed class GuidStream : HeapStream {
/// <inheritdoc/>
public GuidStream() {
}
/// <inheritdoc/>
public GuidStream(DataReaderFactory mdReaderFactory, uint metadataBaseOffset, StreamHeader streamHeader)
: base(mdReaderFactory, metadataBaseOffset, streamHeader) {
}
/// <inheritdoc/>
public override bool IsValidIndex(uint index) => index == 0 || (index <= 0x10000000 && IsValidOffset((index - 1) * 16, 16));
/// <summary>
/// Read a <see cref="Guid"/>
/// </summary>
/// <param name="index">Index into this stream</param>
/// <returns>A <see cref="Guid"/> or <c>null</c> if <paramref name="index"/> is 0 or invalid</returns>
public Guid? Read(uint index) {
if (index == 0 || !IsValidIndex(index))
return null;
var reader = dataReader;
reader.Position = (index - 1) * 16;
return reader.ReadGuid();
}
}
}

View File

@ -1,17 +0,0 @@
// dnlib: See LICENSE.txt for more info
namespace dnlib.DotNet.MD {
/// <summary>
/// Heap type. The values are set in stone by MS. Don't change.
/// </summary>
public enum HeapType : uint {
/// <summary>#Strings heap</summary>
Strings = 0,
/// <summary>#GUID heap</summary>
Guid = 1,
/// <summary>#Blob heap</summary>
Blob = 2,
/// <summary>#US heap</summary>
US = 3,
}
}

View File

@ -1,33 +0,0 @@
// dnlib: See LICENSE.txt for more info
namespace dnlib.DotNet.MD {
/// <summary>
/// Reads metadata table columns
/// </summary>
public interface IColumnReader {
/// <summary>
/// Reads a column
/// </summary>
/// <param name="table">The table to read from</param>
/// <param name="rid">Table row id</param>
/// <param name="column">The column to read</param>
/// <param name="value">Result</param>
/// <returns><c>true</c> if <paramref name="value"/> was updated, <c>false</c> if
/// the column should be read from the original table.</returns>
bool ReadColumn(MDTable table, uint rid, ColumnInfo column, out uint value);
}
/// <summary>
/// Reads table rows
/// </summary>
/// <typeparam name="TRow">Raw row</typeparam>
public interface IRowReader<TRow> where TRow : struct {
/// <summary>
/// Reads a table row or returns false if the row should be read from the original table
/// </summary>
/// <param name="rid">Row id</param>
/// <param name="row">The row</param>
/// <returns></returns>
bool TryReadRow(uint rid, out TRow row);
}
}

View File

@ -1,115 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System;
using dnlib.IO;
using dnlib.PE;
namespace dnlib.DotNet.MD {
/// <summary>
/// Represents the IMAGE_COR20_HEADER structure
/// </summary>
public sealed class ImageCor20Header : FileSection {
readonly uint cb;
readonly ushort majorRuntimeVersion;
readonly ushort minorRuntimeVersion;
readonly ImageDataDirectory metadata;
readonly ComImageFlags flags;
readonly uint entryPointToken_or_RVA;
readonly ImageDataDirectory resources;
readonly ImageDataDirectory strongNameSignature;
readonly ImageDataDirectory codeManagerTable;
readonly ImageDataDirectory vtableFixups;
readonly ImageDataDirectory exportAddressTableJumps;
readonly ImageDataDirectory managedNativeHeader;
/// <summary>
/// Returns <c>true</c> if it has a native header
/// </summary>
public bool HasNativeHeader => (flags & ComImageFlags.ILLibrary) != 0;
/// <summary>
/// Returns the IMAGE_COR20_HEADER.cb field
/// </summary>
public uint CB => cb;
/// <summary>
/// Returns the IMAGE_COR20_HEADER.MajorRuntimeVersion field
/// </summary>
public ushort MajorRuntimeVersion => majorRuntimeVersion;
/// <summary>
/// Returns the IMAGE_COR20_HEADER.MinorRuntimeVersion field
/// </summary>
public ushort MinorRuntimeVersion => minorRuntimeVersion;
/// <summary>
/// Returns the IMAGE_COR20_HEADER.Metadata field
/// </summary>
public ImageDataDirectory Metadata => metadata;
/// <summary>
/// Returns the IMAGE_COR20_HEADER.Flags field
/// </summary>
public ComImageFlags Flags => flags;
/// <summary>
/// Returns the IMAGE_COR20_HEADER.EntryPointToken/EntryPointTokenRVA field
/// </summary>
public uint EntryPointToken_or_RVA => entryPointToken_or_RVA;
/// <summary>
/// Returns the IMAGE_COR20_HEADER.Resources field
/// </summary>
public ImageDataDirectory Resources => resources;
/// <summary>
/// Returns the IMAGE_COR20_HEADER.StrongNameSignature field
/// </summary>
public ImageDataDirectory StrongNameSignature => strongNameSignature;
/// <summary>
/// Returns the IMAGE_COR20_HEADER.CodeManagerTable field
/// </summary>
public ImageDataDirectory CodeManagerTable => codeManagerTable;
/// <summary>
/// Returns the IMAGE_COR20_HEADER.VTableFixups field
/// </summary>
public ImageDataDirectory VTableFixups => vtableFixups;
/// <summary>
/// Returns the IMAGE_COR20_HEADER.ExportAddressTableJumps field
/// </summary>
public ImageDataDirectory ExportAddressTableJumps => exportAddressTableJumps;
/// <summary>
/// Returns the IMAGE_COR20_HEADER.ManagedNativeHeader field
/// </summary>
public ImageDataDirectory ManagedNativeHeader => managedNativeHeader;
/// <summary>
/// Constructor
/// </summary>
/// <param name="reader">PE file reader pointing to the start of this section</param>
/// <param name="verify">Verify section</param>
/// <exception cref="BadImageFormatException">Thrown if verification fails</exception>
public ImageCor20Header(ref DataReader reader, bool verify) {
SetStartOffset(ref reader);
cb = reader.ReadUInt32();
if (verify && cb < 0x48)
throw new BadImageFormatException("Invalid IMAGE_COR20_HEADER.cb value");
majorRuntimeVersion = reader.ReadUInt16();
minorRuntimeVersion = reader.ReadUInt16();
metadata = new ImageDataDirectory(ref reader, verify);
flags = (ComImageFlags)reader.ReadUInt32();
entryPointToken_or_RVA = reader.ReadUInt32();
resources = new ImageDataDirectory(ref reader, verify);
strongNameSignature = new ImageDataDirectory(ref reader, verify);
codeManagerTable = new ImageDataDirectory(ref reader, verify);
vtableFixups = new ImageDataDirectory(ref reader, verify);
exportAddressTableJumps = new ImageDataDirectory(ref reader, verify);
managedNativeHeader = new ImageDataDirectory(ref reader, verify);
SetEndoffset(ref reader);
}
}
}

View File

@ -1,83 +0,0 @@
// dnlib: See LICENSE.txt for more info
namespace dnlib.DotNet.MD {
/// <summary>
/// Version strings found in the meta data header
/// </summary>
public static class MDHeaderRuntimeVersion {
/// <summary>
/// MS CLR 1.0 version string (.NET Framework 1.0)
/// </summary>
public const string MS_CLR_10 = "v1.0.3705";
/// <summary>
/// MS CLR 1.0 version string (.NET Framework 1.0). This is an incorrect version that shouldn't be used.
/// </summary>
public const string MS_CLR_10_X86RETAIL = "v1.x86ret";
/// <summary>
/// MS CLR 1.0 version string (.NET Framework 1.0). This is an incorrect version that shouldn't be used.
/// </summary>
public const string MS_CLR_10_RETAIL = "retail";
/// <summary>
/// MS CLR 1.0 version string (.NET Framework 1.0). This is an incorrect version that shouldn't be used.
/// </summary>
public const string MS_CLR_10_COMPLUS = "COMPLUS";
/// <summary>
/// MS CLR 1.1 version string (.NET Framework 1.1)
/// </summary>
public const string MS_CLR_11 = "v1.1.4322";
/// <summary>
/// MS CLR 2.0 version string (.NET Framework 2.0-3.5)
/// </summary>
public const string MS_CLR_20 = "v2.0.50727";
/// <summary>
/// MS CLR 4.0 version string (.NET Framework 4.0-4.5)
/// </summary>
public const string MS_CLR_40 = "v4.0.30319";
/// <summary>
/// MS CLR 1.0 any version
/// </summary>
public const string MS_CLR_10_PREFIX = "v1.0";
/// <summary>
/// MS CLR 1.0 any version
/// </summary>
public const string MS_CLR_10_PREFIX_X86RETAIL = "v1.x86";
/// <summary>
/// MS CLR 1.1 any version
/// </summary>
public const string MS_CLR_11_PREFIX = "v1.1";
/// <summary>
/// MS CLR 2.0 any version
/// </summary>
public const string MS_CLR_20_PREFIX = "v2.0";
/// <summary>
/// MS CLR 4.0 any version
/// </summary>
public const string MS_CLR_40_PREFIX = "v4.0";
/// <summary>
/// ECMA 2002 version string
/// </summary>
public const string ECMA_2002 = "Standard CLI 2002";
/// <summary>
/// ECMA 2005 version string
/// </summary>
public const string ECMA_2005 = "Standard CLI 2005";
/// <summary>
/// Portable PDB v1.0
/// </summary>
public const string PORTABLE_PDB_V1_0 = "PDB v1.0";
}
}

View File

@ -1,26 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System;
namespace dnlib.DotNet.MD {
/// <summary>
/// MDStream flags
/// </summary>
[Flags]
public enum MDStreamFlags : byte {
/// <summary>#Strings stream is big and requires 4 byte offsets</summary>
BigStrings = 1,
/// <summary>#GUID stream is big and requires 4 byte offsets</summary>
BigGUID = 2,
/// <summary>#Blob stream is big and requires 4 byte offsets</summary>
BigBlob = 4,
/// <summary/>
Padding = 8,
/// <summary/>
DeltaOnly = 0x20,
/// <summary>Extra data follows the row counts</summary>
ExtraData = 0x40,
/// <summary>Set if certain tables can contain deleted rows. The name column (if present) is set to "_Deleted"</summary>
HasDelete = 0x80,
}
}

View File

@ -1,122 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System;
using System.Collections.Generic;
using System.Diagnostics;
using dnlib.IO;
namespace dnlib.DotNet.MD {
/// <summary>
/// A MD table (eg. Method table)
/// </summary>
[DebuggerDisplay("DL:{dataReader.Length} R:{numRows} RS:{tableInfo.RowSize} C:{Count} {tableInfo.Name}")]
public sealed class MDTable : IDisposable, IFileSection {
readonly Table table;
uint numRows;
TableInfo tableInfo;
DataReader dataReader;
// Fix for VS2015 expression evaluator: "The debugger is unable to evaluate this expression"
int Count => tableInfo.Columns.Length;
/// <inheritdoc/>
public FileOffset StartOffset => (FileOffset)dataReader.StartOffset;
/// <inheritdoc/>
public FileOffset EndOffset => (FileOffset)dataReader.EndOffset;
/// <summary>
/// Gets the table
/// </summary>
public Table Table => table;
/// <summary>
/// Gets the name of this table
/// </summary>
public string Name => tableInfo.Name;
/// <summary>
/// Returns total number of rows
/// </summary>
public uint Rows => numRows;
/// <summary>
/// Gets the total size in bytes of one row in this table
/// </summary>
public uint RowSize => (uint)tableInfo.RowSize;
/// <summary>
/// Returns all the columns
/// </summary>
public IList<ColumnInfo> Columns => tableInfo.Columns;
/// <summary>
/// Returns <c>true</c> if there are no valid rows
/// </summary>
public bool IsEmpty => numRows == 0;
/// <summary>
/// Returns info about this table
/// </summary>
public TableInfo TableInfo => tableInfo;
internal DataReader DataReader {
get => dataReader;
set => dataReader = value;
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="table">The table</param>
/// <param name="numRows">Number of rows in this table</param>
/// <param name="tableInfo">Info about this table</param>
internal MDTable(Table table, uint numRows, TableInfo tableInfo) {
this.table = table;
this.numRows = numRows;
this.tableInfo = tableInfo;
var columns = tableInfo.Columns;
int length = columns.Length;
if (length > 0) Column0 = columns[0];
if (length > 1) Column1 = columns[1];
if (length > 2) Column2 = columns[2];
if (length > 3) Column3 = columns[3];
if (length > 4) Column4 = columns[4];
if (length > 5) Column5 = columns[5];
if (length > 6) Column6 = columns[6];
if (length > 7) Column7 = columns[7];
if (length > 8) Column8 = columns[8];
}
// So we don't have to call IList<T> indexer
internal readonly ColumnInfo Column0;
internal readonly ColumnInfo Column1;
internal readonly ColumnInfo Column2;
internal readonly ColumnInfo Column3;
internal readonly ColumnInfo Column4;
internal readonly ColumnInfo Column5;
internal readonly ColumnInfo Column6;
internal readonly ColumnInfo Column7;
internal readonly ColumnInfo Column8;
/// <summary>
/// Checks whether the row <paramref name="rid"/> exists
/// </summary>
/// <param name="rid">Row ID</param>
public bool IsValidRID(uint rid) => rid != 0 && rid <= numRows;
/// <summary>
/// Checks whether the row <paramref name="rid"/> does not exist
/// </summary>
/// <param name="rid">Row ID</param>
public bool IsInvalidRID(uint rid) => rid == 0 || rid > numRows;
/// <inheritdoc/>
public void Dispose() {
numRows = 0;
tableInfo = null;
dataReader = default;
}
}
}

View File

@ -1,371 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System;
using System.Collections.Generic;
using dnlib.PE;
namespace dnlib.DotNet.MD {
/// <summary>
/// Reads .NET metadata
/// </summary>
public abstract class Metadata : IDisposable {
/// <summary>
/// <c>true</c> if the compressed (normal) metadata is used, <c>false</c> if the non-compressed
/// (Edit N' Continue) metadata is used. This can be <c>false</c> even if the table stream
/// is <c>#~</c> but that's very uncommon.
/// </summary>
public abstract bool IsCompressed { get; }
/// <summary>
/// <c>true</c> if this is standalone Portable PDB metadata
/// </summary>
public abstract bool IsStandalonePortablePdb { get; }
/// <summary>
/// Gets the .NET header
/// </summary>
public abstract ImageCor20Header ImageCor20Header { get; }
/// <summary>
/// Gets the version found in the metadata header. The major version number is in the high 16 bits
/// and the lower version number is in the low 16 bits.
/// </summary>
public abstract uint Version { get; }
/// <summary>
/// Gets the version string found in the metadata header
/// </summary>
public abstract string VersionString { get; }
/// <summary>
/// Gets the <see cref="IPEImage"/>
/// </summary>
public abstract IPEImage PEImage { get; }
/// <summary>
/// Gets the metadata header
/// </summary>
public abstract MetadataHeader MetadataHeader { get; }
/// <summary>
/// Returns the #Strings stream or a default empty one if it's not present
/// </summary>
public abstract StringsStream StringsStream { get; }
/// <summary>
/// Returns the #US stream or a default empty one if it's not present
/// </summary>
public abstract USStream USStream { get; }
/// <summary>
/// Returns the #Blob stream or a default empty one if it's not present
/// </summary>
public abstract BlobStream BlobStream { get; }
/// <summary>
/// Returns the #GUID stream or a default empty one if it's not present
/// </summary>
public abstract GuidStream GuidStream { get; }
/// <summary>
/// Returns the #~ or #- tables stream
/// </summary>
public abstract TablesStream TablesStream { get; }
/// <summary>
/// Returns the #Pdb stream or null if it's not a standalone portable PDB file
/// </summary>
public abstract PdbStream PdbStream { get; }
/// <summary>
/// Gets all streams
/// </summary>
public abstract IList<DotNetStream> AllStreams { get; }
/// <summary>
/// Gets a list of all the valid <c>TypeDef</c> rids. It's usually every rid in the
/// <c>TypeDef</c> table, but could be less if a type has been deleted.
/// </summary>
public abstract RidList GetTypeDefRidList();
/// <summary>
/// Gets a list of all the valid <c>ExportedType</c> rids. It's usually every rid in the
/// <c>ExportedType</c> table, but could be less if a type has been deleted.
/// </summary>
public abstract RidList GetExportedTypeRidList();
/// <summary>
/// Gets the <c>Field</c> rid list
/// </summary>
/// <param name="typeDefRid"><c>TypeDef</c> rid</param>
/// <returns>A new <see cref="RidList"/> instance</returns>
public abstract RidList GetFieldRidList(uint typeDefRid);
/// <summary>
/// Gets the <c>Method</c> rid list
/// </summary>
/// <param name="typeDefRid"><c>TypeDef</c> rid</param>
/// <returns>A new <see cref="RidList"/> instance</returns>
public abstract RidList GetMethodRidList(uint typeDefRid);
/// <summary>
/// Gets the <c>Param</c> rid list
/// </summary>
/// <param name="methodRid"><c>Method</c> rid</param>
/// <returns>A new <see cref="RidList"/> instance</returns>
public abstract RidList GetParamRidList(uint methodRid);
/// <summary>
/// Gets the <c>Event</c> rid list
/// </summary>
/// <param name="eventMapRid"><c>EventMap</c> rid</param>
/// <returns>A new <see cref="RidList"/> instance</returns>
public abstract RidList GetEventRidList(uint eventMapRid);
/// <summary>
/// Gets the <c>Property</c> rid list
/// </summary>
/// <param name="propertyMapRid"><c>PropertyMap</c> rid</param>
/// <returns>A new <see cref="RidList"/> instance</returns>
public abstract RidList GetPropertyRidList(uint propertyMapRid);
/// <summary>
/// Finds all <c>InterfaceImpl</c> rids owned by <paramref name="typeDefRid"/>
/// </summary>
/// <param name="typeDefRid">Owner <c>TypeDef</c> rid</param>
/// <returns>A <see cref="RidList"/> instance containing the valid <c>InterfaceImpl</c> rids</returns>
public abstract RidList GetInterfaceImplRidList(uint typeDefRid);
/// <summary>
/// Finds all <c>GenericParam</c> rids owned by <paramref name="rid"/> in table <paramref name="table"/>
/// </summary>
/// <param name="table">A <c>TypeOrMethodDef</c> table</param>
/// <param name="rid">Owner rid</param>
/// <returns>A <see cref="RidList"/> instance containing the valid <c>GenericParam</c> rids</returns>
public abstract RidList GetGenericParamRidList(Table table, uint rid);
/// <summary>
/// Finds all <c>GenericParamConstraint</c> rids owned by <paramref name="genericParamRid"/>
/// </summary>
/// <param name="genericParamRid">Owner <c>GenericParam</c> rid</param>
/// <returns>A <see cref="RidList"/> instance containing the valid <c>GenericParamConstraint</c> rids</returns>
public abstract RidList GetGenericParamConstraintRidList(uint genericParamRid);
/// <summary>
/// Finds all <c>CustomAttribute</c> rids owned by <paramref name="rid"/> in table <paramref name="table"/>
/// </summary>
/// <param name="table">A <c>HasCustomAttribute</c> table</param>
/// <param name="rid">Owner rid</param>
/// <returns>A <see cref="RidList"/> instance containing the valid <c>CustomAttribute</c> rids</returns>
public abstract RidList GetCustomAttributeRidList(Table table, uint rid);
/// <summary>
/// Finds all <c>DeclSecurity</c> rids owned by <paramref name="rid"/> in table <paramref name="table"/>
/// </summary>
/// <param name="table">A <c>HasDeclSecurity</c> table</param>
/// <param name="rid">Owner rid</param>
/// <returns>A <see cref="RidList"/> instance containing the valid <c>DeclSecurity</c> rids</returns>
public abstract RidList GetDeclSecurityRidList(Table table, uint rid);
/// <summary>
/// Finds all <c>MethodSemantics</c> rids owned by <paramref name="rid"/> in table <paramref name="table"/>
/// </summary>
/// <param name="table">A <c>HasSemantic</c> table</param>
/// <param name="rid">Owner rid</param>
/// <returns>A <see cref="RidList"/> instance containing the valid <c>MethodSemantics</c> rids</returns>
public abstract RidList GetMethodSemanticsRidList(Table table, uint rid);
/// <summary>
/// Finds all <c>MethodImpl</c> rids owned by <paramref name="typeDefRid"/>
/// </summary>
/// <param name="typeDefRid">Owner <c>TypeDef</c> rid</param>
/// <returns>A <see cref="RidList"/> instance containing the valid <c>MethodImpl</c> rids</returns>
public abstract RidList GetMethodImplRidList(uint typeDefRid);
/// <summary>
/// Finds a <c>ClassLayout</c> rid
/// </summary>
/// <param name="typeDefRid">Owner <c>TypeDef</c> rid</param>
/// <returns>The <c>ClassLayout</c> rid or 0 if <paramref name="typeDefRid"/> is invalid
/// or if it has no row in the <c>ClassLayout</c> table.</returns>
public abstract uint GetClassLayoutRid(uint typeDefRid);
/// <summary>
/// Finds a <c>FieldLayout</c> rid
/// </summary>
/// <param name="fieldRid">Owner <c>Field</c> rid</param>
/// <returns>The <c>FieldLayout</c> rid or 0 if <paramref name="fieldRid"/> is invalid
/// or if it has no row in the <c>FieldLayout</c> table.</returns>
public abstract uint GetFieldLayoutRid(uint fieldRid);
/// <summary>
/// Finds a <c>FieldMarshal</c> rid
/// </summary>
/// <param name="table">A <c>HasFieldMarshal</c> table</param>
/// <param name="rid">Owner rid</param>
/// <returns>The <c>FieldMarshal</c> rid or 0 if <paramref name="rid"/> is invalid
/// or if it has no row in the <c>FieldMarshal</c> table.</returns>
public abstract uint GetFieldMarshalRid(Table table, uint rid);
/// <summary>
/// Finds a <c>FieldRVA</c> rid
/// </summary>
/// <param name="fieldRid">Owner <c>Field</c> rid</param>
/// <returns>The <c>FieldRVA</c> rid or 0 if <paramref name="fieldRid"/> is invalid
/// or if it has no row in the <c>FieldRVA</c> table.</returns>
public abstract uint GetFieldRVARid(uint fieldRid);
/// <summary>
/// Finds an <c>ImplMap</c> rid
/// </summary>
/// <param name="table">A <c>MemberForwarded</c> table</param>
/// <param name="rid">Owner rid</param>
/// <returns>The <c>ImplMap</c> rid or 0 if <paramref name="rid"/> is invalid
/// or if it has no row in the <c>ImplMap</c> table.</returns>
public abstract uint GetImplMapRid(Table table, uint rid);
/// <summary>
/// Finds a <c>NestedClass</c> rid
/// </summary>
/// <param name="typeDefRid">Owner <c>TypeDef</c> rid</param>
/// <returns>The <c>NestedClass</c> rid or 0 if <paramref name="typeDefRid"/> is invalid
/// or if it has no row in the <c>NestedClass</c> table.</returns>
public abstract uint GetNestedClassRid(uint typeDefRid);
/// <summary>
/// Finds an <c>EventMap</c> rid
/// </summary>
/// <param name="typeDefRid">Owner <c>TypeDef</c> rid</param>
/// <returns>The <c>EventMap</c> rid or 0 if <paramref name="typeDefRid"/> is invalid
/// or if it has no row in the <c>EventMap</c> table.</returns>
public abstract uint GetEventMapRid(uint typeDefRid);
/// <summary>
/// Finds a <c>PropertyMap</c> rid
/// </summary>
/// <param name="typeDefRid">Owner <c>TypeDef</c> rid</param>
/// <returns>The <c>PropertyMap</c> rid or 0 if <paramref name="typeDefRid"/> is invalid
/// or if it has no row in the <c>PropertyMap</c> table.</returns>
public abstract uint GetPropertyMapRid(uint typeDefRid);
/// <summary>
/// Finds a <c>Constant</c> rid
/// </summary>
/// <param name="table">A <c>HasConstant</c> table</param>
/// <param name="rid">Owner rid</param>
/// <returns>The <c>Constant</c> rid or 0 if <paramref name="rid"/> is invalid
/// or if it has no row in the <c>Constant</c> table.</returns>
public abstract uint GetConstantRid(Table table, uint rid);
/// <summary>
/// Returns the owner <c>TypeDef</c> rid
/// </summary>
/// <param name="fieldRid">A <c>Field</c> rid</param>
/// <returns>The owner <c>TypeDef</c> rid or 0 if <paramref name="fieldRid"/> is invalid
/// or if it has no owner.</returns>
public abstract uint GetOwnerTypeOfField(uint fieldRid);
/// <summary>
/// Returns the owner <c>TypeDef</c> rid
/// </summary>
/// <param name="methodRid">A <c>Method</c> rid</param>
/// <returns>The owner <c>TypeDef</c> rid or 0 if <paramref name="methodRid"/> is invalid
/// or if it has no owner.</returns>
public abstract uint GetOwnerTypeOfMethod(uint methodRid);
/// <summary>
/// Returns the owner <c>TypeDef</c> rid
/// </summary>
/// <param name="eventRid">A <c>Event</c> rid</param>
/// <returns>The owner <c>TypeDef</c> rid or 0 if <paramref name="eventRid"/> is invalid
/// or if it has no owner.</returns>
public abstract uint GetOwnerTypeOfEvent(uint eventRid);
/// <summary>
/// Returns the owner <c>TypeDef</c> rid
/// </summary>
/// <param name="propertyRid">A <c>Property</c> rid</param>
/// <returns>The owner <c>TypeDef</c> rid or 0 if <paramref name="propertyRid"/> is invalid
/// or if it has no owner.</returns>
public abstract uint GetOwnerTypeOfProperty(uint propertyRid);
/// <summary>
/// Returns the owner <c>TypeOrMethodDef</c> rid
/// </summary>
/// <param name="gpRid">A <c>GenericParam</c> rid</param>
/// <returns>The owner <c>TypeOrMethodDef</c> rid or 0 if <paramref name="gpRid"/> is
/// invalid or if it has no owner.</returns>
public abstract uint GetOwnerOfGenericParam(uint gpRid);
/// <summary>
/// Returns the owner <c>GenericParam</c> rid
/// </summary>
/// <param name="gpcRid">A <c>GenericParamConstraint</c> rid</param>
/// <returns>The owner <c>GenericParam</c> rid or 0 if <paramref name="gpcRid"/> is
/// invalid or if it has no owner.</returns>
public abstract uint GetOwnerOfGenericParamConstraint(uint gpcRid);
/// <summary>
/// Returns the owner <c>Method</c> rid
/// </summary>
/// <param name="paramRid">A <c>Param</c> rid</param>
/// <returns>The owner <c>Method</c> rid or 0 if <paramref name="paramRid"/> is invalid
/// or if it has no owner.</returns>
public abstract uint GetOwnerOfParam(uint paramRid);
/// <summary>
/// Gets a list of all nested classes owned by <paramref name="typeDefRid"/>
/// </summary>
/// <param name="typeDefRid">A <c>TypeDef</c> rid</param>
/// <returns>A new <see cref="RidList"/> instance</returns>
public abstract RidList GetNestedClassRidList(uint typeDefRid);
/// <summary>
/// Gets a list of all non-nested classes. A type is a non-nested type if
/// <see cref="GetNestedClassRidList(uint)"/> returns an empty list.
/// </summary>
/// <returns>A new <see cref="RidList"/> instance</returns>
public abstract RidList GetNonNestedClassRidList();
/// <summary>
/// Finds all <c>LocalScope</c> rids owned by <paramref name="methodRid"/>
/// </summary>
/// <param name="methodRid">Owner <c>Method</c> rid</param>
/// <returns>A <see cref="RidList"/> instance containing the valid <c>LocalScope</c> rids</returns>
public abstract RidList GetLocalScopeRidList(uint methodRid);
/// <summary>
/// Finds all <c>LocalVariable</c> rids owned by <paramref name="localScopeRid"/>
/// </summary>
/// <param name="localScopeRid">Owner <c>LocalScope</c> rid</param>
/// <returns>A <see cref="RidList"/> instance containing the valid <c>LocalVariable</c> rids</returns>
public abstract RidList GetLocalVariableRidList(uint localScopeRid);
/// <summary>
/// Finds all <c>LocalConstant</c> rids owned by <paramref name="localScopeRid"/>
/// </summary>
/// <param name="localScopeRid">Owner <c>LocalScope</c> rid</param>
/// <returns>A <see cref="RidList"/> instance containing the valid <c>LocalConstant</c> rids</returns>
public abstract RidList GetLocalConstantRidList(uint localScopeRid);
/// <summary>
/// Gets the <c>StateMachineMethod</c> rid or 0 if it's not a state machine method
/// </summary>
/// <param name="methodRid">Owner <c>Method</c> rid</param>
/// <returns></returns>
public abstract uint GetStateMachineMethodRid(uint methodRid);
/// <summary>
/// Finds all <c>CustomDebugInformation</c> rids owned by <paramref name="rid"/> in table <paramref name="table"/>
/// </summary>
/// <param name="table">A <c>HasCustomDebugInformation</c> table</param>
/// <param name="rid">Owner rid</param>
/// <returns>A <see cref="RidList"/> instance containing the valid <c>CustomDebugInformation</c> rids</returns>
public abstract RidList GetCustomDebugInformationRidList(Table table, uint rid);
/// <summary>
/// Disposes of this instance
/// </summary>
public abstract void Dispose();
}
}

View File

@ -1,763 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Threading;
using dnlib.IO;
using dnlib.PE;
namespace dnlib.DotNet.MD {
/// <summary>
/// Common base class for #~ and #- metadata classes
/// </summary>
abstract class MetadataBase : Metadata {
/// <summary>
/// The PE image
/// </summary>
protected IPEImage peImage;
/// <summary>
/// The .NET header
/// </summary>
protected ImageCor20Header cor20Header;
/// <summary>
/// The MD header
/// </summary>
protected MetadataHeader mdHeader;
/// <summary>
/// The #Strings stream
/// </summary>
protected StringsStream stringsStream;
/// <summary>
/// The #US stream
/// </summary>
protected USStream usStream;
/// <summary>
/// The #Blob stream
/// </summary>
protected BlobStream blobStream;
/// <summary>
/// The #GUID stream
/// </summary>
protected GuidStream guidStream;
/// <summary>
/// The #~ or #- stream
/// </summary>
protected TablesStream tablesStream;
/// <summary>
/// The #Pdb stream
/// </summary>
protected PdbStream pdbStream;
/// <summary>
/// All the streams that are present in the PE image
/// </summary>
protected IList<DotNetStream> allStreams;
public override bool IsStandalonePortablePdb => isStandalonePortablePdb;
/// <summary><c>true</c> if this is standalone Portable PDB metadata</summary>
protected readonly bool isStandalonePortablePdb;
uint[] fieldRidToTypeDefRid;
uint[] methodRidToTypeDefRid;
uint[] eventRidToTypeDefRid;
uint[] propertyRidToTypeDefRid;
uint[] gpRidToOwnerRid;
uint[] gpcRidToOwnerRid;
uint[] paramRidToOwnerRid;
Dictionary<uint, List<uint>> typeDefRidToNestedClasses;
StrongBox<RidList> nonNestedTypes;
DataReaderFactory mdReaderFactoryToDisposeLater;
/// <summary>
/// Sorts a table by key column
/// </summary>
protected sealed class SortedTable {
RowInfo[] rows;
/// <summary>
/// Remembers <c>rid</c> and key
/// </summary>
[DebuggerDisplay("{rid} {key}")]
readonly struct RowInfo : IComparable<RowInfo> {
public readonly uint rid;
public readonly uint key;
/// <summary>
/// Constructor
/// </summary>
/// <param name="rid">Row ID</param>
/// <param name="key">Key</param>
public RowInfo(uint rid, uint key) {
this.rid = rid;
this.key = key;
}
public int CompareTo(RowInfo other) {
if (key < other.key)
return -1;
if (key > other.key)
return 1;
return rid.CompareTo(other.rid);
}
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="mdTable">The MD table</param>
/// <param name="keyColIndex">Index of key column</param>
public SortedTable(MDTable mdTable, int keyColIndex) {
InitializeKeys(mdTable, keyColIndex);
Array.Sort(rows);
}
void InitializeKeys(MDTable mdTable, int keyColIndex) {
var keyColumn = mdTable.TableInfo.Columns[keyColIndex];
Debug.Assert(keyColumn.Size == 2 || keyColumn.Size == 4);
rows = new RowInfo[mdTable.Rows + 1];
if (mdTable.Rows == 0)
return;
var reader = mdTable.DataReader;
reader.Position = (uint)keyColumn.Offset;
uint increment = (uint)(mdTable.TableInfo.RowSize - keyColumn.Size);
for (uint i = 1; i <= mdTable.Rows; i++) {
rows[i] = new RowInfo(i, keyColumn.Unsafe_Read24(ref reader));
if (i < mdTable.Rows)
reader.Position += increment;
}
}
/// <summary>
/// Binary searches for a row with a certain key
/// </summary>
/// <param name="key">The key</param>
/// <returns>The row or 0 if not found</returns>
int BinarySearch(uint key) {
int lo = 1, hi = rows.Length - 1;
while (lo <= hi && hi != -1) {
int curr = (lo + hi) / 2;
uint key2 = rows[curr].key;
if (key == key2)
return curr;
if (key2 > key)
hi = curr - 1;
else
lo = curr + 1;
}
return 0;
}
/// <summary>
/// Find all rids that contain <paramref name="key"/>
/// </summary>
/// <param name="key">The key</param>
/// <returns>A new <see cref="RidList"/> instance</returns>
public RidList FindAllRows(uint key) {
int startIndex = BinarySearch(key);
if (startIndex == 0)
return RidList.Empty;
int endIndex = startIndex + 1;
for (; startIndex > 1; startIndex--) {
if (key != rows[startIndex - 1].key)
break;
}
for (; endIndex < rows.Length; endIndex++) {
if (key != rows[endIndex].key)
break;
}
var list = new List<uint>(endIndex - startIndex);
for (int i = startIndex; i < endIndex; i++)
list.Add(rows[i].rid);
return RidList.Create(list);
}
}
SortedTable eventMapSortedTable;
SortedTable propertyMapSortedTable;
public override ImageCor20Header ImageCor20Header => cor20Header;
public override uint Version => ((uint)mdHeader.MajorVersion << 16) | mdHeader.MinorVersion;
public override string VersionString => mdHeader.VersionString;
public override IPEImage PEImage => peImage;
public override MetadataHeader MetadataHeader => mdHeader;
public override StringsStream StringsStream => stringsStream;
public override USStream USStream => usStream;
public override BlobStream BlobStream => blobStream;
public override GuidStream GuidStream => guidStream;
public override TablesStream TablesStream => tablesStream;
public override PdbStream PdbStream => pdbStream;
public override IList<DotNetStream> AllStreams => allStreams;
/// <summary>
/// Constructor
/// </summary>
/// <param name="peImage">The PE image</param>
/// <param name="cor20Header">The .NET header</param>
/// <param name="mdHeader">The MD header</param>
protected MetadataBase(IPEImage peImage, ImageCor20Header cor20Header, MetadataHeader mdHeader) {
try {
allStreams = new List<DotNetStream>();
this.peImage = peImage;
this.cor20Header = cor20Header;
this.mdHeader = mdHeader;
isStandalonePortablePdb = false;
}
catch {
if (peImage is not null)
peImage.Dispose();
throw;
}
}
internal MetadataBase(MetadataHeader mdHeader, bool isStandalonePortablePdb) {
allStreams = new List<DotNetStream>();
peImage = null;
cor20Header = null;
this.mdHeader = mdHeader;
this.isStandalonePortablePdb = isStandalonePortablePdb;
}
/// <summary>
/// Initializes the metadata, tables, streams
/// </summary>
public void Initialize(DataReaderFactory mdReaderFactory) {
mdReaderFactoryToDisposeLater = mdReaderFactory;
uint metadataBaseOffset;
if (peImage is not null) {
Debug.Assert(mdReaderFactory is null);
Debug.Assert(cor20Header is not null);
metadataBaseOffset = (uint)peImage.ToFileOffset(cor20Header.Metadata.VirtualAddress);
mdReaderFactory = peImage.DataReaderFactory;
}
else {
Debug.Assert(mdReaderFactory is not null);
metadataBaseOffset = 0;
}
InitializeInternal(mdReaderFactory, metadataBaseOffset);
if (tablesStream is null)
throw new BadImageFormatException("Missing MD stream");
if (isStandalonePortablePdb && pdbStream is null)
throw new BadImageFormatException("Missing #Pdb stream");
InitializeNonExistentHeaps();
}
/// <summary>
/// Creates empty heap objects if they're not present in the metadata
/// </summary>
protected void InitializeNonExistentHeaps() {
if (stringsStream is null)
stringsStream = new StringsStream();
if (usStream is null)
usStream = new USStream();
if (blobStream is null)
blobStream = new BlobStream();
if (guidStream is null)
guidStream = new GuidStream();
}
/// <summary>
/// Called by <see cref="Initialize(DataReaderFactory)"/>
/// </summary>
protected abstract void InitializeInternal(DataReaderFactory mdReaderFactory, uint metadataBaseOffset);
public override RidList GetTypeDefRidList() => RidList.Create(1, tablesStream.TypeDefTable.Rows);
public override RidList GetExportedTypeRidList() => RidList.Create(1, tablesStream.ExportedTypeTable.Rows);
/// <summary>
/// Binary searches the table for a <c>rid</c> whose key column at index
/// <paramref name="keyColIndex"/> is equal to <paramref name="key"/>.
/// </summary>
/// <param name="tableSource">Table to search</param>
/// <param name="keyColIndex">Key column index</param>
/// <param name="key">Key</param>
/// <returns>The <c>rid</c> of the found row, or 0 if none found</returns>
protected abstract uint BinarySearch(MDTable tableSource, int keyColIndex, uint key);
/// <summary>
/// Finds all rows owned by <paramref name="key"/> in table <paramref name="tableSource"/>
/// whose index is <paramref name="keyColIndex"/>
/// </summary>
/// <param name="tableSource">Table to search</param>
/// <param name="keyColIndex">Key column index</param>
/// <param name="key">Key</param>
/// <returns>A <see cref="RidList"/> instance</returns>
protected RidList FindAllRows(MDTable tableSource, int keyColIndex, uint key) {
uint startRid = BinarySearch(tableSource, keyColIndex, key);
if (tableSource.IsInvalidRID(startRid))
return RidList.Empty;
uint endRid = startRid + 1;
var column = tableSource.TableInfo.Columns[keyColIndex];
for (; startRid > 1; startRid--) {
if (!tablesStream.TryReadColumn24(tableSource, startRid - 1, column, out uint key2))
break; // Should never happen since startRid is valid
if (key != key2)
break;
}
for (; endRid <= tableSource.Rows; endRid++) {
if (!tablesStream.TryReadColumn24(tableSource, endRid, column, out uint key2))
break; // Should never happen since endRid is valid
if (key != key2)
break;
}
return RidList.Create(startRid, endRid - startRid);
}
/// <summary>
/// Finds all rows owned by <paramref name="key"/> in table <paramref name="tableSource"/>
/// whose index is <paramref name="keyColIndex"/>. Should be called if <paramref name="tableSource"/>
/// could be unsorted.
/// </summary>
/// <param name="tableSource">Table to search</param>
/// <param name="keyColIndex">Key column index</param>
/// <param name="key">Key</param>
/// <returns>A <see cref="RidList"/> instance</returns>
protected virtual RidList FindAllRowsUnsorted(MDTable tableSource, int keyColIndex, uint key) => FindAllRows(tableSource, keyColIndex, key);
public override RidList GetInterfaceImplRidList(uint typeDefRid) => FindAllRowsUnsorted(tablesStream.InterfaceImplTable, 0, typeDefRid);
public override RidList GetGenericParamRidList(Table table, uint rid) {
if (!CodedToken.TypeOrMethodDef.Encode(new MDToken(table, rid), out uint codedToken))
return RidList.Empty;
return FindAllRowsUnsorted(tablesStream.GenericParamTable, 2, codedToken);
}
public override RidList GetGenericParamConstraintRidList(uint genericParamRid) =>
FindAllRowsUnsorted(tablesStream.GenericParamConstraintTable, 0, genericParamRid);
public override RidList GetCustomAttributeRidList(Table table, uint rid) {
if (!CodedToken.HasCustomAttribute.Encode(new MDToken(table, rid), out uint codedToken))
return RidList.Empty;
return FindAllRowsUnsorted(tablesStream.CustomAttributeTable, 0, codedToken);
}
public override RidList GetDeclSecurityRidList(Table table, uint rid) {
if (!CodedToken.HasDeclSecurity.Encode(new MDToken(table, rid), out uint codedToken))
return RidList.Empty;
return FindAllRowsUnsorted(tablesStream.DeclSecurityTable, 1, codedToken);
}
public override RidList GetMethodSemanticsRidList(Table table, uint rid) {
if (!CodedToken.HasSemantic.Encode(new MDToken(table, rid), out uint codedToken))
return RidList.Empty;
return FindAllRowsUnsorted(tablesStream.MethodSemanticsTable, 2, codedToken);
}
public override RidList GetMethodImplRidList(uint typeDefRid) => FindAllRowsUnsorted(tablesStream.MethodImplTable, 0, typeDefRid);
public override uint GetClassLayoutRid(uint typeDefRid) {
var list = FindAllRowsUnsorted(tablesStream.ClassLayoutTable, 2, typeDefRid);
return list.Count == 0 ? 0 : list[0];
}
public override uint GetFieldLayoutRid(uint fieldRid) {
var list = FindAllRowsUnsorted(tablesStream.FieldLayoutTable, 1, fieldRid);
return list.Count == 0 ? 0 : list[0];
}
public override uint GetFieldMarshalRid(Table table, uint rid) {
if (!CodedToken.HasFieldMarshal.Encode(new MDToken(table, rid), out uint codedToken))
return 0;
var list = FindAllRowsUnsorted(tablesStream.FieldMarshalTable, 0, codedToken);
return list.Count == 0 ? 0 : list[0];
}
public override uint GetFieldRVARid(uint fieldRid) {
var list = FindAllRowsUnsorted(tablesStream.FieldRVATable, 1, fieldRid);
return list.Count == 0 ? 0 : list[0];
}
public override uint GetImplMapRid(Table table, uint rid) {
if (!CodedToken.MemberForwarded.Encode(new MDToken(table, rid), out uint codedToken))
return 0;
var list = FindAllRowsUnsorted(tablesStream.ImplMapTable, 1, codedToken);
return list.Count == 0 ? 0 : list[0];
}
public override uint GetNestedClassRid(uint typeDefRid) {
var list = FindAllRowsUnsorted(tablesStream.NestedClassTable, 0, typeDefRid);
return list.Count == 0 ? 0 : list[0];
}
public override uint GetEventMapRid(uint typeDefRid) {
// The EventMap and PropertyMap tables can only be trusted to be sorted if it's
// an NGen image and it's the normal #- stream. The IsSorted bit must not be used
// to check whether the tables are sorted. See coreclr: md/inc/metamodel.h / IsVerified()
if (eventMapSortedTable is null)
Interlocked.CompareExchange(ref eventMapSortedTable, new SortedTable(tablesStream.EventMapTable, 0), null);
var list = eventMapSortedTable.FindAllRows(typeDefRid);
return list.Count == 0 ? 0 : list[0];
}
public override uint GetPropertyMapRid(uint typeDefRid) {
// Always unsorted, see comment in GetEventMapRid() above
if (propertyMapSortedTable is null)
Interlocked.CompareExchange(ref propertyMapSortedTable, new SortedTable(tablesStream.PropertyMapTable, 0), null);
var list = propertyMapSortedTable.FindAllRows(typeDefRid);
return list.Count == 0 ? 0 : list[0];
}
public override uint GetConstantRid(Table table, uint rid) {
if (!CodedToken.HasConstant.Encode(new MDToken(table, rid), out uint codedToken))
return 0;
var list = FindAllRowsUnsorted(tablesStream.ConstantTable, 2, codedToken);
return list.Count == 0 ? 0 : list[0];
}
public override uint GetOwnerTypeOfField(uint fieldRid) {
if (fieldRidToTypeDefRid is null)
InitializeInverseFieldOwnerRidList();
uint index = fieldRid - 1;
if (index >= fieldRidToTypeDefRid.LongLength)
return 0;
return fieldRidToTypeDefRid[index];
}
void InitializeInverseFieldOwnerRidList() {
if (fieldRidToTypeDefRid is not null)
return;
var newFieldRidToTypeDefRid = new uint[tablesStream.FieldTable.Rows];
var ownerList = GetTypeDefRidList();
for (int i = 0; i < ownerList.Count; i++) {
var ownerRid = ownerList[i];
var fieldList = GetFieldRidList(ownerRid);
for (int j = 0; j < fieldList.Count; j++) {
uint ridIndex = fieldList[j] - 1;
if (newFieldRidToTypeDefRid[ridIndex] != 0)
continue;
newFieldRidToTypeDefRid[ridIndex] = ownerRid;
}
}
Interlocked.CompareExchange(ref fieldRidToTypeDefRid, newFieldRidToTypeDefRid, null);
}
public override uint GetOwnerTypeOfMethod(uint methodRid) {
if (methodRidToTypeDefRid is null)
InitializeInverseMethodOwnerRidList();
uint index = methodRid - 1;
if (index >= methodRidToTypeDefRid.LongLength)
return 0;
return methodRidToTypeDefRid[index];
}
void InitializeInverseMethodOwnerRidList() {
if (methodRidToTypeDefRid is not null)
return;
var newMethodRidToTypeDefRid = new uint[tablesStream.MethodTable.Rows];
var ownerList = GetTypeDefRidList();
for (int i = 0; i < ownerList.Count; i++) {
var ownerRid = ownerList[i];
var methodList = GetMethodRidList(ownerRid);
for (int j = 0; j < methodList.Count; j++) {
uint ridIndex = methodList[j] - 1;
if (newMethodRidToTypeDefRid[ridIndex] != 0)
continue;
newMethodRidToTypeDefRid[ridIndex] = ownerRid;
}
}
Interlocked.CompareExchange(ref methodRidToTypeDefRid, newMethodRidToTypeDefRid, null);
}
public override uint GetOwnerTypeOfEvent(uint eventRid) {
if (eventRidToTypeDefRid is null)
InitializeInverseEventOwnerRidList();
uint index = eventRid - 1;
if (index >= eventRidToTypeDefRid.LongLength)
return 0;
return eventRidToTypeDefRid[index];
}
void InitializeInverseEventOwnerRidList() {
if (eventRidToTypeDefRid is not null)
return;
var newEventRidToTypeDefRid = new uint[tablesStream.EventTable.Rows];
var ownerList = GetTypeDefRidList();
for (int i = 0; i < ownerList.Count; i++) {
var ownerRid = ownerList[i];
var eventList = GetEventRidList(GetEventMapRid(ownerRid));
for (int j = 0; j < eventList.Count; j++) {
uint ridIndex = eventList[j] - 1;
if (newEventRidToTypeDefRid[ridIndex] != 0)
continue;
newEventRidToTypeDefRid[ridIndex] = ownerRid;
}
}
Interlocked.CompareExchange(ref eventRidToTypeDefRid, newEventRidToTypeDefRid, null);
}
public override uint GetOwnerTypeOfProperty(uint propertyRid) {
if (propertyRidToTypeDefRid is null)
InitializeInversePropertyOwnerRidList();
uint index = propertyRid - 1;
if (index >= propertyRidToTypeDefRid.LongLength)
return 0;
return propertyRidToTypeDefRid[index];
}
void InitializeInversePropertyOwnerRidList() {
if (propertyRidToTypeDefRid is not null)
return;
var newPropertyRidToTypeDefRid = new uint[tablesStream.PropertyTable.Rows];
var ownerList = GetTypeDefRidList();
for (int i = 0; i < ownerList.Count; i++) {
var ownerRid = ownerList[i];
var propertyList = GetPropertyRidList(GetPropertyMapRid(ownerRid));
for (int j = 0; j < propertyList.Count; j++) {
uint ridIndex = propertyList[j] - 1;
if (newPropertyRidToTypeDefRid[ridIndex] != 0)
continue;
newPropertyRidToTypeDefRid[ridIndex] = ownerRid;
}
}
Interlocked.CompareExchange(ref propertyRidToTypeDefRid, newPropertyRidToTypeDefRid, null);
}
public override uint GetOwnerOfGenericParam(uint gpRid) {
// Don't use GenericParam.Owner column. If the GP table is sorted, it's
// possible to have two blocks of GPs with the same owner. Only one of the
// blocks is the "real" generic params for the owner. Of course, rarely
// if ever will this occur, but could happen if some obfuscator has
// added it.
if (gpRidToOwnerRid is null)
InitializeInverseGenericParamOwnerRidList();
uint index = gpRid - 1;
if (index >= gpRidToOwnerRid.LongLength)
return 0;
return gpRidToOwnerRid[index];
}
void InitializeInverseGenericParamOwnerRidList() {
if (gpRidToOwnerRid is not null)
return;
var gpTable = tablesStream.GenericParamTable;
var newGpRidToOwnerRid = new uint[gpTable.Rows];
// Find all owners by reading the GenericParam.Owner column
var ownerCol = gpTable.TableInfo.Columns[2];
var ownersDict = new Dictionary<uint, bool>();
for (uint rid = 1; rid <= gpTable.Rows; rid++) {
if (!tablesStream.TryReadColumn24(gpTable, rid, ownerCol, out uint owner))
continue;
ownersDict[owner] = true;
}
// Now that we have the owners, find all the generic params they own. An obfuscated
// module could have 2+ owners pointing to the same generic param row.
var owners = new List<uint>(ownersDict.Keys);
owners.Sort();
for (int i = 0; i < owners.Count; i++) {
if (!CodedToken.TypeOrMethodDef.Decode(owners[i], out uint ownerToken))
continue;
var ridList = GetGenericParamRidList(MDToken.ToTable(ownerToken), MDToken.ToRID(ownerToken));
for (int j = 0; j < ridList.Count; j++) {
uint ridIndex = ridList[j] - 1;
if (newGpRidToOwnerRid[ridIndex] != 0)
continue;
newGpRidToOwnerRid[ridIndex] = owners[i];
}
}
Interlocked.CompareExchange(ref gpRidToOwnerRid, newGpRidToOwnerRid, null);
}
public override uint GetOwnerOfGenericParamConstraint(uint gpcRid) {
// Don't use GenericParamConstraint.Owner column for the same reason
// as described in GetOwnerOfGenericParam().
if (gpcRidToOwnerRid is null)
InitializeInverseGenericParamConstraintOwnerRidList();
uint index = gpcRid - 1;
if (index >= gpcRidToOwnerRid.LongLength)
return 0;
return gpcRidToOwnerRid[index];
}
void InitializeInverseGenericParamConstraintOwnerRidList() {
if (gpcRidToOwnerRid is not null)
return;
var gpcTable = tablesStream.GenericParamConstraintTable;
var newGpcRidToOwnerRid = new uint[gpcTable.Rows];
var ownerCol = gpcTable.TableInfo.Columns[0];
var ownersDict = new Dictionary<uint, bool>();
for (uint rid = 1; rid <= gpcTable.Rows; rid++) {
if (!tablesStream.TryReadColumn24(gpcTable, rid, ownerCol, out uint owner))
continue;
ownersDict[owner] = true;
}
var owners = new List<uint>(ownersDict.Keys);
owners.Sort();
for (int i = 0; i < owners.Count; i++) {
uint ownerToken = owners[i];
var ridList = GetGenericParamConstraintRidList(ownerToken);
for (int j = 0; j < ridList.Count; j++) {
uint ridIndex = ridList[j] - 1;
if (newGpcRidToOwnerRid[ridIndex] != 0)
continue;
newGpcRidToOwnerRid[ridIndex] = ownerToken;
}
}
Interlocked.CompareExchange(ref gpcRidToOwnerRid, newGpcRidToOwnerRid, null);
}
public override uint GetOwnerOfParam(uint paramRid) {
if (paramRidToOwnerRid is null)
InitializeInverseParamOwnerRidList();
uint index = paramRid - 1;
if (index >= paramRidToOwnerRid.LongLength)
return 0;
return paramRidToOwnerRid[index];
}
void InitializeInverseParamOwnerRidList() {
if (paramRidToOwnerRid is not null)
return;
var newParamRidToOwnerRid = new uint[tablesStream.ParamTable.Rows];
var table = tablesStream.MethodTable;
for (uint rid = 1; rid <= table.Rows; rid++) {
var ridList = GetParamRidList(rid);
for (int j = 0; j < ridList.Count; j++) {
uint ridIndex = ridList[j] - 1;
if (newParamRidToOwnerRid[ridIndex] != 0)
continue;
newParamRidToOwnerRid[ridIndex] = rid;
}
}
Interlocked.CompareExchange(ref paramRidToOwnerRid, newParamRidToOwnerRid, null);
}
public override RidList GetNestedClassRidList(uint typeDefRid) {
if (typeDefRidToNestedClasses is null)
InitializeNestedClassesDictionary();
if (typeDefRidToNestedClasses.TryGetValue(typeDefRid, out var ridList))
return RidList.Create(ridList);
return RidList.Empty;
}
void InitializeNestedClassesDictionary() {
var table = tablesStream.NestedClassTable;
var destTable = tablesStream.TypeDefTable;
Dictionary<uint, bool> validTypeDefRids = null;
var typeDefRidList = GetTypeDefRidList();
if ((uint)typeDefRidList.Count != destTable.Rows) {
validTypeDefRids = new Dictionary<uint, bool>(typeDefRidList.Count);
for (int i = 0; i < typeDefRidList.Count; i++)
validTypeDefRids[typeDefRidList[i]] = true;
}
var nestedRidsDict = new Dictionary<uint, bool>((int)table.Rows);
var nestedRids = new List<uint>((int)table.Rows); // Need it so we add the rids in correct order
for (uint rid = 1; rid <= table.Rows; rid++) {
if (validTypeDefRids is not null && !validTypeDefRids.ContainsKey(rid))
continue;
if (!tablesStream.TryReadNestedClassRow(rid, out var row))
continue; // Should never happen since rid is valid
if (!destTable.IsValidRID(row.NestedClass) || !destTable.IsValidRID(row.EnclosingClass))
continue;
if (nestedRidsDict.ContainsKey(row.NestedClass))
continue;
nestedRidsDict[row.NestedClass] = true;
nestedRids.Add(row.NestedClass);
}
var newTypeDefRidToNestedClasses = new Dictionary<uint, List<uint>>();
int count = nestedRids.Count;
for (int i = 0; i < count; i++) {
var nestedRid = nestedRids[i];
if (!tablesStream.TryReadNestedClassRow(GetNestedClassRid(nestedRid), out var row))
continue;
if (!newTypeDefRidToNestedClasses.TryGetValue(row.EnclosingClass, out var ridList))
newTypeDefRidToNestedClasses[row.EnclosingClass] = ridList = new List<uint>();
ridList.Add(nestedRid);
}
var newNonNestedTypes = new List<uint>((int)(destTable.Rows - nestedRidsDict.Count));
for (uint rid = 1; rid <= destTable.Rows; rid++) {
if (validTypeDefRids is not null && !validTypeDefRids.ContainsKey(rid))
continue;
if (nestedRidsDict.ContainsKey(rid))
continue;
newNonNestedTypes.Add(rid);
}
Interlocked.CompareExchange(ref nonNestedTypes, new StrongBox<RidList>(RidList.Create(newNonNestedTypes)), null);
// Initialize this one last since it's tested by the callers of this method
Interlocked.CompareExchange(ref typeDefRidToNestedClasses, newTypeDefRidToNestedClasses, null);
}
public override RidList GetNonNestedClassRidList() {
// Check typeDefRidToNestedClasses and not nonNestedTypes since
// InitializeNestedClassesDictionary() writes to typeDefRidToNestedClasses last.
if (typeDefRidToNestedClasses is null)
InitializeNestedClassesDictionary();
return nonNestedTypes.Value;
}
public override RidList GetLocalScopeRidList(uint methodRid) => FindAllRows(tablesStream.LocalScopeTable, 0, methodRid);
public override uint GetStateMachineMethodRid(uint methodRid) {
var list = FindAllRows(tablesStream.StateMachineMethodTable, 0, methodRid);
return list.Count == 0 ? 0 : list[0];
}
public override RidList GetCustomDebugInformationRidList(Table table, uint rid) {
if (!CodedToken.HasCustomDebugInformation.Encode(new MDToken(table, rid), out uint codedToken))
return RidList.Empty;
return FindAllRows(tablesStream.CustomDebugInformationTable, 0, codedToken);
}
public override void Dispose() {
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Dispose method
/// </summary>
/// <param name="disposing"><c>true</c> if called by <see cref="Dispose()"/></param>
protected virtual void Dispose(bool disposing) {
if (!disposing)
return;
peImage?.Dispose();
stringsStream?.Dispose();
usStream?.Dispose();
blobStream?.Dispose();
guidStream?.Dispose();
tablesStream?.Dispose();
var as2 = allStreams;
if (as2 is not null) {
foreach (var stream in as2)
stream?.Dispose();
}
mdReaderFactoryToDisposeLater?.Dispose();
peImage = null;
cor20Header = null;
mdHeader = null;
stringsStream = null;
usStream = null;
blobStream = null;
guidStream = null;
tablesStream = null;
allStreams = null;
fieldRidToTypeDefRid = null;
methodRidToTypeDefRid = null;
typeDefRidToNestedClasses = null;
mdReaderFactoryToDisposeLater = null;
}
}
}

View File

@ -1,222 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System;
using System.Collections.Generic;
using dnlib.IO;
using dnlib.PE;
namespace dnlib.DotNet.MD {
/// <summary>
/// Low level access to a .NET file's metadata
/// </summary>
public static class MetadataFactory {
enum MetadataType {
Unknown,
Compressed, // #~ (normal)
ENC, // #- (edit and continue)
}
internal static MetadataBase Load(string fileName, CLRRuntimeReaderKind runtime) {
IPEImage peImage = null;
try {
return Load(peImage = new PEImage(fileName), runtime);
}
catch {
if (peImage is not null)
peImage.Dispose();
throw;
}
}
internal static MetadataBase Load(byte[] data, CLRRuntimeReaderKind runtime) {
IPEImage peImage = null;
try {
return Load(peImage = new PEImage(data), runtime);
}
catch {
if (peImage is not null)
peImage.Dispose();
throw;
}
}
internal static MetadataBase Load(IntPtr addr, CLRRuntimeReaderKind runtime) {
IPEImage peImage = null;
// We don't know what layout it is. Memory is more common so try that first.
try {
return Load(peImage = new PEImage(addr, ImageLayout.Memory, true), runtime);
}
catch {
if (peImage is not null)
peImage.Dispose();
peImage = null;
}
try {
return Load(peImage = new PEImage(addr, ImageLayout.File, true), runtime);
}
catch {
if (peImage is not null)
peImage.Dispose();
throw;
}
}
internal static MetadataBase Load(IntPtr addr, ImageLayout imageLayout, CLRRuntimeReaderKind runtime) {
IPEImage peImage = null;
try {
return Load(peImage = new PEImage(addr, imageLayout, true), runtime);
}
catch {
if (peImage is not null)
peImage.Dispose();
throw;
}
}
internal static MetadataBase Load(IPEImage peImage, CLRRuntimeReaderKind runtime) => Create(peImage, runtime, true);
/// <summary>
/// Create a <see cref="Metadata"/> instance
/// </summary>
/// <param name="peImage">The PE image</param>
/// <returns>A new <see cref="Metadata"/> instance</returns>
public static Metadata CreateMetadata(IPEImage peImage) => CreateMetadata(peImage, CLRRuntimeReaderKind.CLR);
/// <summary>
/// Create a <see cref="Metadata"/> instance
/// </summary>
/// <param name="peImage">The PE image</param>
/// <param name="runtime">Runtime reader kind</param>
/// <returns>A new <see cref="Metadata"/> instance</returns>
public static Metadata CreateMetadata(IPEImage peImage, CLRRuntimeReaderKind runtime) => Create(peImage, runtime, true);
/// <summary>
/// Create a <see cref="Metadata"/> instance
/// </summary>
/// <param name="peImage">The PE image</param>
/// <param name="verify"><c>true</c> if we should verify that it's a .NET PE file</param>
/// <returns>A new <see cref="Metadata"/> instance</returns>
public static Metadata CreateMetadata(IPEImage peImage, bool verify) => CreateMetadata(peImage, CLRRuntimeReaderKind.CLR, verify);
/// <summary>
/// Create a <see cref="Metadata"/> instance
/// </summary>
/// <param name="peImage">The PE image</param>
/// <param name="runtime">Runtime reader kind</param>
/// <param name="verify"><c>true</c> if we should verify that it's a .NET PE file</param>
/// <returns>A new <see cref="Metadata"/> instance</returns>
public static Metadata CreateMetadata(IPEImage peImage, CLRRuntimeReaderKind runtime, bool verify) => Create(peImage, runtime, verify);
/// <summary>
/// Create a <see cref="MetadataBase"/> instance
/// </summary>
/// <param name="peImage">The PE image</param>
/// <param name="runtime">Runtime reader kind</param>
/// <param name="verify"><c>true</c> if we should verify that it's a .NET PE file</param>
/// <returns>A new <see cref="MetadataBase"/> instance</returns>
static MetadataBase Create(IPEImage peImage, CLRRuntimeReaderKind runtime, bool verify) {
MetadataBase md = null;
try {
var dotNetDir = peImage.ImageNTHeaders.OptionalHeader.DataDirectories[14];
// Mono doesn't check that the Size field is >= 0x48
if (dotNetDir.VirtualAddress == 0)
throw new BadImageFormatException(".NET data directory RVA is 0");
var cor20HeaderReader = peImage.CreateReader(dotNetDir.VirtualAddress, 0x48);
var cor20Header = new ImageCor20Header(ref cor20HeaderReader, verify && runtime == CLRRuntimeReaderKind.CLR);
if (cor20Header.Metadata.VirtualAddress == 0)
throw new BadImageFormatException(".NET metadata RVA is 0");
var mdRva = cor20Header.Metadata.VirtualAddress;
// Don't use the size field, Mono ignores it. Create a reader that can read to EOF.
var mdHeaderReader = peImage.CreateReader(mdRva);
var mdHeader = new MetadataHeader(ref mdHeaderReader, runtime, verify);
if (verify) {
foreach (var sh in mdHeader.StreamHeaders) {
if ((ulong)sh.Offset + sh.StreamSize > mdHeaderReader.EndOffset)
throw new BadImageFormatException("Invalid stream header");
}
}
md = GetMetadataType(mdHeader.StreamHeaders, runtime) switch {
MetadataType.Compressed => new CompressedMetadata(peImage, cor20Header, mdHeader, runtime),
MetadataType.ENC => new ENCMetadata(peImage, cor20Header, mdHeader, runtime),
_ => throw new BadImageFormatException("No #~ or #- stream found"),
};
md.Initialize(null);
return md;
}
catch {
if (md is not null)
md.Dispose();
throw;
}
}
/// <summary>
/// Create a standalone portable PDB <see cref="MetadataBase"/> instance
/// </summary>
/// <param name="mdReaderFactory">Metadata stream</param>
/// <param name="verify"><c>true</c> if we should verify that it's a .NET PE file</param>
/// <returns>A new <see cref="MetadataBase"/> instance</returns>
internal static MetadataBase CreateStandalonePortablePDB(DataReaderFactory mdReaderFactory, bool verify) {
const CLRRuntimeReaderKind runtime = CLRRuntimeReaderKind.CLR;
MetadataBase md = null;
try {
var reader = mdReaderFactory.CreateReader();
var mdHeader = new MetadataHeader(ref reader, runtime, verify);
if (verify) {
foreach (var sh in mdHeader.StreamHeaders) {
if (sh.Offset + sh.StreamSize < sh.Offset || sh.Offset + sh.StreamSize > reader.Length)
throw new BadImageFormatException("Invalid stream header");
}
}
md = GetMetadataType(mdHeader.StreamHeaders, runtime) switch {
MetadataType.Compressed => new CompressedMetadata(mdHeader, true, runtime),
MetadataType.ENC => new ENCMetadata(mdHeader, true, runtime),
_ => throw new BadImageFormatException("No #~ or #- stream found"),
};
md.Initialize(mdReaderFactory);
return md;
}
catch {
md?.Dispose();
throw;
}
}
static MetadataType GetMetadataType(IList<StreamHeader> streamHeaders, CLRRuntimeReaderKind runtime) {
MetadataType? mdType = null;
if (runtime == CLRRuntimeReaderKind.CLR) {
foreach (var sh in streamHeaders) {
if (mdType is null) {
if (sh.Name == "#~")
mdType = MetadataType.Compressed;
else if (sh.Name == "#-")
mdType = MetadataType.ENC;
}
if (sh.Name == "#Schema")
mdType = MetadataType.ENC;
}
}
else if (runtime == CLRRuntimeReaderKind.Mono) {
foreach (var sh in streamHeaders) {
if (sh.Name == "#~")
mdType = MetadataType.Compressed;
else if (sh.Name == "#-") {
mdType = MetadataType.ENC;
break;
}
}
}
else
throw new ArgumentOutOfRangeException(nameof(runtime));
if (mdType is null)
return MetadataType.Unknown;
return mdType.Value;
}
}
}

View File

@ -1,141 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System;
using System.Collections.Generic;
using System.Text;
using dnlib.IO;
namespace dnlib.DotNet.MD {
/// <summary>
/// Represents the .NET metadata header
/// </summary>
/// <remarks><c>IMAGE_COR20_HEADER.Metadata</c> points to this header</remarks>
public sealed class MetadataHeader : FileSection {
readonly uint signature;
readonly ushort majorVersion;
readonly ushort minorVersion;
readonly uint reserved1;
readonly uint stringLength;
readonly string versionString;
readonly FileOffset offset2ndPart;
readonly StorageFlags flags;
readonly byte reserved2;
readonly ushort streams;
readonly IList<StreamHeader> streamHeaders;
/// <summary>
/// Returns the signature (should be 0x424A5342)
/// </summary>
public uint Signature => signature;
/// <summary>
/// Returns the major version
/// </summary>
public ushort MajorVersion => majorVersion;
/// <summary>
/// Returns the minor version
/// </summary>
public ushort MinorVersion => minorVersion;
/// <summary>
/// Returns the reserved dword (pointer to extra header data)
/// </summary>
public uint Reserved1 => reserved1;
/// <summary>
/// Returns the version string length value
/// </summary>
public uint StringLength => stringLength;
/// <summary>
/// Returns the version string
/// </summary>
public string VersionString => versionString;
/// <summary>
/// Returns the offset of <c>STORAGEHEADER</c>
/// </summary>
public FileOffset StorageHeaderOffset => offset2ndPart;
/// <summary>
/// Returns the flags (reserved)
/// </summary>
public StorageFlags Flags => flags;
/// <summary>
/// Returns the reserved byte (padding)
/// </summary>
public byte Reserved2 => reserved2;
/// <summary>
/// Returns the number of streams
/// </summary>
public ushort Streams => streams;
/// <summary>
/// Returns all stream headers
/// </summary>
public IList<StreamHeader> StreamHeaders => streamHeaders;
/// <summary>
/// Constructor
/// </summary>
/// <param name="reader">PE file reader pointing to the start of this section</param>
/// <param name="verify">Verify section</param>
/// <exception cref="BadImageFormatException">Thrown if verification fails</exception>
public MetadataHeader(ref DataReader reader, bool verify)
: this(ref reader, CLRRuntimeReaderKind.CLR, verify) {
}
/// <summary>
/// Constructor
/// </summary>
/// <param name="reader">PE file reader pointing to the start of this section</param>
/// <param name="runtime">Runtime reader kind</param>
/// <param name="verify">Verify section</param>
/// <exception cref="BadImageFormatException">Thrown if verification fails</exception>
public MetadataHeader(ref DataReader reader, CLRRuntimeReaderKind runtime, bool verify) {
SetStartOffset(ref reader);
signature = reader.ReadUInt32();
if (verify && signature != 0x424A5342)
throw new BadImageFormatException("Invalid metadata header signature");
majorVersion = reader.ReadUInt16();
minorVersion = reader.ReadUInt16();
reserved1 = reader.ReadUInt32();
stringLength = reader.ReadUInt32();
versionString = ReadString(ref reader, stringLength, runtime);
offset2ndPart = (FileOffset)reader.CurrentOffset;
flags = (StorageFlags)reader.ReadByte();
reserved2 = reader.ReadByte();
streams = reader.ReadUInt16();
streamHeaders = new StreamHeader[streams];
for (int i = 0; i < streamHeaders.Count; i++) {
// Mono doesn't verify all of these so we can't either
var sh = new StreamHeader(ref reader, throwOnError: false, verify, runtime, out bool failedVerification);
if (failedVerification || (ulong)sh.Offset + sh.StreamSize > reader.EndOffset)
sh = new StreamHeader(0, 0, "<invalid>");
streamHeaders[i] = sh;
}
SetEndoffset(ref reader);
}
static string ReadString(ref DataReader reader, uint maxLength, CLRRuntimeReaderKind runtime) {
ulong endOffset = (ulong)reader.CurrentOffset + maxLength;
if (runtime == CLRRuntimeReaderKind.Mono)
endOffset = (endOffset + 3) / 4 * 4;
if (endOffset > reader.EndOffset)
throw new BadImageFormatException("Invalid MD version string");
var utf8Bytes = new byte[maxLength];
uint i;
for (i = 0; i < maxLength; i++) {
byte b = reader.ReadByte();
if (b == 0)
break;
utf8Bytes[i] = b;
}
reader.CurrentOffset = (uint)endOffset;
return Encoding.UTF8.GetString(utf8Bytes, 0, (int)i);
}
}
}

View File

@ -1,46 +0,0 @@
// dnlib: See LICENSE.txt for more info
using dnlib.IO;
namespace dnlib.DotNet.MD {
/// <summary>
/// #Pdb stream
/// </summary>
public sealed class PdbStream : HeapStream {
/// <summary>
/// Gets the PDB id
/// </summary>
public byte[] Id { get; private set; }
/// <summary>
/// Gets the entry point token or 0
/// </summary>
public MDToken EntryPoint { get; private set; }
/// <summary>
/// Gets the referenced type system tables in the PE metadata file
/// </summary>
public ulong ReferencedTypeSystemTables { get; private set; }
/// <summary>
/// Gets all type system table rows. This array has exactly 64 elements.
/// </summary>
public uint[] TypeSystemTableRows { get; private set; }
/// <inheritdoc/>
public PdbStream(DataReaderFactory mdReaderFactory, uint metadataBaseOffset, StreamHeader streamHeader)
: base(mdReaderFactory, metadataBaseOffset, streamHeader) {
var reader = CreateReader();
Id = reader.ReadBytes(20);
EntryPoint = new MDToken(reader.ReadUInt32());
var tables = reader.ReadUInt64();
ReferencedTypeSystemTables = tables;
var rows = new uint[64];
for (int i = 0; i < rows.Length; i++, tables >>= 1) {
if (((uint)tables & 1) != 0)
rows[i] = reader.ReadUInt32();
}
TypeSystemTableRows = rows;
}
}
}

View File

@ -1,550 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System.Collections.Generic;
#pragma warning disable 1591 // XML doc comments
namespace dnlib.DotNet.MD {
/// <summary>
/// Equality comparer for all raw rows
/// </summary>
public sealed class RawRowEqualityComparer : IEqualityComparer<RawModuleRow>,
IEqualityComparer<RawTypeRefRow>, IEqualityComparer<RawTypeDefRow>,
IEqualityComparer<RawFieldPtrRow>, IEqualityComparer<RawFieldRow>,
IEqualityComparer<RawMethodPtrRow>, IEqualityComparer<RawMethodRow>,
IEqualityComparer<RawParamPtrRow>, IEqualityComparer<RawParamRow>,
IEqualityComparer<RawInterfaceImplRow>, IEqualityComparer<RawMemberRefRow>,
IEqualityComparer<RawConstantRow>, IEqualityComparer<RawCustomAttributeRow>,
IEqualityComparer<RawFieldMarshalRow>, IEqualityComparer<RawDeclSecurityRow>,
IEqualityComparer<RawClassLayoutRow>, IEqualityComparer<RawFieldLayoutRow>,
IEqualityComparer<RawStandAloneSigRow>, IEqualityComparer<RawEventMapRow>,
IEqualityComparer<RawEventPtrRow>, IEqualityComparer<RawEventRow>,
IEqualityComparer<RawPropertyMapRow>, IEqualityComparer<RawPropertyPtrRow>,
IEqualityComparer<RawPropertyRow>, IEqualityComparer<RawMethodSemanticsRow>,
IEqualityComparer<RawMethodImplRow>, IEqualityComparer<RawModuleRefRow>,
IEqualityComparer<RawTypeSpecRow>, IEqualityComparer<RawImplMapRow>,
IEqualityComparer<RawFieldRVARow>, IEqualityComparer<RawENCLogRow>,
IEqualityComparer<RawENCMapRow>, IEqualityComparer<RawAssemblyRow>,
IEqualityComparer<RawAssemblyProcessorRow>, IEqualityComparer<RawAssemblyOSRow>,
IEqualityComparer<RawAssemblyRefRow>, IEqualityComparer<RawAssemblyRefProcessorRow>,
IEqualityComparer<RawAssemblyRefOSRow>, IEqualityComparer<RawFileRow>,
IEqualityComparer<RawExportedTypeRow>, IEqualityComparer<RawManifestResourceRow>,
IEqualityComparer<RawNestedClassRow>, IEqualityComparer<RawGenericParamRow>,
IEqualityComparer<RawMethodSpecRow>, IEqualityComparer<RawGenericParamConstraintRow>,
IEqualityComparer<RawDocumentRow>, IEqualityComparer<RawMethodDebugInformationRow>,
IEqualityComparer<RawLocalScopeRow>, IEqualityComparer<RawLocalVariableRow>,
IEqualityComparer<RawLocalConstantRow>, IEqualityComparer<RawImportScopeRow>,
IEqualityComparer<RawStateMachineMethodRow>, IEqualityComparer<RawCustomDebugInformationRow> {
/// <summary>
/// Default instance
/// </summary>
public static readonly RawRowEqualityComparer Instance = new RawRowEqualityComparer();
static int rol(uint val, int shift) => (int)((val << shift) | (val >> (32 - shift)));
public bool Equals(RawModuleRow x, RawModuleRow y) =>
x.Generation == y.Generation &&
x.Name == y.Name &&
x.Mvid == y.Mvid &&
x.EncId == y.EncId &&
x.EncBaseId == y.EncBaseId;
public int GetHashCode(RawModuleRow obj) =>
obj.Generation +
rol(obj.Name, 3) +
rol(obj.Mvid, 7) +
rol(obj.EncId, 11) +
rol(obj.EncBaseId, 15);
public bool Equals(RawTypeRefRow x, RawTypeRefRow y) =>
x.ResolutionScope == y.ResolutionScope &&
x.Name == y.Name &&
x.Namespace == y.Namespace;
public int GetHashCode(RawTypeRefRow obj) =>
(int)obj.ResolutionScope +
rol(obj.Name, 3) +
rol(obj.Namespace, 7);
public bool Equals(RawTypeDefRow x, RawTypeDefRow y) =>
x.Flags == y.Flags &&
x.Name == y.Name &&
x.Namespace == y.Namespace &&
x.Extends == y.Extends &&
x.FieldList == y.FieldList &&
x.MethodList == y.MethodList;
public int GetHashCode(RawTypeDefRow obj) =>
(int)obj.Flags +
rol(obj.Name, 3) +
rol(obj.Namespace, 7) +
rol(obj.Extends, 11) +
rol(obj.FieldList, 15) +
rol(obj.MethodList, 19);
public bool Equals(RawFieldPtrRow x, RawFieldPtrRow y) => x.Field == y.Field;
public int GetHashCode(RawFieldPtrRow obj) => (int)obj.Field;
public bool Equals(RawFieldRow x, RawFieldRow y) =>
x.Flags == y.Flags &&
x.Name == y.Name &&
x.Signature == y.Signature;
public int GetHashCode(RawFieldRow obj) =>
(int)obj.Flags +
rol(obj.Name, 3) +
rol(obj.Signature, 7);
public bool Equals(RawMethodPtrRow x, RawMethodPtrRow y) => x.Method == y.Method;
public int GetHashCode(RawMethodPtrRow obj) => (int)obj.Method;
public bool Equals(RawMethodRow x, RawMethodRow y) =>
x.RVA == y.RVA &&
x.ImplFlags == y.ImplFlags &&
x.Flags == y.Flags &&
x.Name == y.Name &&
x.Signature == y.Signature &&
x.ParamList == y.ParamList;
public int GetHashCode(RawMethodRow obj) =>
(int)obj.RVA +
rol(obj.ImplFlags, 3) +
rol(obj.Flags, 7) +
rol(obj.Name, 11) +
rol(obj.Signature, 15) +
rol(obj.ParamList, 19);
public bool Equals(RawParamPtrRow x, RawParamPtrRow y) => x.Param == y.Param;
public int GetHashCode(RawParamPtrRow obj) => (int)obj.Param;
public bool Equals(RawParamRow x, RawParamRow y) =>
x.Flags == y.Flags &&
x.Sequence == y.Sequence &&
x.Name == y.Name;
public int GetHashCode(RawParamRow obj) =>
(int)obj.Flags +
rol(obj.Sequence, 3) +
rol(obj.Name, 7);
public bool Equals(RawInterfaceImplRow x, RawInterfaceImplRow y) =>
x.Class == y.Class &&
x.Interface == y.Interface;
public int GetHashCode(RawInterfaceImplRow obj) =>
(int)obj.Class +
rol(obj.Interface, 3);
public bool Equals(RawMemberRefRow x, RawMemberRefRow y) =>
x.Class == y.Class &&
x.Name == y.Name &&
x.Signature == y.Signature;
public int GetHashCode(RawMemberRefRow obj) =>
(int)obj.Class +
rol(obj.Name, 3) +
rol(obj.Signature, 7);
public bool Equals(RawConstantRow x, RawConstantRow y) =>
x.Type == y.Type &&
x.Padding == y.Padding &&
x.Parent == y.Parent &&
x.Value == y.Value;
public int GetHashCode(RawConstantRow obj) =>
(int)obj.Type +
rol(obj.Padding, 3) +
rol(obj.Parent, 7) +
rol(obj.Value, 11);
public bool Equals(RawCustomAttributeRow x, RawCustomAttributeRow y) =>
x.Parent == y.Parent &&
x.Type == y.Type &&
x.Value == y.Value;
public int GetHashCode(RawCustomAttributeRow obj) =>
(int)obj.Parent +
rol(obj.Type, 3) +
rol(obj.Value, 7);
public bool Equals(RawFieldMarshalRow x, RawFieldMarshalRow y) =>
x.Parent == y.Parent &&
x.NativeType == y.NativeType;
public int GetHashCode(RawFieldMarshalRow obj) =>
(int)obj.Parent +
rol(obj.NativeType, 3);
public bool Equals(RawDeclSecurityRow x, RawDeclSecurityRow y) =>
x.Action == y.Action &&
x.Parent == y.Parent &&
x.PermissionSet == y.PermissionSet;
public int GetHashCode(RawDeclSecurityRow obj) =>
(int)obj.Action +
rol(obj.Parent, 3) +
rol(obj.PermissionSet, 7);
public bool Equals(RawClassLayoutRow x, RawClassLayoutRow y) =>
x.PackingSize == y.PackingSize &&
x.ClassSize == y.ClassSize &&
x.Parent == y.Parent;
public int GetHashCode(RawClassLayoutRow obj) =>
(int)obj.PackingSize +
rol(obj.ClassSize, 3) +
rol(obj.Parent, 7);
public bool Equals(RawFieldLayoutRow x, RawFieldLayoutRow y) =>
x.OffSet == y.OffSet &&
x.Field == y.Field;
public int GetHashCode(RawFieldLayoutRow obj) =>
(int)obj.OffSet +
rol(obj.Field, 3);
public bool Equals(RawStandAloneSigRow x, RawStandAloneSigRow y) => x.Signature == y.Signature;
public int GetHashCode(RawStandAloneSigRow obj) => (int)obj.Signature;
public bool Equals(RawEventMapRow x, RawEventMapRow y) =>
x.Parent == y.Parent &&
x.EventList == y.EventList;
public int GetHashCode(RawEventMapRow obj) =>
(int)obj.Parent +
rol(obj.EventList, 3);
public bool Equals(RawEventPtrRow x, RawEventPtrRow y) => x.Event == y.Event;
public int GetHashCode(RawEventPtrRow obj) => (int)obj.Event;
public bool Equals(RawEventRow x, RawEventRow y) =>
x.EventFlags == y.EventFlags &&
x.Name == y.Name &&
x.EventType == y.EventType;
public int GetHashCode(RawEventRow obj) =>
(int)obj.EventFlags +
rol(obj.Name, 3) +
rol(obj.EventType, 7);
public bool Equals(RawPropertyMapRow x, RawPropertyMapRow y) =>
x.Parent == y.Parent &&
x.PropertyList == y.PropertyList;
public int GetHashCode(RawPropertyMapRow obj) =>
(int)obj.Parent +
rol(obj.PropertyList, 3);
public bool Equals(RawPropertyPtrRow x, RawPropertyPtrRow y) => x.Property == y.Property;
public int GetHashCode(RawPropertyPtrRow obj) => (int)obj.Property;
public bool Equals(RawPropertyRow x, RawPropertyRow y) =>
x.PropFlags == y.PropFlags &&
x.Name == y.Name &&
x.Type == y.Type;
public int GetHashCode(RawPropertyRow obj) =>
(int)obj.PropFlags +
rol(obj.Name, 3) +
rol(obj.Type, 7);
public bool Equals(RawMethodSemanticsRow x, RawMethodSemanticsRow y) =>
x.Semantic == y.Semantic &&
x.Method == y.Method &&
x.Association == y.Association;
public int GetHashCode(RawMethodSemanticsRow obj) =>
(int)obj.Semantic +
rol(obj.Method, 3) +
rol(obj.Association, 7);
public bool Equals(RawMethodImplRow x, RawMethodImplRow y) =>
x.Class == y.Class &&
x.MethodBody == y.MethodBody &&
x.MethodDeclaration == y.MethodDeclaration;
public int GetHashCode(RawMethodImplRow obj) =>
(int)obj.Class +
rol(obj.MethodBody, 3) +
rol(obj.MethodDeclaration, 7);
public bool Equals(RawModuleRefRow x, RawModuleRefRow y) => x.Name == y.Name;
public int GetHashCode(RawModuleRefRow obj) => (int)obj.Name;
public bool Equals(RawTypeSpecRow x, RawTypeSpecRow y) => x.Signature == y.Signature;
public int GetHashCode(RawTypeSpecRow obj) => (int)obj.Signature;
public bool Equals(RawImplMapRow x, RawImplMapRow y) =>
x.MappingFlags == y.MappingFlags &&
x.MemberForwarded == y.MemberForwarded &&
x.ImportName == y.ImportName &&
x.ImportScope == y.ImportScope;
public int GetHashCode(RawImplMapRow obj) =>
(int)obj.MappingFlags +
rol(obj.MemberForwarded, 3) +
rol(obj.ImportName, 7) +
rol(obj.ImportScope, 11);
public bool Equals(RawFieldRVARow x, RawFieldRVARow y) =>
x.RVA == y.RVA &&
x.Field == y.Field;
public int GetHashCode(RawFieldRVARow obj) =>
(int)obj.RVA +
rol(obj.Field, 3);
public bool Equals(RawENCLogRow x, RawENCLogRow y) =>
x.Token == y.Token &&
x.FuncCode == y.FuncCode;
public int GetHashCode(RawENCLogRow obj) =>
(int)obj.Token +
rol(obj.FuncCode, 3);
public bool Equals(RawENCMapRow x, RawENCMapRow y) => x.Token == y.Token;
public int GetHashCode(RawENCMapRow obj) => (int)obj.Token;
public bool Equals(RawAssemblyRow x, RawAssemblyRow y) =>
x.HashAlgId == y.HashAlgId &&
x.MajorVersion == y.MajorVersion &&
x.MinorVersion == y.MinorVersion &&
x.BuildNumber == y.BuildNumber &&
x.RevisionNumber == y.RevisionNumber &&
x.Flags == y.Flags &&
x.PublicKey == y.PublicKey &&
x.Name == y.Name &&
x.Locale == y.Locale;
public int GetHashCode(RawAssemblyRow obj) =>
(int)obj.HashAlgId +
rol(obj.MajorVersion, 3) +
rol(obj.MinorVersion, 7) +
rol(obj.BuildNumber, 11) +
rol(obj.RevisionNumber, 15) +
rol(obj.Flags, 19) +
rol(obj.PublicKey, 23) +
rol(obj.Name, 27) +
rol(obj.Locale, 31);
public bool Equals(RawAssemblyProcessorRow x, RawAssemblyProcessorRow y) => x.Processor == y.Processor;
public int GetHashCode(RawAssemblyProcessorRow obj) => (int)obj.Processor;
public bool Equals(RawAssemblyOSRow x, RawAssemblyOSRow y) =>
x.OSPlatformId == y.OSPlatformId &&
x.OSMajorVersion == y.OSMajorVersion &&
x.OSMinorVersion == y.OSMinorVersion;
public int GetHashCode(RawAssemblyOSRow obj) =>
(int)obj.OSPlatformId +
rol(obj.OSMajorVersion, 3) +
rol(obj.OSMinorVersion, 7);
public bool Equals(RawAssemblyRefRow x, RawAssemblyRefRow y) =>
x.MajorVersion == y.MajorVersion &&
x.MinorVersion == y.MinorVersion &&
x.BuildNumber == y.BuildNumber &&
x.RevisionNumber == y.RevisionNumber &&
x.Flags == y.Flags &&
x.PublicKeyOrToken == y.PublicKeyOrToken &&
x.Name == y.Name &&
x.Locale == y.Locale &&
x.HashValue == y.HashValue;
public int GetHashCode(RawAssemblyRefRow obj) =>
(int)obj.MajorVersion +
rol(obj.MinorVersion, 3) +
rol(obj.BuildNumber, 7) +
rol(obj.RevisionNumber, 11) +
rol(obj.Flags, 15) +
rol(obj.PublicKeyOrToken, 19) +
rol(obj.Name, 23) +
rol(obj.Locale, 27) +
rol(obj.HashValue, 31);
public bool Equals(RawAssemblyRefProcessorRow x, RawAssemblyRefProcessorRow y) =>
x.Processor == y.Processor &&
x.AssemblyRef == y.AssemblyRef;
public int GetHashCode(RawAssemblyRefProcessorRow obj) =>
(int)obj.Processor +
rol(obj.AssemblyRef, 3);
public bool Equals(RawAssemblyRefOSRow x, RawAssemblyRefOSRow y) =>
x.OSPlatformId == y.OSPlatformId &&
x.OSMajorVersion == y.OSMajorVersion &&
x.OSMinorVersion == y.OSMinorVersion &&
x.AssemblyRef == y.AssemblyRef;
public int GetHashCode(RawAssemblyRefOSRow obj) =>
(int)obj.OSPlatformId +
rol(obj.OSMajorVersion, 3) +
rol(obj.OSMinorVersion, 7) +
rol(obj.AssemblyRef, 11);
public bool Equals(RawFileRow x, RawFileRow y) =>
x.Flags == y.Flags &&
x.Name == y.Name &&
x.HashValue == y.HashValue;
public int GetHashCode(RawFileRow obj) =>
(int)obj.Flags +
rol(obj.Name, 3) +
rol(obj.HashValue, 7);
public bool Equals(RawExportedTypeRow x, RawExportedTypeRow y) =>
x.Flags == y.Flags &&
x.TypeDefId == y.TypeDefId &&
x.TypeName == y.TypeName &&
x.TypeNamespace == y.TypeNamespace &&
x.Implementation == y.Implementation;
public int GetHashCode(RawExportedTypeRow obj) =>
(int)obj.Flags +
rol(obj.TypeDefId, 3) +
rol(obj.TypeName, 7) +
rol(obj.TypeNamespace, 11) +
rol(obj.Implementation, 15);
public bool Equals(RawManifestResourceRow x, RawManifestResourceRow y) =>
x.Offset == y.Offset &&
x.Flags == y.Flags &&
x.Name == y.Name &&
x.Implementation == y.Implementation;
public int GetHashCode(RawManifestResourceRow obj) =>
(int)obj.Offset +
rol(obj.Flags, 3) +
rol(obj.Name, 7) +
rol(obj.Implementation, 11);
public bool Equals(RawNestedClassRow x, RawNestedClassRow y) =>
x.NestedClass == y.NestedClass &&
x.EnclosingClass == y.EnclosingClass;
public int GetHashCode(RawNestedClassRow obj) =>
(int)obj.NestedClass +
rol(obj.EnclosingClass, 3);
public bool Equals(RawGenericParamRow x, RawGenericParamRow y) =>
x.Number == y.Number &&
x.Flags == y.Flags &&
x.Owner == y.Owner &&
x.Name == y.Name &&
x.Kind == y.Kind;
public int GetHashCode(RawGenericParamRow obj) =>
(int)obj.Number +
rol(obj.Flags, 3) +
rol(obj.Owner, 7) +
rol(obj.Name, 11) +
rol(obj.Kind, 15);
public bool Equals(RawMethodSpecRow x, RawMethodSpecRow y) =>
x.Method == y.Method &&
x.Instantiation == y.Instantiation;
public int GetHashCode(RawMethodSpecRow obj) =>
(int)obj.Method +
rol(obj.Instantiation, 3);
public bool Equals(RawGenericParamConstraintRow x, RawGenericParamConstraintRow y) =>
x.Owner == y.Owner &&
x.Constraint == y.Constraint;
public int GetHashCode(RawGenericParamConstraintRow obj) =>
(int)obj.Owner +
rol(obj.Constraint, 3);
public bool Equals(RawDocumentRow x, RawDocumentRow y) =>
x.Name == y.Name &&
x.HashAlgorithm == y.HashAlgorithm &&
x.Hash == y.Hash &&
x.Language == y.Language;
public int GetHashCode(RawDocumentRow obj) =>
(int)obj.Name +
rol(obj.HashAlgorithm, 3) +
rol(obj.Hash, 7) +
rol(obj.Language, 11);
public bool Equals(RawMethodDebugInformationRow x, RawMethodDebugInformationRow y) =>
x.Document == y.Document &&
x.SequencePoints == y.SequencePoints;
public int GetHashCode(RawMethodDebugInformationRow obj) =>
(int)obj.Document +
rol(obj.SequencePoints, 3);
public bool Equals(RawLocalScopeRow x, RawLocalScopeRow y) =>
x.Method == y.Method &&
x.ImportScope == y.ImportScope &&
x.VariableList == y.VariableList &&
x.ConstantList == y.ConstantList &&
x.StartOffset == y.StartOffset &&
x.Length == y.Length;
public int GetHashCode(RawLocalScopeRow obj) =>
(int)obj.Method +
rol(obj.ImportScope, 3) +
rol(obj.VariableList, 7) +
rol(obj.ConstantList, 11) +
rol(obj.StartOffset, 15) +
rol(obj.Length, 19);
public bool Equals(RawLocalVariableRow x, RawLocalVariableRow y) =>
x.Attributes == y.Attributes &&
x.Index == y.Index &&
x.Name == y.Name;
public int GetHashCode(RawLocalVariableRow obj) =>
obj.Attributes +
rol(obj.Index, 3) +
rol(obj.Name, 7);
public bool Equals(RawLocalConstantRow x, RawLocalConstantRow y) =>
x.Name == y.Name &&
x.Signature == y.Signature;
public int GetHashCode(RawLocalConstantRow obj) =>
(int)obj.Name +
rol(obj.Signature, 3);
public bool Equals(RawImportScopeRow x, RawImportScopeRow y) =>
x.Parent == y.Parent &&
x.Imports == y.Imports;
public int GetHashCode(RawImportScopeRow obj) =>
(int)obj.Parent +
rol(obj.Imports, 3);
public bool Equals(RawStateMachineMethodRow x, RawStateMachineMethodRow y) =>
x.MoveNextMethod == y.MoveNextMethod &&
x.KickoffMethod == y.KickoffMethod;
public int GetHashCode(RawStateMachineMethodRow obj) =>
(int)obj.MoveNextMethod +
rol(obj.KickoffMethod, 3);
public bool Equals(RawCustomDebugInformationRow x, RawCustomDebugInformationRow y) =>
x.Parent == y.Parent &&
x.Kind == y.Kind &&
x.Value == y.Value;
public int GetHashCode(RawCustomDebugInformationRow obj) =>
(int)obj.Parent +
rol(obj.Kind, 3) +
rol(obj.Value, 7);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,141 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
namespace dnlib.DotNet.MD {
/// <summary>
/// Stores a list of rids
/// </summary>
[DebuggerDisplay("Count = {Count}")]
public readonly struct RidList : IEnumerable<uint> {
readonly uint startRid;
readonly uint length;
readonly IList<uint> rids;
/// <summary>
/// Gets the empty instance
/// </summary>
public static readonly RidList Empty = Create(0, 0);
/// <summary>
/// Creates a new instance
/// </summary>
/// <param name="startRid"></param>
/// <param name="length"></param>
/// <returns></returns>
public static RidList Create(uint startRid, uint length) => new RidList(startRid, length);
/// <summary>
/// Creates a new instance
/// </summary>
/// <param name="rids">List of valid rids</param>
/// <returns></returns>
public static RidList Create(IList<uint> rids) => new RidList(rids);
RidList(uint startRid, uint length) {
this.startRid = startRid;
this.length = length;
rids = null;
}
RidList(IList<uint> rids) {
this.rids = rids ?? throw new ArgumentNullException(nameof(rids));
startRid = 0;
length = (uint)rids.Count;
}
/// <summary>
/// Gets the <paramref name="index"/>'th rid
/// </summary>
/// <param name="index">Index. Must be &lt; <see cref="Count"/></param>
/// <returns>A rid or 0 if <paramref name="index"/> is invalid</returns>
public uint this[int index] {
get {
if (rids is not null) {
if ((uint)index >= (uint)rids.Count)
return 0;
return rids[index];
}
else {
if ((uint)index >= length)
return 0;
return startRid + (uint)index;
}
}
}
/// <summary>
/// Gets the number of rids it will iterate over
/// </summary>
public int Count => (int)length;
/// <summary>
/// Enumerator
/// </summary>
public struct Enumerator : IEnumerator<uint> {
readonly uint startRid;
readonly uint length;
readonly IList<uint> rids;
uint index;
uint current;
internal Enumerator(in RidList list) {
startRid = list.startRid;
length = list.length;
rids = list.rids;
index = 0;
current = 0;
}
/// <summary>
/// Gets the current rid
/// </summary>
public uint Current => current;
object IEnumerator.Current => current;
/// <summary>
/// Disposes this instance
/// </summary>
public void Dispose() { }
/// <summary>
/// Moves to the next rid
/// </summary>
/// <returns></returns>
public bool MoveNext() {
if (rids is null && index < length) {
current = startRid + index;
index++;
return true;
}
return MoveNextOther();
}
bool MoveNextOther() {
if (index >= length) {
current = 0;
return false;
}
if (rids is not null)
current = rids[(int)index];
else
current = startRid + index;
index++;
return true;
}
void IEnumerator.Reset() => throw new NotSupportedException();
}
/// <summary>
/// Gets the enumerator
/// </summary>
/// <returns></returns>
public Enumerator GetEnumerator() => new Enumerator(this);
IEnumerator<uint> IEnumerable<uint>.GetEnumerator() => GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
}

View File

@ -1,22 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System;
namespace dnlib.DotNet.MD {
/// <summary>
/// Storage flags found in the MD header
/// </summary>
[Flags]
public enum StorageFlags : byte {
/// <summary>
/// Normal flags
/// </summary>
Normal = 0,
/// <summary>
/// More data after the header but before the streams.
/// </summary>
/// <remarks>The CLR will fail to load the file if this flag (or any other bits) is set.</remarks>
ExtraData = 1,
}
}

View File

@ -1,85 +0,0 @@
// dnlib: See LICENSE.txt for more info
using System;
using System.Diagnostics;
using System.Text;
using dnlib.IO;
namespace dnlib.DotNet.MD {
/// <summary>
/// A metadata stream header
/// </summary>
[DebuggerDisplay("O:{offset} L:{streamSize} {name}")]
public sealed class StreamHeader : FileSection {
readonly uint offset;
readonly uint streamSize;
readonly string name;
/// <summary>
/// The offset of the stream relative to the start of the metadata header
/// </summary>
public uint Offset => offset;
/// <summary>
/// The size of the stream
/// </summary>
public uint StreamSize => streamSize;
/// <summary>
/// The name of the stream
/// </summary>
public string Name => name;
/// <summary>
/// Constructor
/// </summary>
/// <param name="reader">PE file reader pointing to the start of this section</param>
/// <param name="verify">Verify section</param>
/// <exception cref="BadImageFormatException">Thrown if verification fails</exception>
public StreamHeader(ref DataReader reader, bool verify)
: this(ref reader, verify, verify, CLRRuntimeReaderKind.CLR, out _) {
}
internal StreamHeader(ref DataReader reader, bool throwOnError, bool verify, CLRRuntimeReaderKind runtime, out bool failedVerification) {
failedVerification = false;
SetStartOffset(ref reader);
offset = reader.ReadUInt32();
streamSize = reader.ReadUInt32();
name = ReadString(ref reader, 32, verify, ref failedVerification);
SetEndoffset(ref reader);
if (runtime == CLRRuntimeReaderKind.Mono) {
if (offset > reader.Length)
offset = reader.Length;
// Mono ignores the size (eg. it can be 0 or max value) so set it to the max possible value
streamSize = reader.Length - offset;
}
if (verify && offset + size < offset)
failedVerification = true;
if (throwOnError && failedVerification)
throw new BadImageFormatException("Invalid stream header");
}
internal StreamHeader(uint offset, uint streamSize, string name) {
this.offset = offset;
this.streamSize = streamSize;
this.name = name ?? throw new ArgumentNullException(nameof(name));
}
static string ReadString(ref DataReader reader, int maxLen, bool verify, ref bool failedVerification) {
var origPos = reader.Position;
var sb = new StringBuilder(maxLen);
int i;
for (i = 0; i < maxLen; i++) {
byte b = reader.ReadByte();
if (b == 0)
break;
sb.Append((char)b);
}
if (verify && i == maxLen)
failedVerification = true;
if (i != maxLen)
reader.Position = origPos + (((uint)i + 1 + 3) & ~3U);
return sb.ToString();
}
}
}

View File

@ -1,44 +0,0 @@
// dnlib: See LICENSE.txt for more info
using dnlib.IO;
namespace dnlib.DotNet.MD {
/// <summary>
/// Represents the #Strings stream
/// </summary>
public sealed class StringsStream : HeapStream {
/// <inheritdoc/>
public StringsStream() {
}
/// <inheritdoc/>
public StringsStream(DataReaderFactory mdReaderFactory, uint metadataBaseOffset, StreamHeader streamHeader)
: base(mdReaderFactory, metadataBaseOffset, streamHeader) {
}
/// <summary>
/// Reads a <see cref="UTF8String"/>
/// </summary>
/// <param name="offset">Offset of string</param>
/// <returns>A <see cref="UTF8String"/> instance or <c>null</c> if invalid offset</returns>
public UTF8String Read(uint offset) {
if (offset >= StreamLength)
return null;
byte[] data;
var reader = dataReader;
reader.Position = offset;
data = reader.TryReadBytesUntil(0);
if (data is null)
return null;
return new UTF8String(data);
}
/// <summary>
/// Reads a <see cref="UTF8String"/>. The empty string is returned if <paramref name="offset"/>
/// is invalid.
/// </summary>
/// <param name="offset">Offset of string</param>
/// <returns>A <see cref="UTF8String"/> instance</returns>
public UTF8String ReadNoNull(uint offset) => Read(offset) ?? UTF8String.Empty;
}
}

Some files were not shown because too many files have changed in this diff Show More