// dnlib: See LICENSE.txt for more info
using System;
using System.Collections.Generic;
using System.Diagnostics;
using dnlib.PE;
namespace dnlib.DotNet {
///
/// All native vtables
///
[DebuggerDisplay("RVA = {RVA}, Count = {VTables.Count}")]
public sealed class VTableFixups : IEnumerable {
RVA rva;
IList vtables;
///
/// Gets/sets the RVA of the vtable fixups
///
public RVA RVA {
get => rva;
set => rva = value;
}
///
/// Gets all s
///
public IList VTables => vtables;
///
/// Default constructor
///
public VTableFixups() => vtables = new List();
///
/// Constructor
///
/// Module
public VTableFixups(ModuleDefMD module) => Initialize(module);
void Initialize(ModuleDefMD module) {
var info = module.Metadata.ImageCor20Header.VTableFixups;
if (info.VirtualAddress == 0 || info.Size == 0) {
vtables = new List();
return;
}
rva = info.VirtualAddress;
vtables = new List((int)info.Size / 8);
var peImage = module.Metadata.PEImage;
var reader = peImage.CreateReader();
reader.Position = (uint)peImage.ToFileOffset(info.VirtualAddress);
ulong endPos = (ulong)reader.Position + info.Size;
while ((ulong)reader.Position + 8 <= endPos && reader.CanRead(8U)) {
var tableRva = (RVA)reader.ReadUInt32();
int numSlots = reader.ReadUInt16();
var flags = (VTableFlags)reader.ReadUInt16();
var vtable = new VTable(tableRva, flags, numSlots);
vtables.Add(vtable);
var pos = reader.Position;
reader.Position = (uint)peImage.ToFileOffset(tableRva);
uint slotSize = vtable.Is64Bit ? 8U : 4;
while (numSlots-- > 0 && reader.CanRead(slotSize)) {
vtable.Methods.Add(module.ResolveToken(reader.ReadUInt32()) as IMethod);
if (slotSize == 8)
reader.ReadUInt32();
}
reader.Position = pos;
}
}
///
public IEnumerator GetEnumerator() => vtables.GetEnumerator();
///
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => GetEnumerator();
}
///
/// See COR_VTABLE_XXX in CorHdr.h
///
[Flags]
public enum VTableFlags : ushort {
///
/// 32-bit vtable slots
///
Bit32 = 0x01,
///
/// 64-bit vtable slots
///
Bit64 = 0x02,
///
/// Transition from unmanaged code
///
FromUnmanaged = 0x04,
///
/// Also retain app domain
///
FromUnmanagedRetainAppDomain = 0x08,
///
/// Call most derived method
///
CallMostDerived = 0x10,
}
///
/// One VTable accessed by native code
///
public sealed class VTable : IEnumerable {
RVA rva;
VTableFlags flags;
readonly IList methods;
///
/// Gets/sets the of this vtable
///
public RVA RVA {
get => rva;
set => rva = value;
}
///
/// Gets/sets the flags
///
public VTableFlags Flags {
get => flags;
set => flags = value;
}
///
/// true if each vtable slot is 32 bits in size
///
public bool Is32Bit => (flags & VTableFlags.Bit32) != 0;
///
/// true if each vtable slot is 64 bits in size
///
public bool Is64Bit => (flags & VTableFlags.Bit64) != 0;
///
/// Gets the vtable methods
///
public IList Methods => methods;
///
/// Default constructor
///
public VTable() => methods = new List();
///
/// Constructor
///
/// Flags
public VTable(VTableFlags flags) {
this.flags = flags;
methods = new List();
}
///
/// Constructor
///
/// RVA of this vtable
/// Flgas
/// Number of methods in vtable
public VTable(RVA rva, VTableFlags flags, int numSlots) {
this.rva = rva;
this.flags = flags;
methods = new List(numSlots);
}
///
/// Constructor
///
/// RVA of this vtable
/// Flgas
/// Vtable methods
public VTable(RVA rva, VTableFlags flags, IEnumerable methods) {
this.rva = rva;
this.flags = flags;
this.methods = new List(methods);
}
///
public IEnumerator GetEnumerator() => methods.GetEnumerator();
///
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => GetEnumerator();
///
public override string ToString() {
if (methods.Count == 0)
return $"{methods.Count} {(uint)rva:X8}";
return $"{methods.Count} {(uint)rva:X8} {methods[0]}";
}
}
}