/* * PERWAPI - An API for Reading and Writing PE Files * * Copyright (c) Diane Corney, Queensland University of Technology, 2004. * * This program is free software; you can redistribute it and/or modify * it under the terms of the PERWAPI Copyright as included with this * distribution in the file PERWAPIcopyright.rtf. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY as is explained in the copyright notice. * * The author may be contacted at d.corney@qut.edu.au * * Version Date: 26/01/07 */ using System; using System.IO; using System.Collections; using System.Security.Cryptography; namespace QUT.PERWAPI { /**************************************************************************/ /// /// Base descriptor for signature blobs /// public class Signature : MetaDataElement { protected uint sigIx; protected byte[] sigBytes; /*-------------------- Constructors ---------------------------------*/ internal Signature() { tabIx = MDTable.StandAloneSig; } private Signature(uint sIx) { sigIx = sIx; } internal static void Read(PEReader buff, TableRow[] sigs) { for (int i = 0; i < sigs.Length; i++) { uint sigIx = buff.GetBlobIx(); uint tag = buff.FirstBlobByte(sigIx); if (tag == LocalSig.LocalSigByte) sigs[i] = new LocalSig(sigIx); else if (tag == Field.FieldTag) sigs[i] = new Signature(sigIx); else sigs[i] = new CalliSig(sigIx); sigs[i].Row = (uint)i + 1; } } internal override void Resolve(PEReader buff) { Type sigType = buff.GetFieldType(sigIx); buff.ReplaceSig(this, sigType); } internal static uint Size(MetaData md) { return md.BlobIndexSize(); } internal sealed override void Write(PEWriter output) { output.BlobIndex(sigIx); } internal sealed override uint GetCodedIx(CIx code) { return (uint)tabIx; } } /**************************************************************************/ /// /// Signature for calli instruction /// public class CalliSig : Signature { CallConv callConv; Type retType; Type[] parTypes, optParTypes; uint numPars = 0, numOptPars = 0; /*-------------------- Constructors ---------------------------------*/ /// /// Create a signature for a calli instruction /// /// calling conventions /// return type /// parameter types public CalliSig(CallConv cconv, Type retType, Type[] pars) { callConv = cconv; this.retType = retType; parTypes = pars; if (pars != null) numPars = (uint)pars.Length; } internal CalliSig(uint sigIx) { this.sigIx = sigIx; } /// /// The return type of the method being called. /// public Type ReturnType { get { return retType; } } /// /// The number of parameters on the method being called. /// public uint NumPars { get { return numPars; } } /// /// The number of optional parameters on the method being called. /// public uint NumOptPars { get { return numOptPars; } } /// /// Check to see if the method signature has a particular calling convention. /// /// The convention to check to see if the method has. /// Ture if the calling convention exists on the method. internal bool HasCallConv(CallConv callCon) { return ((callConv & callCon) == callCon); } internal sealed override void Resolve(PEReader buff) { MethSig mSig = buff.ReadMethSig(null, sigIx); callConv = mSig.callConv; retType = mSig.retType; parTypes = mSig.parTypes; if (parTypes != null) numPars = (uint)parTypes.Length; optParTypes = mSig.optParTypes; if (optParTypes != null) numOptPars = (uint)optParTypes.Length; } /// /// Add the optional parameters to a vararg method /// This method sets the vararg calling convention /// /// the optional pars for the vararg call public void AddVarArgs(Type[] optPars) { optParTypes = optPars; if (optPars != null) numOptPars = (uint)optPars.Length; callConv |= CallConv.Vararg; } /// /// Add extra calling conventions to this callsite signature /// /// public void AddCallingConv(CallConv cconv) { callConv |= cconv; } internal void ChangeRefsToDefs(ClassDef newType, ClassDef[] oldTypes) { for (int i = 0; i < oldTypes.Length; i++) { if (retType == oldTypes[i]) retType = newType; for (int j = 0; j < numPars; j++) { if (parTypes[j] == oldTypes[i]) parTypes[j] = newType; } for (int j = 0; j < numOptPars; j++) { if (optParTypes[j] == oldTypes[i]) optParTypes[j] = newType; } } } internal sealed override void BuildTables(MetaDataOut md) { md.AddToTable(MDTable.StandAloneSig, this); for (int i = 0; i < numPars; i++) { parTypes[i].BuildMDTables(md); } if (numOptPars > 0) { for (int i = 0; i < numOptPars; i++) { optParTypes[i].BuildMDTables(md); } } } internal sealed override void BuildSignatures(MetaDataOut md) { MemoryStream sig = new MemoryStream(); sig.WriteByte((byte)callConv); MetaDataOut.CompressNum(BlobUtil.CompressUInt(numPars + numOptPars), sig); retType.TypeSig(sig); for (int i = 0; i < numPars; i++) { parTypes[i].TypeSig(sig); } if (numOptPars > 0) { sig.WriteByte((byte)ElementType.Sentinel); for (int i = 0; i < numOptPars; i++) { optParTypes[i].TypeSig(sig); } } sigIx = md.AddToBlobHeap(sig.ToArray()); done = false; } } /**************************************************************************/ /// /// Descriptor for the locals for a method /// public class LocalSig : Signature { internal static readonly byte LocalSigByte = 0x7; Local[] locals; bool resolved = true; /*-------------------- Constructors ---------------------------------*/ public LocalSig(Local[] locals) { this.locals = locals; } internal LocalSig(uint sigIx) { resolved = false; this.sigIx = sigIx; } internal override void Resolve(PEReader buff) { } internal void Resolve(PEReader buff, MethodDef meth) { if (resolved) return; buff.currentMethodScope = meth; buff.currentClassScope = (Class)meth.GetParent(); locals = buff.ReadLocalSig(sigIx); buff.currentMethodScope = null; buff.currentClassScope = null; } internal Local[] GetLocals() { return locals; } internal sealed override void BuildTables(MetaDataOut md) { md.AddToTable(tabIx, this); for (int i = 0; i < locals.Length; i++) { locals[i].BuildTables(md); } } internal byte[] SigBytes() { MemoryStream sig = new MemoryStream(); sig.WriteByte(LocalSigByte); MetaDataOut.CompressNum(BlobUtil.CompressUInt((uint)locals.Length), sig); for (int i = 0; i < locals.Length; i++) { ((Local)locals[i]).TypeSig(sig); } return sig.ToArray(); } internal sealed override void BuildSignatures(MetaDataOut md) { sigIx = md.AddToBlobHeap(SigBytes()); done = false; } } /// /// Stores the signature for the debug info for a local variable. /// public class DebugLocalSig : Signature { internal static readonly byte LocalSigByte = 0x6; bool resolved = true; byte[] loc; /*-------------------- Constructors ---------------------------------*/ internal DebugLocalSig(byte[] loc) { this.loc = loc; } internal DebugLocalSig(uint sigIx) { resolved = false; this.sigIx = sigIx; } internal override void Resolve(PEReader buff) { } internal void Resolve(PEReader buff, MethodDef meth) { if (resolved) return; } internal sealed override void BuildTables(MetaDataOut md) { md.AddToTable(tabIx, this); } internal byte[] SigBytes() { byte[] b = new byte[loc.Length + 1]; b[0] = LocalSigByte; System.Array.Copy(loc, 0, b, 1, loc.Length); return b; } internal sealed override void BuildSignatures(MetaDataOut md) { sigIx = md.AddToBlobHeap(SigBytes()); done = false; } } }