de4dot-cex/blocks/DotNetUtils.cs

1366 lines
42 KiB
C#
Raw Normal View History

2011-09-22 10:55:30 +08:00
/*
2012-01-10 06:02:47 +08:00
Copyright (C) 2011-2012 de4dot@gmail.com
2011-09-22 10:55:30 +08:00
This file is part of de4dot.
de4dot is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
de4dot is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with de4dot. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
2012-11-04 07:50:24 +08:00
using dot10.DotNet;
using dot10.DotNet.Emit;
2012-11-01 01:52:50 +08:00
2011-09-24 16:26:29 +08:00
namespace de4dot.blocks {
2012-03-17 02:13:27 +08:00
public enum FrameworkType {
2012-03-16 02:03:22 +08:00
Unknown,
Desktop,
Silverlight, // and WindowsPhone, XNA Xbox360
CompactFramework,
2012-03-21 10:20:59 +08:00
XNA,
2012-03-16 02:03:22 +08:00
Zune,
}
2012-11-02 15:23:20 +08:00
#if PORT
class TypeCache {
ModuleDefinition module;
2012-11-01 04:07:57 +08:00
de4dot.blocks.OLD_REMOVE.TypeDefinitionDict<TypeDefinition> typeRefToDef = new de4dot.blocks.OLD_REMOVE.TypeDefinitionDict<TypeDefinition>();
public TypeCache(ModuleDefinition module) {
this.module = module;
init();
}
void init() {
foreach (var type in module.GetTypes())
typeRefToDef.add(type, type);
}
public TypeDefinition lookup(TypeReference typeReference) {
return typeRefToDef.find(typeReference);
}
}
2012-11-02 15:23:20 +08:00
#endif
2012-11-02 15:23:20 +08:00
#if PORT
public class TypeCaches {
Dictionary<ModuleDefinition, TypeCache> typeCaches = new Dictionary<ModuleDefinition, TypeCache>();
// Should be called when the whole module is reloaded or when a lot of types have been
// modified (eg. renamed)
public void invalidate(ModuleDefinition module) {
if (module == null)
return;
typeCaches.Remove(module);
}
// Call this to invalidate all modules
2011-11-17 05:56:36 +08:00
public List<ModuleDefinition> invalidateAll() {
var list = new List<ModuleDefinition>(typeCaches.Keys);
typeCaches.Clear();
2011-11-17 05:56:36 +08:00
return list;
}
public TypeDefinition lookup(ModuleDefinition module, TypeReference typeReference) {
TypeCache typeCache;
if (!typeCaches.TryGetValue(module, out typeCache))
typeCaches[module] = typeCache = new TypeCache(module);
return typeCache.lookup(typeReference);
}
}
2012-11-02 15:23:20 +08:00
#endif
2011-09-24 16:26:29 +08:00
public class CallCounter {
2012-11-18 01:57:36 +08:00
Dictionary<IMethod, int> calls = new Dictionary<IMethod, int>(MethodEqualityComparer.CompareDeclaringTypes);
2011-09-22 10:55:30 +08:00
2012-11-18 01:57:36 +08:00
public void add(IMethod calledMethod) {
2011-09-22 10:55:30 +08:00
int count;
2012-11-18 01:57:36 +08:00
calls.TryGetValue(calledMethod, out count);
calls[calledMethod] = count + 1;
2011-09-22 10:55:30 +08:00
}
2012-11-18 01:57:36 +08:00
public IMethod most() {
2011-11-26 19:34:17 +08:00
int numCalls;
return most(out numCalls);
}
2012-11-18 01:57:36 +08:00
public IMethod most(out int numCalls) {
IMethod method = null;
2011-09-22 10:55:30 +08:00
int callCount = 0;
foreach (var key in calls.Keys) {
if (calls[key] > callCount) {
callCount = calls[key];
2012-11-18 01:57:36 +08:00
method = key;
2011-09-22 10:55:30 +08:00
}
}
2011-11-26 19:34:17 +08:00
numCalls = callCount;
2011-09-22 10:55:30 +08:00
return method;
}
}
2012-11-02 15:23:20 +08:00
#if PORT
2011-09-24 16:26:29 +08:00
public class MethodCalls {
2011-09-22 10:55:30 +08:00
Dictionary<string, int> methodCalls = new Dictionary<string, int>(StringComparer.Ordinal);
2012-11-06 23:30:39 +08:00
public void addMethodCalls(MethodDef method) {
2011-09-22 10:55:30 +08:00
if (!method.HasBody)
return;
2012-11-06 23:30:39 +08:00
foreach (var instr in method.Body.Instructions) {
2011-09-22 10:55:30 +08:00
var calledMethod = instr.Operand as MethodReference;
if (calledMethod != null)
add(calledMethod);
}
}
public void add(MethodReference method) {
string key = method.FullName;
if (!methodCalls.ContainsKey(key))
methodCalls[key] = 0;
methodCalls[key]++;
}
public int count(string methodFullName) {
int count;
methodCalls.TryGetValue(methodFullName, out count);
return count;
}
public bool called(string methodFullName) {
return count(methodFullName) != 0;
}
}
2012-11-02 15:23:20 +08:00
#endif
2011-09-22 10:55:30 +08:00
2011-09-24 16:26:29 +08:00
public static class DotNetUtils {
2012-11-02 15:23:20 +08:00
#if PORT
public static readonly TypeCaches typeCaches = new TypeCaches();
2012-11-02 15:23:20 +08:00
#endif
2012-11-04 07:50:24 +08:00
public static TypeDef getModuleType(ModuleDef module) {
2012-11-01 16:10:06 +08:00
return module.GlobalType;
2011-09-22 10:55:30 +08:00
}
2012-11-04 07:50:24 +08:00
public static MethodDef getModuleTypeCctor(ModuleDef module) {
2012-11-17 06:50:52 +08:00
return module.GlobalType.FindStaticConstructor();
2012-01-22 18:15:14 +08:00
}
2012-11-04 07:50:24 +08:00
public static bool isEmpty(MethodDef method) {
if (method.Body == null)
2011-09-22 10:55:30 +08:00
return false;
foreach (var instr in method.Body.Instructions) {
2011-09-22 10:55:30 +08:00
var code = instr.OpCode.Code;
2012-11-04 07:50:24 +08:00
if (code != Code.Nop && code != Code.Ret)
2011-09-22 10:55:30 +08:00
return false;
}
return true;
}
2012-11-04 07:50:24 +08:00
public static bool isEmptyObfuscated(MethodDef method) {
if (method.Body == null)
2011-11-24 17:35:42 +08:00
return false;
int index = 0;
var instr = getInstruction(method.Body.Instructions, ref index);
2012-11-04 07:50:24 +08:00
if (instr == null || instr.OpCode.Code != Code.Ret)
2011-11-24 17:35:42 +08:00
return false;
return true;
}
2012-11-09 05:24:13 +08:00
public static FieldDef findFieldType(TypeDef typeDefinition, string typeName, bool isStatic) {
2011-09-22 10:55:30 +08:00
if (typeDefinition == null)
return null;
foreach (var field in typeDefinition.Fields) {
2012-11-09 05:24:13 +08:00
if (field.IsStatic == isStatic && field.FieldSig.GetFieldType().GetFullName() == typeName)
2011-09-22 10:55:30 +08:00
return field;
}
return null;
}
2012-11-06 23:30:39 +08:00
public static IEnumerable<MethodDef> findMethods(IEnumerable<MethodDef> methods, string returnType, string[] argsTypes) {
2012-07-07 13:11:32 +08:00
return findMethods(methods, returnType, argsTypes, true);
}
2012-11-06 23:30:39 +08:00
public static IEnumerable<MethodDef> findMethods(IEnumerable<MethodDef> methods, string returnType, string[] argsTypes, bool isStatic) {
2011-09-22 10:55:30 +08:00
foreach (var method in methods) {
2012-11-06 23:30:39 +08:00
var sig = method.MethodSig;
if (sig == null || !method.HasBody || !sig.IsDefault)
2011-09-22 10:55:30 +08:00
continue;
2012-11-07 12:17:45 +08:00
if (method.IsStatic != isStatic || sig.Params.Count != argsTypes.Length)
2011-09-22 10:55:30 +08:00
continue;
2012-11-06 23:30:39 +08:00
if (sig.GenParamCount > 0)
2011-09-22 10:55:30 +08:00
continue;
2012-11-06 23:30:39 +08:00
if (sig.RetType.GetFullName() != returnType)
2011-09-22 10:55:30 +08:00
continue;
for (int i = 0; i < argsTypes.Length; i++) {
2012-11-06 23:30:39 +08:00
if (sig.Params[i].GetFullName() != argsTypes[i])
2011-09-22 10:55:30 +08:00
goto next;
}
yield return method;
next: ;
}
}
2012-11-04 07:50:24 +08:00
public static bool isDelegate(IType type) {
2012-11-01 16:10:06 +08:00
if (type == null)
return false;
var fn = type.FullName;
return fn == "System.Delegate" || fn == "System.MulticastDelegate";
2011-11-04 07:06:25 +08:00
}
2012-11-04 07:50:24 +08:00
public static bool derivesFromDelegate(TypeDef type) {
2011-11-04 07:06:25 +08:00
return type != null && isDelegate(type.BaseType);
2011-09-22 10:55:30 +08:00
}
2012-11-02 15:23:20 +08:00
#if PORT
2011-09-27 07:48:47 +08:00
public static bool isSameAssembly(TypeReference type, string assembly) {
return MemberReferenceHelper.getCanonicalizedScopeName(type.Scope) == assembly.ToLowerInvariant();
}
2011-09-22 10:55:30 +08:00
public static bool isMethod(MethodReference method, string returnType, string parameters) {
return method != null && method.FullName == returnType + " " + method.DeclaringType.FullName + "::" + method.Name + parameters;
}
2012-11-02 15:23:20 +08:00
#endif
2011-09-22 10:55:30 +08:00
2012-11-04 07:50:24 +08:00
public static bool isMethod(IMethod method, string returnType, string parameters) {
2012-11-01 21:39:39 +08:00
return method != null && method.FullName == returnType + " " + method.DeclaringType.FullName + "::" + method.Name + parameters;
}
2012-11-04 07:50:24 +08:00
public static string getDllName(string dll) {
if (dll.EndsWith(".dll", StringComparison.OrdinalIgnoreCase))
return dll.Substring(0, dll.Length - 4);
return dll;
}
2012-11-07 12:17:45 +08:00
public static bool hasPinvokeMethod(TypeDef type, string methodName) {
2012-04-26 07:14:46 +08:00
return getPInvokeMethod(type, methodName) != null;
}
2012-11-07 12:17:45 +08:00
public static MethodDef getPInvokeMethod(TypeDef type, string methodName) {
2012-04-26 07:14:46 +08:00
if (type == null)
return null;
2012-11-07 12:17:45 +08:00
var mname = new UTF8String(methodName);
2012-04-26 07:14:46 +08:00
foreach (var method in type.Methods) {
2012-11-07 12:17:45 +08:00
if (method.ImplMap == null)
2012-04-26 07:14:46 +08:00
continue;
2012-11-07 12:17:45 +08:00
if (UTF8String.Equals(method.ImplMap.Name, mname))
2012-04-26 07:14:46 +08:00
return method;
}
return null;
}
2012-11-08 16:48:05 +08:00
public static MethodDef getPInvokeMethod(TypeDef type, string dll, string funcName) {
2011-09-22 10:55:30 +08:00
foreach (var method in type.Methods) {
if (isPinvokeMethod(method, dll, funcName))
return method;
}
return null;
}
2012-11-06 23:30:39 +08:00
public static bool isPinvokeMethod(MethodDef method, string dll, string funcName) {
2011-09-22 10:55:30 +08:00
if (method == null)
return false;
2012-11-08 16:48:05 +08:00
if (method.ImplMap == null || method.ImplMap.Name.String != funcName)
2011-09-22 10:55:30 +08:00
return false;
2012-11-17 06:50:52 +08:00
return getDllName(dll).Equals(getDllName(method.ImplMap.Module.Name.String), StringComparison.OrdinalIgnoreCase);
2011-09-22 10:55:30 +08:00
}
2012-11-08 16:48:05 +08:00
#if PORT
2012-11-06 23:30:39 +08:00
public static MethodDef getMethod(TypeDefinition type, string name) {
2011-09-22 10:55:30 +08:00
if (type == null)
return null;
foreach (var method in type.Methods) {
if (method.Name == name)
return method;
}
return null;
}
2012-11-06 23:30:39 +08:00
public static MethodDef getMethod(TypeDefinition type, MethodReference methodReference) {
2011-09-22 10:55:30 +08:00
if (type == null || methodReference == null)
return null;
2012-11-06 23:30:39 +08:00
if (methodReference is MethodDef)
return (MethodDef)methodReference;
2011-09-22 10:55:30 +08:00
foreach (var method in type.Methods) {
if (MemberReferenceHelper.compareMethodReference(method, methodReference))
return method;
}
return null;
}
2012-11-18 01:57:36 +08:00
#endif
2011-09-22 10:55:30 +08:00
2012-11-18 01:57:36 +08:00
public static MethodDef getMethod(ModuleDefMD module, IMethod method) {
2012-07-08 14:12:41 +08:00
if (method == null)
return null;
return getMethod(module, method, method.DeclaringType);
}
2012-11-08 14:43:57 +08:00
public static MethodDef getMethod2(ModuleDefMD module, IMethod method) {
2012-07-08 14:12:41 +08:00
if (method == null)
return null;
2012-11-08 14:43:57 +08:00
if (method is MethodDef)
return (MethodDef)method;
var git = method.DeclaringType.ToGenericInstSig();
var dt = git == null ? method.DeclaringType : git.GenericType.TypeDefOrRef;
return getMethod(module, method, dt);
2012-07-08 14:12:41 +08:00
}
2012-11-08 14:43:57 +08:00
static MethodDef getMethod(ModuleDefMD module, IMethod method, ITypeDefOrRef declaringType) {
2011-09-22 10:55:30 +08:00
if (method == null)
return null;
2012-11-06 23:30:39 +08:00
if (method is MethodDef)
return (MethodDef)method;
2012-07-08 14:12:41 +08:00
return getMethod(getType(module, declaringType), method);
2011-09-22 10:55:30 +08:00
}
2012-11-07 08:52:15 +08:00
public static MethodDef getMethod(TypeDef type, string returnType, string parameters) {
2011-12-29 15:21:19 +08:00
foreach (var method in type.Methods) {
if (isMethod(method, returnType, parameters))
return method;
}
return null;
}
2012-11-04 07:50:24 +08:00
public static MethodDef getMethod2(ModuleDef module, IMethod method) {
2012-11-01 18:28:09 +08:00
if (method == null)
return null;
return getMethod(module, method, method.DeclaringType.ScopeType);
}
2012-11-07 00:15:11 +08:00
public static TypeDef getType(ModuleDef module, TypeSig type) {
type = type.RemovePinnedAndModifiers();
var tdr = type as TypeDefOrRefSig;
if (tdr == null)
return null;
return getType(module, tdr.TypeDefOrRef);
}
2012-11-01 18:28:09 +08:00
2012-11-07 00:15:11 +08:00
public static TypeDef getType(ModuleDef module, ITypeDefOrRef type) {
var td = type as TypeDef;
if (td == null) {
var tr = type as TypeRef;
if (tr != null) {
var trAsm = tr.DefinitionAssembly;
var modAsm = module.Assembly;
if (trAsm != null && modAsm != null && trAsm.Name == modAsm.Name)
td = tr.Resolve();
}
}
2012-11-17 06:50:52 +08:00
return td != null && td.Module == module ? td : null;
2012-11-01 18:28:09 +08:00
}
2012-11-04 07:50:24 +08:00
static MethodDef getMethod(ModuleDef module, IMethod method, ITypeDefOrRef declaringType) {
2012-11-01 18:28:09 +08:00
if (method == null)
return null;
2012-11-04 07:50:24 +08:00
if (method is MethodDef)
return (MethodDef)method;
2012-11-01 18:28:09 +08:00
return getMethod(getType(module, declaringType), method);
}
2012-11-04 07:50:24 +08:00
public static MethodDef getMethod(TypeDef type, IMethod methodRef) {
2012-11-01 18:28:09 +08:00
if (type == null || methodRef == null)
return null;
2012-11-04 07:50:24 +08:00
if (methodRef is MethodDef)
return (MethodDef)methodRef;
2012-11-01 18:28:09 +08:00
return type.FindMethod(methodRef.Name, methodRef.MethodSig);
}
2012-11-02 15:23:20 +08:00
#if PORT
2012-11-06 23:30:39 +08:00
public static IEnumerable<MethodDef> getNormalMethods(TypeDefinition type) {
2011-09-22 10:55:30 +08:00
foreach (var method in type.Methods) {
if (method.HasPInvokeInfo)
continue;
if (method.Name == ".ctor" || method.Name == ".cctor")
continue;
yield return method;
}
}
public static TypeDefinition getType(ModuleDefinition module, TypeReference typeReference) {
if (typeReference == null)
return null;
if (typeReference is TypeDefinition)
return (TypeDefinition)typeReference;
return typeCaches.lookup(module, typeReference);
2011-09-22 10:55:30 +08:00
}
public static FieldDefinition getField(ModuleDefinition module, FieldReference field) {
2012-01-17 09:51:23 +08:00
if (field == null)
return null;
2011-09-22 10:55:30 +08:00
if (field is FieldDefinition)
return (FieldDefinition)field;
return getField(getType(module, field.DeclaringType), field);
}
2012-11-08 14:06:46 +08:00
#endif
2011-09-22 10:55:30 +08:00
2012-11-08 14:06:46 +08:00
public static FieldDef getField(TypeDef type, IField fieldReference) {
2011-09-22 10:55:30 +08:00
if (type == null || fieldReference == null)
return null;
2012-11-08 14:06:46 +08:00
if (fieldReference is FieldDef)
return (FieldDef)fieldReference;
return type.FindField(fieldReference.Name, fieldReference.FieldSig);
2011-09-22 10:55:30 +08:00
}
2012-11-08 16:48:05 +08:00
public static FieldDef getField(TypeDef type, string typeFullName) {
if (type == null)
return null;
foreach (var field in type.Fields) {
2012-11-08 16:48:05 +08:00
if (field.FieldSig.GetFieldType().GetFullName() == typeFullName)
return field;
}
return null;
}
2012-11-08 16:48:05 +08:00
#if PORT
public static FieldDefinition getFieldByName(TypeDefinition type, string name) {
2012-01-11 09:32:36 +08:00
if (type == null)
return null;
foreach (var field in type.Fields) {
if (field.Name == name)
return field;
}
return null;
}
2012-11-06 23:30:39 +08:00
public static IEnumerable<MethodReference> getMethodCalls(MethodDef method) {
2011-09-22 10:55:30 +08:00
var list = new List<MethodReference>();
if (method.HasBody) {
2012-11-06 23:30:39 +08:00
foreach (var instr in method.Body.Instructions) {
2011-09-22 10:55:30 +08:00
var calledMethod = instr.Operand as MethodReference;
if (calledMethod != null)
list.Add(calledMethod);
}
}
return list;
}
2012-11-06 23:30:39 +08:00
public static MethodCalls getMethodCallCounts(MethodDef method) {
2011-09-22 10:55:30 +08:00
var methodCalls = new MethodCalls();
methodCalls.addMethodCalls(method);
return methodCalls;
}
2012-11-06 23:30:39 +08:00
public static bool hasString(MethodDef method, string s) {
if (method == null || method.Body == null)
2012-04-05 03:06:10 +08:00
return false;
2012-11-06 23:30:39 +08:00
foreach (var instr in method.Body.Instructions) {
2012-04-05 03:06:10 +08:00
if (instr.OpCode.Code == Code.Ldstr && (string)instr.Operand == s)
return true;
}
return false;
}
2012-11-06 23:30:39 +08:00
public static IList<string> getCodeStrings(MethodDef method) {
2011-09-22 10:55:30 +08:00
var strings = new List<string>();
2012-11-06 23:30:39 +08:00
if (method != null && method.Body != null) {
foreach (var instr in method.Body.Instructions) {
2011-09-22 10:55:30 +08:00
if (instr.OpCode.Code == Code.Ldstr)
2012-11-01 21:39:39 +08:00
strings.Add((string)instr.Operand);
}
}
return strings;
}
2012-11-02 15:23:20 +08:00
#endif
2012-11-01 21:39:39 +08:00
2012-11-04 07:50:24 +08:00
public static IList<string> getCodeStrings(MethodDef method) {
2012-11-01 21:39:39 +08:00
var strings = new List<string>();
if (method != null && method.Body != null) {
foreach (var instr in method.Body.Instructions) {
2012-11-04 07:50:24 +08:00
if (instr.OpCode.Code == Code.Ldstr)
2011-09-22 10:55:30 +08:00
strings.Add((string)instr.Operand);
}
}
return strings;
}
2012-11-04 07:50:24 +08:00
public static Resource getResource(ModuleDef module, string name) {
2011-09-22 10:55:30 +08:00
return getResource(module, new List<string> { name });
}
2012-11-04 07:50:24 +08:00
public static Resource getResource(ModuleDef module, IEnumerable<string> strings) {
2011-09-22 10:55:30 +08:00
if (!module.HasResources)
return null;
var resources = module.Resources;
foreach (var tmp in strings) {
var resourceName = removeFromNullChar(tmp);
2011-09-22 10:55:30 +08:00
if (resourceName == null)
continue;
2012-11-04 07:50:24 +08:00
var name = new UTF8String(resourceName);
2011-09-22 10:55:30 +08:00
foreach (var resource in resources) {
2012-11-04 07:50:24 +08:00
if (UTF8String.Equals(resource.Name, name))
2011-09-22 10:55:30 +08:00
return resource;
}
}
return null;
}
static string removeFromNullChar(string s) {
int index = s.IndexOf((char)0);
if (index < 0)
return s;
return s.Substring(0, index);
}
2012-11-02 15:23:20 +08:00
#if PORT
2012-05-02 19:48:44 +08:00
// Copies most things but not everything
2012-11-06 23:30:39 +08:00
public static MethodDef clone(MethodDef method) {
var newMethod = new MethodDef(method.Name, method.Attributes, method.MethodReturnType.ReturnType);
2012-05-02 19:48:44 +08:00
newMethod.MetadataToken = method.MetadataToken;
newMethod.Attributes = method.Attributes;
newMethod.ImplAttributes = method.ImplAttributes;
newMethod.HasThis = method.HasThis;
newMethod.ExplicitThis = method.ExplicitThis;
newMethod.CallingConvention = method.CallingConvention;
newMethod.SemanticsAttributes = method.SemanticsAttributes;
newMethod.DeclaringType = method.DeclaringType;
foreach (var arg in method.Parameters)
newMethod.Parameters.Add(new ParameterDefinition(arg.Name, arg.Attributes, arg.ParameterType));
foreach (var gp in method.GenericParameters)
newMethod.GenericParameters.Add(new GenericParameter(gp.Name, newMethod) { Attributes = gp.Attributes });
2012-05-10 00:26:19 +08:00
copyBodyFromTo(method, newMethod);
2012-05-02 19:48:44 +08:00
return newMethod;
}
2012-11-02 15:23:20 +08:00
#endif
2012-05-02 19:48:44 +08:00
2012-11-01 01:52:50 +08:00
// Copies most things but not everything
2012-11-04 07:50:24 +08:00
public static MethodDef clone(MethodDef method) {
2012-11-17 06:50:52 +08:00
var newMethod = new MethodDefUser(method.Name, method.MethodSig, method.ImplAttributes, method.Attributes);
2012-11-04 19:54:05 +08:00
newMethod.Rid = method.Rid;
newMethod.DeclaringType2 = method.DeclaringType;
foreach (var pd in method.ParamList)
2012-11-17 06:50:52 +08:00
newMethod.ParamList.Add(new ParamDefUser(pd.Name, pd.Sequence, pd.Attributes));
foreach (var gp in method.GenericParameters) {
2012-11-04 19:54:05 +08:00
var newGp = new GenericParamUser(gp.Number, gp.Flags, gp.Name);
foreach (var gpc in newGp.GenericParamConstraints)
newGp.GenericParamConstraints.Add(new GenericParamConstraintUser(gpc.Constraint));
2012-11-17 06:50:52 +08:00
newMethod.GenericParameters.Add(newGp);
2012-11-04 19:54:05 +08:00
}
2012-11-09 07:21:45 +08:00
newMethod.Body = new CilBody();
2012-11-04 19:54:05 +08:00
copyBodyFromTo(method, newMethod);
2012-11-09 07:21:45 +08:00
return newMethod;
2012-11-01 01:52:50 +08:00
}
2012-11-02 15:23:20 +08:00
#if PORT
2011-10-24 18:45:20 +08:00
public static Instruction clone(Instruction instr) {
return new Instruction {
Offset = instr.Offset,
OpCode = instr.OpCode,
Operand = instr.Operand,
SequencePoint = instr.SequencePoint,
};
}
2012-11-06 23:30:39 +08:00
public static void copyBody(MethodDef method, out IList<Instruction> instructions, out IList<ExceptionHandler> exceptionHandlers) {
2011-09-22 10:55:30 +08:00
if (method == null || !method.HasBody) {
instructions = new List<Instruction>();
exceptionHandlers = new List<ExceptionHandler>();
return;
}
2012-11-06 23:30:39 +08:00
var oldInstrs = method.Body.Instructions;
var oldExHandlers = method.Body.ExceptionHandlers;
2011-09-22 10:55:30 +08:00
instructions = new List<Instruction>(oldInstrs.Count);
exceptionHandlers = new List<ExceptionHandler>(oldExHandlers.Count);
var oldToIndex = Utils.createObjectToIndexDictionary(oldInstrs);
2011-10-24 18:45:20 +08:00
foreach (var oldInstr in oldInstrs)
instructions.Add(clone(oldInstr));
2011-09-22 10:55:30 +08:00
foreach (var newInstr in instructions) {
var operand = newInstr.Operand;
if (operand is Instruction)
newInstr.Operand = instructions[oldToIndex[(Instruction)operand]];
else if (operand is Instruction[]) {
var oldArray = (Instruction[])operand;
var newArray = new Instruction[oldArray.Length];
for (int i = 0; i < oldArray.Length; i++)
newArray[i] = instructions[oldToIndex[oldArray[i]]];
newInstr.Operand = newArray;
}
}
foreach (var oldEx in oldExHandlers) {
var newEx = new ExceptionHandler(oldEx.HandlerType) {
TryStart = getInstruction(instructions, oldToIndex, oldEx.TryStart),
TryEnd = getInstruction(instructions, oldToIndex, oldEx.TryEnd),
FilterStart = getInstruction(instructions, oldToIndex, oldEx.FilterStart),
HandlerStart= getInstruction(instructions, oldToIndex, oldEx.HandlerStart),
HandlerEnd = getInstruction(instructions, oldToIndex, oldEx.HandlerEnd),
CatchType = oldEx.CatchType,
};
exceptionHandlers.Add(newEx);
}
}
static Instruction getInstruction(IList<Instruction> instructions, IDictionary<Instruction, int> instructionToIndex, Instruction instruction) {
if (instruction == null)
return null;
return instructions[instructionToIndex[instruction]];
}
2012-11-02 15:23:20 +08:00
#endif
2011-09-22 10:55:30 +08:00
2012-11-04 07:50:24 +08:00
public static void copyBody(MethodDef method, out IList<Instruction> instructions, out IList<ExceptionHandler> exceptionHandlers) {
if (method == null || !method.HasBody) {
2012-11-04 07:50:24 +08:00
instructions = new List<Instruction>();
exceptionHandlers = new List<ExceptionHandler>();
2012-11-02 15:23:20 +08:00
return;
}
var oldInstrs = method.Body.Instructions;
var oldExHandlers = method.Body.ExceptionHandlers;
2012-11-04 07:50:24 +08:00
instructions = new List<Instruction>(oldInstrs.Count);
exceptionHandlers = new List<ExceptionHandler>(oldExHandlers.Count);
2012-11-02 15:23:20 +08:00
var oldToIndex = Utils.createObjectToIndexDictionary(oldInstrs);
foreach (var oldInstr in oldInstrs)
instructions.Add(oldInstr.Clone());
foreach (var newInstr in instructions) {
var operand = newInstr.Operand;
2012-11-04 07:50:24 +08:00
if (operand is Instruction)
newInstr.Operand = instructions[oldToIndex[(Instruction)operand]];
else if (operand is IList<Instruction>) {
var oldArray = (IList<Instruction>)operand;
var newArray = new Instruction[oldArray.Count];
2012-11-02 15:23:20 +08:00
for (int i = 0; i < oldArray.Count; i++)
newArray[i] = instructions[oldToIndex[oldArray[i]]];
newInstr.Operand = newArray;
}
}
foreach (var oldEx in oldExHandlers) {
2012-11-04 07:50:24 +08:00
var newEx = new ExceptionHandler(oldEx.HandlerType) {
2012-11-02 15:23:20 +08:00
TryStart = getInstruction(instructions, oldToIndex, oldEx.TryStart),
TryEnd = getInstruction(instructions, oldToIndex, oldEx.TryEnd),
FilterStart = getInstruction(instructions, oldToIndex, oldEx.FilterStart),
HandlerStart = getInstruction(instructions, oldToIndex, oldEx.HandlerStart),
HandlerEnd = getInstruction(instructions, oldToIndex, oldEx.HandlerEnd),
CatchType = oldEx.CatchType,
};
exceptionHandlers.Add(newEx);
}
}
2012-11-04 07:50:24 +08:00
static Instruction getInstruction(IList<Instruction> instructions, IDictionary<Instruction, int> instructionToIndex, Instruction instruction) {
2012-11-02 15:23:20 +08:00
if (instruction == null)
return null;
return instructions[instructionToIndex[instruction]];
}
#if PORT
2012-11-06 23:30:39 +08:00
public static void restoreBody(MethodDef method, IEnumerable<Instruction> instructions, IEnumerable<ExceptionHandler> exceptionHandlers) {
2011-09-22 10:55:30 +08:00
if (method == null || !method.HasBody)
return;
2012-11-06 23:30:39 +08:00
var bodyInstrs = method.Body.Instructions;
2011-09-22 10:55:30 +08:00
bodyInstrs.Clear();
foreach (var instr in instructions)
bodyInstrs.Add(instr);
2012-11-06 23:30:39 +08:00
var bodyExceptionHandlers = method.Body.ExceptionHandlers;
2011-09-22 10:55:30 +08:00
bodyExceptionHandlers.Clear();
foreach (var eh in exceptionHandlers)
bodyExceptionHandlers.Add(eh);
}
2012-11-02 15:23:20 +08:00
#endif
2012-11-01 01:52:50 +08:00
2012-11-04 07:50:24 +08:00
public static void restoreBody(MethodDef method, IEnumerable<Instruction> instructions, IEnumerable<ExceptionHandler> exceptionHandlers) {
if (method == null || method.Body == null)
2012-11-01 01:52:50 +08:00
return;
var bodyInstrs = method.Body.Instructions;
2012-11-01 01:52:50 +08:00
bodyInstrs.Clear();
foreach (var instr in instructions)
bodyInstrs.Add(instr);
var bodyExceptionHandlers = method.Body.ExceptionHandlers;
2012-11-01 01:52:50 +08:00
bodyExceptionHandlers.Clear();
foreach (var eh in exceptionHandlers)
bodyExceptionHandlers.Add(eh);
}
2012-11-04 19:54:05 +08:00
public static void copyBodyFromTo(MethodDef fromMethod, MethodDef toMethod) {
2012-02-03 11:24:43 +08:00
if (fromMethod == toMethod)
return;
IList<Instruction> instructions;
IList<ExceptionHandler> exceptionHandlers;
copyBody(fromMethod, out instructions, out exceptionHandlers);
restoreBody(toMethod, instructions, exceptionHandlers);
copyLocalsFromTo(fromMethod, toMethod);
updateInstructionOperands(fromMethod, toMethod);
}
2012-11-04 19:54:05 +08:00
static void copyLocalsFromTo(MethodDef fromMethod, MethodDef toMethod) {
var fromBody = fromMethod.Body;
var toBody = toMethod.Body;
2012-02-03 11:24:43 +08:00
2012-11-04 19:54:05 +08:00
toBody.LocalList.Clear();
foreach (var local in fromBody.LocalList)
toBody.LocalList.Add(new Local(local.Type));
2012-02-03 11:24:43 +08:00
}
2012-11-04 19:54:05 +08:00
static void updateInstructionOperands(MethodDef fromMethod, MethodDef toMethod) {
var fromBody = fromMethod.Body;
var toBody = toMethod.Body;
2012-02-03 11:24:43 +08:00
toBody.InitLocals = fromBody.InitLocals;
2012-11-04 19:54:05 +08:00
toBody.MaxStack = fromBody.MaxStack;
2012-02-03 11:24:43 +08:00
var newOperands = new Dictionary<object, object>();
2012-11-04 19:54:05 +08:00
var fromParams = fromMethod.Parameters;
var toParams = toMethod.Parameters;
2012-02-03 11:24:43 +08:00
for (int i = 0; i < fromParams.Count; i++)
newOperands[fromParams[i]] = toParams[i];
2012-11-04 19:54:05 +08:00
for (int i = 0; i < fromBody.LocalList.Count; i++)
newOperands[fromBody.LocalList[i]] = toBody.LocalList[i];
2012-02-03 11:24:43 +08:00
foreach (var instr in toBody.Instructions) {
if (instr.Operand == null)
continue;
object newOperand;
if (newOperands.TryGetValue(instr.Operand, out newOperand))
instr.Operand = newOperand;
}
}
2012-11-04 19:54:05 +08:00
#if PORT
2012-08-16 01:33:43 +08:00
public static IEnumerable<CustomAttribute> findAttributes(ICustomAttributeProvider custAttrProvider, TypeReference attr) {
2011-09-22 10:55:30 +08:00
var list = new List<CustomAttribute>();
2012-08-16 01:33:43 +08:00
if (custAttrProvider == null)
2011-10-05 14:20:32 +08:00
return list;
2012-08-16 01:33:43 +08:00
foreach (var cattr in custAttrProvider.CustomAttributes) {
2011-09-22 10:55:30 +08:00
if (MemberReferenceHelper.compareTypes(attr, cattr.AttributeType))
list.Add(cattr);
}
return list;
}
2012-11-06 23:30:39 +08:00
#endif
2011-09-22 10:55:30 +08:00
public static string getCustomArgAsString(CustomAttribute cattr, int arg) {
2012-11-17 06:50:52 +08:00
if (cattr == null || arg >= cattr.ConstructorArguments.Count)
2011-09-22 10:55:30 +08:00
return null;
2012-11-17 06:50:52 +08:00
var carg = cattr.ConstructorArguments[arg];
2012-11-06 23:30:39 +08:00
if (carg.Type.GetElementType() != ElementType.String)
2011-09-22 10:55:30 +08:00
return null;
2012-11-06 23:30:39 +08:00
return UTF8String.ToSystemStringOrEmpty((UTF8String)carg.Value);
2011-09-22 10:55:30 +08:00
}
2012-11-07 00:15:11 +08:00
public static IEnumerable<MethodDef> getCalledMethods(ModuleDef module, MethodDef method) {
2011-09-22 10:55:30 +08:00
if (method != null && method.HasBody) {
2012-11-06 23:30:39 +08:00
foreach (var call in method.Body.Instructions) {
2011-09-22 10:55:30 +08:00
if (call.OpCode.Code != Code.Call && call.OpCode.Code != Code.Callvirt)
continue;
2012-11-07 00:15:11 +08:00
var methodRef = call.Operand as IMethod;
2012-02-06 05:52:34 +08:00
if (methodRef == null)
continue;
var type = getType(module, methodRef.DeclaringType);
var methodDef = getMethod(type, methodRef);
2012-03-18 03:36:41 +08:00
if (methodDef != null)
yield return methodDef;
2011-09-22 10:55:30 +08:00
}
}
}
public static IList<Instruction> getInstructions(IList<Instruction> instructions, int i, params OpCode[] opcodes) {
if (i + opcodes.Length > instructions.Count)
return null;
if (opcodes.Length == 0)
return new List<Instruction>();
if (opcodes[0] != instructions[i].OpCode)
return null;
2011-09-22 10:55:30 +08:00
var list = new List<Instruction>(opcodes.Length);
for (int j = 0; j < opcodes.Length; j++) {
var instr = instructions[i + j];
if (instr.OpCode != opcodes[j])
return null;
list.Add(instr);
}
return list;
}
2012-11-08 14:06:46 +08:00
#if PORT
2011-09-22 10:55:30 +08:00
public static bool hasReturnValue(IMethodSignature method) {
2012-04-13 07:48:22 +08:00
var type = method.MethodReturnType.ReturnType;
while (type.IsOptionalModifier || type.IsRequiredModifier)
type = ((TypeSpecification)type).ElementType;
return type.EType != ElementType.Void;
2011-09-22 10:55:30 +08:00
}
2012-11-02 15:23:20 +08:00
#endif
2011-09-22 10:55:30 +08:00
2012-11-04 07:50:24 +08:00
public static bool hasReturnValue(IMethod method) {
if (method == null || method.MethodSig == null || method.MethodSig.RetType == null)
2012-11-02 04:09:09 +08:00
return false;
2012-11-04 07:50:24 +08:00
return method.MethodSig.RetType.RemovePinnedAndModifiers().ElementType != ElementType.Void;
2012-11-02 04:09:09 +08:00
}
2012-11-02 15:23:20 +08:00
#if PORT
2011-10-17 06:22:22 +08:00
public static void updateStack(Instruction instr, ref int stack, bool methodHasReturnValue) {
int pushes, pops;
calculateStackUsage(instr, methodHasReturnValue, out pushes, out pops);
if (pops == -1)
stack = 0;
2011-09-22 10:55:30 +08:00
else
2011-10-17 06:22:22 +08:00
stack += pushes - pops;
2011-09-22 10:55:30 +08:00
}
2011-10-17 06:22:22 +08:00
// Sets pops to -1 if the stack is supposed to be cleared
public static void calculateStackUsage(Instruction instr, bool methodHasReturnValue, out int pushes, out int pops) {
if (instr.OpCode.FlowControl == FlowControl.Call)
calculateStackUsage_call(instr, out pushes, out pops);
else
calculateStackUsage_nonCall(instr, methodHasReturnValue, out pushes, out pops);
}
static void calculateStackUsage_call(Instruction instr, out int pushes, out int pops) {
pushes = 0;
pops = 0;
var method = (IMethodSignature)instr.Operand;
bool implicitThis = method.HasThis && !method.ExplicitThis;
2011-10-17 06:22:22 +08:00
if (hasReturnValue(method) || (instr.OpCode.Code == Code.Newobj && method.HasThis))
pushes++;
if (method.HasParameters)
pops += method.Parameters.Count;
if (implicitThis && instr.OpCode.Code != Code.Newobj)
2011-10-17 06:22:22 +08:00
pops++;
2012-04-12 02:02:15 +08:00
if (instr.OpCode.Code == Code.Calli)
pops++;
2011-10-17 06:22:22 +08:00
}
// Sets pops to -1 if the stack is supposed to be cleared
static void calculateStackUsage_nonCall(Instruction instr, bool methodHasReturnValue, out int pushes, out int pops) {
2011-09-22 10:55:30 +08:00
StackBehaviour stackBehavior;
2011-10-17 06:22:22 +08:00
pushes = 0;
pops = 0;
2011-09-22 10:55:30 +08:00
stackBehavior = instr.OpCode.StackBehaviourPush;
switch (stackBehavior) {
case StackBehaviour.Push0:
break;
case StackBehaviour.Push1:
case StackBehaviour.Pushi:
case StackBehaviour.Pushi8:
case StackBehaviour.Pushr4:
case StackBehaviour.Pushr8:
case StackBehaviour.Pushref:
2011-10-17 06:22:22 +08:00
pushes++;
2011-09-22 10:55:30 +08:00
break;
case StackBehaviour.Push1_push1:
2011-10-17 06:22:22 +08:00
pushes += 2;
2011-09-22 10:55:30 +08:00
break;
case StackBehaviour.Varpush: // only call, calli, callvirt which are handled elsewhere
default:
throw new ApplicationException(string.Format("Unknown push StackBehavior {0}", stackBehavior));
}
stackBehavior = instr.OpCode.StackBehaviourPop;
switch (stackBehavior) {
case StackBehaviour.Pop0:
break;
case StackBehaviour.Pop1:
case StackBehaviour.Popi:
case StackBehaviour.Popref:
2011-10-17 06:22:22 +08:00
pops++;
2011-09-22 10:55:30 +08:00
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:
2011-10-17 06:22:22 +08:00
pops += 2;
2011-09-22 10:55:30 +08:00
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:
2011-10-17 06:22:22 +08:00
pops += 3;
2011-09-22 10:55:30 +08:00
break;
case StackBehaviour.PopAll:
2011-10-17 06:22:22 +08:00
pops = -1;
2011-09-22 10:55:30 +08:00
break;
case StackBehaviour.Varpop: // call, calli, callvirt, newobj (all handled elsewhere), and ret
2011-10-17 06:22:22 +08:00
if (methodHasReturnValue)
pops++;
2011-09-22 10:55:30 +08:00
break;
default:
throw new ApplicationException(string.Format("Unknown pop StackBehavior {0}", stackBehavior));
}
}
2011-09-27 07:48:47 +08:00
2011-11-17 05:56:36 +08:00
public static AssemblyNameReference getAssemblyNameReference(TypeReference type) {
var scope = type.Scope;
2012-08-31 06:24:42 +08:00
if (scope == null)
return null;
2011-09-27 07:48:47 +08:00
if (scope is ModuleDefinition) {
var moduleDefinition = (ModuleDefinition)scope;
return moduleDefinition.Assembly.Name;
}
2011-11-17 05:56:36 +08:00
if (scope is AssemblyNameReference)
2011-09-27 07:48:47 +08:00
return (AssemblyNameReference)scope;
2011-11-17 05:56:36 +08:00
if (scope is ModuleReference && type.Module.Assembly != null) {
foreach (var module in type.Module.Assembly.Modules) {
if (scope.Name == module.Name)
return type.Module.Assembly.Name;
}
}
2011-09-27 07:48:47 +08:00
throw new ApplicationException(string.Format("Unknown IMetadataScope type: {0}", scope.GetType()));
}
2011-11-17 05:56:36 +08:00
public static string getFullAssemblyName(TypeReference type) {
var asmRef = getAssemblyNameReference(type);
2012-08-31 06:24:42 +08:00
return asmRef == null ? null : asmRef.FullName;
2011-09-27 07:48:47 +08:00
}
2011-10-17 06:22:22 +08:00
public static bool isAssembly(IMetadataScope scope, string assemblySimpleName) {
return scope.Name == assemblySimpleName ||
scope.Name.StartsWith(assemblySimpleName + ",", StringComparison.Ordinal);
}
2011-10-24 18:45:20 +08:00
2012-01-07 06:59:20 +08:00
public static bool isReferenceToModule(ModuleReference moduleReference, IMetadataScope scope) {
switch (scope.MetadataScopeType) {
case MetadataScopeType.AssemblyNameReference:
var asmRef = (AssemblyNameReference)scope;
var module = moduleReference as ModuleDefinition;
return module != null && module.Assembly != null && module.Assembly.Name.FullName == asmRef.FullName;
case MetadataScopeType.ModuleDefinition:
return moduleReference == scope;
case MetadataScopeType.ModuleReference:
return moduleReference.Name == ((ModuleReference)scope).Name;
default:
throw new ApplicationException("Unknown MetadataScopeType");
}
}
2012-01-22 03:31:47 +08:00
public static int getArgIndex(Instruction instr) {
2011-10-24 18:45:20 +08:00
switch (instr.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.Ldarga:
case Code.Ldarga_S:
case Code.Ldarg:
case Code.Ldarg_S:
2012-01-22 03:31:47 +08:00
return getArgIndex(instr.Operand as ParameterDefinition);
2011-10-24 18:45:20 +08:00
}
return -1;
}
2012-01-22 03:31:47 +08:00
public static int getArgIndex(ParameterDefinition arg) {
2011-10-24 18:45:20 +08:00
if (arg == null)
return -1;
2012-01-22 03:31:47 +08:00
return arg.Sequence;
2011-10-24 18:45:20 +08:00
}
2011-11-01 06:56:02 +08:00
public static List<ParameterDefinition> getParameters(MethodReference method) {
var args = new List<ParameterDefinition>(method.Parameters.Count + 1);
2012-01-22 02:54:33 +08:00
if (method.HasImplicitThis) {
2012-11-06 23:30:39 +08:00
var methodDef = method as MethodDef;
if (methodDef != null && methodDef.Body != null)
args.Add(methodDef.Body.ThisParameter);
2012-01-22 02:54:33 +08:00
else
args.Add(new ParameterDefinition(method.DeclaringType, method));
}
2011-11-01 06:56:02 +08:00
foreach (var arg in method.Parameters)
args.Add(arg);
return args;
}
public static ParameterDefinition getParameter(MethodReference method, Instruction instr) {
2012-01-22 03:31:47 +08:00
return getParameter(getParameters(method), instr);
2012-01-09 05:40:11 +08:00
}
2012-01-22 03:31:47 +08:00
public static ParameterDefinition getParameter(IList<ParameterDefinition> parameters, Instruction instr) {
return getParameter(parameters, getArgIndex(instr));
2011-11-01 06:56:02 +08:00
}
public static ParameterDefinition getParameter(IList<ParameterDefinition> parameters, int index) {
if (0 <= index && index < parameters.Count)
return parameters[index];
return null;
}
2012-11-02 15:23:20 +08:00
#endif
2011-11-01 06:56:02 +08:00
2012-11-04 07:50:24 +08:00
public static Parameter getParameter(IList<Parameter> parameters, int index) {
2012-11-02 04:09:09 +08:00
if (0 <= index && index < parameters.Count)
return parameters[index];
return null;
}
2012-11-04 07:50:24 +08:00
public static TypeSig getArg(IList<TypeSig> args, int index) {
2012-11-02 15:23:20 +08:00
if (0 <= index && index < args.Count)
return args[index];
return null;
}
#if PORT
2011-10-24 18:45:20 +08:00
public static List<TypeReference> getArgs(MethodReference method) {
var args = new List<TypeReference>(method.Parameters.Count + 1);
if (method.HasImplicitThis)
2011-10-24 18:45:20 +08:00
args.Add(method.DeclaringType);
foreach (var arg in method.Parameters)
args.Add(arg.ParameterType);
return args;
}
2012-11-02 15:23:20 +08:00
#endif
2011-10-24 18:45:20 +08:00
2012-11-04 07:50:24 +08:00
public static List<TypeSig> getArgs(IMethod method) {
2012-11-01 01:52:50 +08:00
var sig = method.MethodSig;
2012-11-04 07:50:24 +08:00
var args = new List<TypeSig>(sig.Params.Count + 1);
2012-11-01 23:42:02 +08:00
if (sig.ImplicitThis)
2012-11-04 07:50:24 +08:00
args.Add(method.DeclaringType.ToTypeSig());
2012-11-01 01:52:50 +08:00
foreach (var arg in sig.Params)
args.Add(arg);
return args;
}
2012-11-02 15:23:20 +08:00
#if PORT
public static TypeReference getArgType(MethodReference method, Instruction instr) {
2012-01-22 03:31:47 +08:00
return getArgType(getArgs(method), instr);
2011-11-01 06:56:02 +08:00
}
2012-01-22 03:31:47 +08:00
public static TypeReference getArgType(IList<TypeReference> methodArgs, Instruction instr) {
return getArgType(methodArgs, getArgIndex(instr));
2011-11-01 06:56:02 +08:00
}
public static TypeReference getArgType(IList<TypeReference> methodArgs, int index) {
if (0 <= index && index < methodArgs.Count)
return methodArgs[index];
return null;
}
2011-10-24 18:45:20 +08:00
public static int getArgsCount(MethodReference method) {
int count = method.Parameters.Count;
if (method.HasImplicitThis)
2011-10-24 18:45:20 +08:00
count++;
return count;
}
2012-11-02 15:23:20 +08:00
#endif
2011-10-27 03:01:38 +08:00
2012-11-04 07:50:24 +08:00
public static int getArgsCount(IMethod method) {
2012-11-01 01:52:50 +08:00
var sig = method.MethodSig;
if (sig == null)
return 0;
int count = sig.Params.Count;
2012-11-01 23:42:02 +08:00
if (sig.ImplicitThis)
2012-11-01 01:52:50 +08:00
count++;
return count;
}
2012-11-18 01:57:36 +08:00
public static IList<TypeSig> replaceGenericParameters(GenericInstSig typeOwner, MethodSpec methodOwner, IList<TypeSig> types) {
if (typeOwner == null && methodOwner == null)
return types;
for (int i = 0; i < types.Count; i++)
types[i] = getGenericArgument(typeOwner, methodOwner, types[i]);
return types;
}
2012-11-18 01:57:36 +08:00
public static TypeSig getGenericArgument(GenericInstSig typeOwner, MethodSpec methodOwner, TypeSig type) {
var typeArgs = typeOwner == null ? null : typeOwner.GenericArguments;
var genMethodArgs = methodOwner == null || methodOwner.GenericInstMethodSig == null ?
null : methodOwner.GenericInstMethodSig.GenericArguments;
return GenericArgsSubstitutor.create(type, typeArgs, genMethodArgs);
}
2012-11-18 01:57:36 +08:00
#if PORT
public static Instruction getInstruction(IList<Instruction> instructions, ref int index) {
for (int i = 0; i < 10; i++) {
if (index < 0 || index >= instructions.Count)
return null;
var instr = instructions[index++];
if (instr.OpCode.Code == Code.Nop)
continue;
2012-01-24 09:28:21 +08:00
if (instr.OpCode.OpCodeType == OpCodeType.Prefix)
continue;
if (instr == null || (instr.OpCode.Code != Code.Br && instr.OpCode.Code != Code.Br_S))
return instr;
instr = instr.Operand as Instruction;
if (instr == null)
return null;
index = instructions.IndexOf(instr);
}
return null;
}
2012-11-02 15:23:20 +08:00
#endif
2011-11-21 17:32:57 +08:00
2012-11-04 07:50:24 +08:00
public static Instruction getInstruction(IList<Instruction> instructions, ref int index) {
2012-11-01 01:52:50 +08:00
for (int i = 0; i < 10; i++) {
if (index < 0 || index >= instructions.Count)
return null;
var instr = instructions[index++];
2012-11-04 07:50:24 +08:00
if (instr.OpCode.Code == Code.Nop)
2012-11-01 01:52:50 +08:00
continue;
2012-11-04 07:50:24 +08:00
if (instr.OpCode.OpCodeType == OpCodeType.Prefix)
2012-11-01 01:52:50 +08:00
continue;
2012-11-04 07:50:24 +08:00
if (instr == null || (instr.OpCode.Code != Code.Br && instr.OpCode.Code != Code.Br_S))
2012-11-01 01:52:50 +08:00
return instr;
2012-11-04 07:50:24 +08:00
instr = instr.Operand as Instruction;
2012-11-01 01:52:50 +08:00
if (instr == null)
return null;
index = instructions.IndexOf(instr);
}
return null;
}
2012-11-02 15:23:20 +08:00
#if PORT
2012-11-06 23:30:39 +08:00
public static PropertyDefinition createPropertyDefinition(string name, TypeReference propType, MethodDef getter, MethodDef setter) {
return new PropertyDefinition(name, PropertyAttributes.None, propType) {
2011-12-29 15:21:19 +08:00
MetadataToken = nextPropertyToken(),
GetMethod = getter,
SetMethod = setter,
};
2011-11-21 17:32:57 +08:00
}
2011-12-29 15:21:19 +08:00
2011-11-23 13:38:10 +08:00
public static EventDefinition createEventDefinition(string name, TypeReference eventType) {
return new EventDefinition(name, EventAttributes.None, eventType) {
2011-12-29 15:21:19 +08:00
MetadataToken = nextEventToken(),
};
2011-11-23 13:38:10 +08:00
}
2011-12-22 12:37:10 +08:00
2012-01-29 05:18:28 +08:00
public static FieldDefinition createFieldDefinition(string name, FieldAttributes attributes, TypeReference fieldType) {
return new FieldDefinition(name, attributes, fieldType) {
MetadataToken = nextFieldToken(),
};
}
2011-12-29 15:21:19 +08:00
static int nextTokenRid = 0x00FFFFFF;
public static MetadataToken nextTypeRefToken() {
return new MetadataToken(TokenType.TypeRef, nextTokenRid--);
}
public static MetadataToken nextTypeDefToken() {
return new MetadataToken(TokenType.TypeDef, nextTokenRid--);
}
public static MetadataToken nextFieldToken() {
return new MetadataToken(TokenType.Field, nextTokenRid--);
}
public static MetadataToken nextMethodToken() {
return new MetadataToken(TokenType.Method, nextTokenRid--);
}
public static MetadataToken nextPropertyToken() {
return new MetadataToken(TokenType.Property, nextTokenRid--);
}
public static MetadataToken nextEventToken() {
return new MetadataToken(TokenType.Event, nextTokenRid--);
}
public static TypeReference findTypeReference(ModuleDefinition module, string asmSimpleName, string fullName) {
foreach (var type in module.GetTypeReferences()) {
if (type.FullName != fullName)
continue;
var asmRef = type.Scope as AssemblyNameReference;
if (asmRef == null || asmRef.Name != asmSimpleName)
continue;
return type;
}
return null;
}
public static TypeReference findOrCreateTypeReference(ModuleDefinition module, AssemblyNameReference asmRef, string ns, string name, bool isValueType) {
var typeRef = findTypeReference(module, asmRef.Name, ns + "." + name);
if (typeRef != null)
return typeRef;
typeRef = new TypeReference(ns, name, module, asmRef);
typeRef.MetadataToken = nextTypeRefToken();
typeRef.IsValueType = isValueType;
return typeRef;
}
2012-11-02 15:23:20 +08:00
#endif
2012-03-16 02:03:22 +08:00
2012-11-04 07:50:24 +08:00
public static TypeDefOrRefSig findOrCreateTypeReference(ModuleDef module, AssemblyRef asmRef, string ns, string name, bool isValueType) {
var typeRef = module.UpdateRowId(new TypeRefUser(module, ns, name, asmRef));
2012-11-01 18:28:09 +08:00
if (isValueType)
2012-11-04 07:50:24 +08:00
return new ValueTypeSig(typeRef);
2012-11-01 18:28:09 +08:00
else
2012-11-04 07:50:24 +08:00
return new ClassSig(typeRef);
2012-11-01 18:28:09 +08:00
}
2012-11-09 05:24:13 +08:00
public static FrameworkType getFrameworkType(ModuleDefMD module) {
foreach (var modRef in module.GetAssemblyRefs()) {
2012-03-16 02:03:22 +08:00
if (modRef.Name != "mscorlib")
continue;
2012-11-09 05:24:13 +08:00
if (PublicKeyBase.IsNullOrEmpty2(modRef.PublicKeyOrToken))
2012-03-16 02:03:22 +08:00
continue;
2012-11-09 05:24:13 +08:00
switch (BitConverter.ToString(modRef.PublicKeyOrToken.Data).Replace("-", "").ToLowerInvariant()) {
2012-03-16 02:03:22 +08:00
case "b77a5c561934e089":
2012-03-17 02:13:27 +08:00
return FrameworkType.Desktop;
2012-03-16 02:03:22 +08:00
case "7cec85d7bea7798e":
2012-03-17 02:13:27 +08:00
return FrameworkType.Silverlight;
2012-03-16 02:03:22 +08:00
case "969db8053d3322ac":
2012-03-17 02:13:27 +08:00
return FrameworkType.CompactFramework;
2012-03-21 10:20:59 +08:00
case "1c9e259686f921e0":
return FrameworkType.XNA;
2012-03-16 02:03:22 +08:00
case "e92a8b81eba7ceb7":
2012-03-17 02:13:27 +08:00
return FrameworkType.Zune;
2012-03-16 02:03:22 +08:00
}
}
2012-03-17 02:13:27 +08:00
return FrameworkType.Unknown;
2012-03-16 02:03:22 +08:00
}
2012-11-06 23:30:39 +08:00
public static int getMethodCalls(MethodDef method, string methodFullName) {
if (method == null || method.Body == null)
return 0;
int count = 0;
foreach (var instr in method.Body.Instructions) {
if (instr.OpCode.Code != Code.Call && instr.OpCode.Code != Code.Callvirt && instr.OpCode.Code != Code.Newobj)
continue;
var calledMethod = instr.Operand as IMethod;
if (calledMethod == null)
continue;
if (calledMethod.FullName == methodFullName)
count++;
}
return count;
}
2012-03-16 02:29:56 +08:00
2012-11-06 23:30:39 +08:00
public static bool callsMethod(MethodDef method, string methodFullName) {
if (method == null || method.Body == null)
2012-03-16 02:29:56 +08:00
return false;
2012-11-06 23:30:39 +08:00
foreach (var instr in method.Body.Instructions) {
2012-07-31 21:01:54 +08:00
if (instr.OpCode.Code != Code.Call && instr.OpCode.Code != Code.Callvirt && instr.OpCode.Code != Code.Newobj)
2012-03-16 02:29:56 +08:00
continue;
2012-11-07 00:15:11 +08:00
var calledMethod = instr.Operand as IMethod;
2012-03-16 02:29:56 +08:00
if (calledMethod == null)
continue;
if (calledMethod.FullName == methodFullName)
return true;
}
return false;
}
2012-11-06 23:30:39 +08:00
public static bool callsMethod(MethodDef method, string returnType, string parameters) {
if (method == null || method.Body == null)
2012-03-16 02:29:56 +08:00
return false;
2012-11-06 23:30:39 +08:00
foreach (var instr in method.Body.Instructions) {
if (instr.OpCode.Code != Code.Call && instr.OpCode.Code != Code.Callvirt && instr.OpCode.Code != Code.Newobj)
2012-03-16 02:29:56 +08:00
continue;
2012-11-09 05:24:13 +08:00
if (isMethod(instr.Operand as IMethod, returnType, parameters))
2012-03-16 02:29:56 +08:00
return true;
}
return false;
}
2012-05-10 00:25:43 +08:00
public static IList<Instruction> getArgPushes(IList<Instruction> instrs, int index) {
return getArgPushes(instrs, ref index);
}
public static IList<Instruction> getArgPushes(IList<Instruction> instrs, ref int index) {
if (index < 0 || index >= instrs.Count)
return null;
var startInstr = instrs[index];
int pushes, pops;
2012-11-09 07:21:45 +08:00
startInstr.CalculateStackUsage(false, out pushes, out pops);
2012-05-10 00:25:43 +08:00
index--;
int numArgs = pops;
var args = new List<Instruction>(numArgs);
int stackSize = numArgs;
while (index >= 0 && args.Count != numArgs) {
var instr = instrs[index--];
2012-11-09 07:21:45 +08:00
instr.CalculateStackUsage(false, out pushes, out pops);
2012-05-10 00:25:43 +08:00
if (instr.OpCode.Code == Code.Dup) {
args.Add(instr);
stackSize--;
}
else {
if (pushes == 1)
args.Add(instr);
else if (pushes > 1)
throw new NotImplementedException();
stackSize -= pushes;
if (pops != 0) {
index++;
if (getArgPushes(instrs, ref index) == null)
return null;
}
}
if (stackSize < 0)
return null;
}
if (args.Count != numArgs)
return null;
args.Reverse();
return args;
}
2012-07-30 15:17:22 +08:00
2012-11-09 07:21:45 +08:00
#if PORT
2012-07-30 15:17:22 +08:00
public static AssemblyNameReference addAssemblyReference(ModuleDefinition module, AssemblyNameReference asmRef) {
foreach (var modAsmRef in module.AssemblyReferences) {
if (modAsmRef.FullName == asmRef.FullName)
return modAsmRef;
}
var newAsmRef = AssemblyNameReference.Parse(asmRef.FullName);
module.AssemblyReferences.Add(newAsmRef);
return newAsmRef;
}
public static ModuleReference addModuleReference(ModuleDefinition module, ModuleReference modRef) {
foreach (var modModRef in module.ModuleReferences) {
if (modModRef.Name == modRef.Name)
return modModRef;
}
var newModRef = new ModuleReference(modRef.Name);
module.ModuleReferences.Add(newModRef);
return newModRef;
}
2012-11-02 15:23:20 +08:00
#endif
2011-09-22 10:55:30 +08:00
}
}