Methodsrewriter is now working
This commit is contained in:
parent
695dd81b43
commit
c257f16787
|
@ -51,12 +51,14 @@
|
||||||
<Compile Include="methodsrewriter\Operand.cs" />
|
<Compile Include="methodsrewriter\Operand.cs" />
|
||||||
<Compile Include="methodsrewriter\Resolver.cs" />
|
<Compile Include="methodsrewriter\Resolver.cs" />
|
||||||
<Compile Include="methodsrewriter\ResolverUtils.cs" />
|
<Compile Include="methodsrewriter\ResolverUtils.cs" />
|
||||||
|
<Compile Include="methodsrewriter\TypeInstanceResolver.cs" />
|
||||||
<Compile Include="methodsrewriter\TypeResolver.cs" />
|
<Compile Include="methodsrewriter\TypeResolver.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="SimpleData.cs" />
|
<Compile Include="SimpleData.cs" />
|
||||||
<Compile Include="Utils.cs" />
|
<Compile Include="Utils.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Reference Include="System" />
|
||||||
<Reference Include="System.Runtime.Remoting" />
|
<Reference Include="System.Runtime.Remoting" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -69,6 +69,10 @@ namespace AssemblyData {
|
||||||
static class Utils {
|
static class Utils {
|
||||||
static Random random = new Random();
|
static Random random = new Random();
|
||||||
|
|
||||||
|
public static uint getRandomUint() {
|
||||||
|
return (uint)(random.NextDouble() * uint.MaxValue);
|
||||||
|
}
|
||||||
|
|
||||||
public static Type getDelegateType(Type returnType, Type[] args) {
|
public static Type getDelegateType(Type returnType, Type[] args) {
|
||||||
Type[] types;
|
Type[] types;
|
||||||
if (returnType == typeof(void)) {
|
if (returnType == typeof(void)) {
|
||||||
|
|
|
@ -56,6 +56,7 @@ namespace AssemblyData.methodsrewriter {
|
||||||
}
|
}
|
||||||
|
|
||||||
IMethodsRewriter methodsRewriter;
|
IMethodsRewriter methodsRewriter;
|
||||||
|
string methodName;
|
||||||
IList<Instruction> allInstructions;
|
IList<Instruction> allInstructions;
|
||||||
IList<ExceptionHandler> allExceptionHandlers;
|
IList<ExceptionHandler> allExceptionHandlers;
|
||||||
ILGenerator ilg;
|
ILGenerator ilg;
|
||||||
|
@ -69,13 +70,15 @@ namespace AssemblyData.methodsrewriter {
|
||||||
List<LocalBuilder> locals;
|
List<LocalBuilder> locals;
|
||||||
List<Label> labels;
|
List<Label> labels;
|
||||||
Dictionary<Instruction, int> instrToIndex;
|
Dictionary<Instruction, int> instrToIndex;
|
||||||
|
Stack<ExceptionHandler> exceptionHandlersStack;
|
||||||
|
|
||||||
public Type DelegateType {
|
public Type DelegateType {
|
||||||
get { return delegateType; }
|
get { return delegateType; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public CodeGenerator(IMethodsRewriter methodsRewriter) {
|
public CodeGenerator(IMethodsRewriter methodsRewriter, string methodName) {
|
||||||
this.methodsRewriter = methodsRewriter;
|
this.methodsRewriter = methodsRewriter;
|
||||||
|
this.methodName = methodName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setMethodInfo(MMethod methodInfo) {
|
public void setMethodInfo(MMethod methodInfo) {
|
||||||
|
@ -89,7 +92,7 @@ namespace AssemblyData.methodsrewriter {
|
||||||
this.allInstructions = allInstructions;
|
this.allInstructions = allInstructions;
|
||||||
this.allExceptionHandlers = allExceptionHandlers;
|
this.allExceptionHandlers = allExceptionHandlers;
|
||||||
|
|
||||||
var dm = new DynamicMethod("emulated_" + methodInfo.methodBase.Name, methodReturnType, methodParameters, methodsRewriter.GetType(), true);
|
var dm = new DynamicMethod(methodName, methodReturnType, methodParameters, methodInfo.methodBase.Module, true);
|
||||||
var lastInstr = allInstructions[allInstructions.Count - 1];
|
var lastInstr = allInstructions[allInstructions.Count - 1];
|
||||||
ilg = dm.GetILGenerator(lastInstr.Offset + lastInstr.GetSize());
|
ilg = dm.GetILGenerator(lastInstr.Offset + lastInstr.GetSize());
|
||||||
|
|
||||||
|
@ -97,7 +100,9 @@ namespace AssemblyData.methodsrewriter {
|
||||||
initLocals();
|
initLocals();
|
||||||
initLabels();
|
initLabels();
|
||||||
|
|
||||||
|
exceptionHandlersStack = new Stack<ExceptionHandler>();
|
||||||
for (int i = 0; i < allInstructions.Count; i++) {
|
for (int i = 0; i < allInstructions.Count; i++) {
|
||||||
|
updateExceptionHandlers(i);
|
||||||
var instr = allInstructions[i];
|
var instr = allInstructions[i];
|
||||||
ilg.MarkLabel(labels[i]);
|
ilg.MarkLabel(labels[i]);
|
||||||
if (instr.Operand is Operand)
|
if (instr.Operand is Operand)
|
||||||
|
@ -105,10 +110,66 @@ namespace AssemblyData.methodsrewriter {
|
||||||
else
|
else
|
||||||
writeInstr(instr);
|
writeInstr(instr);
|
||||||
}
|
}
|
||||||
|
updateExceptionHandlers(-1);
|
||||||
|
|
||||||
return dm.CreateDelegate(delegateType);
|
return dm.CreateDelegate(delegateType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Instruction getExceptionInstruction(int instructionIndex) {
|
||||||
|
return instructionIndex < 0 ? null : allInstructions[instructionIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateExceptionHandlers(int instructionIndex) {
|
||||||
|
var instr = getExceptionInstruction(instructionIndex);
|
||||||
|
updateExceptionHandlers(instr);
|
||||||
|
if (addTryStart(instr))
|
||||||
|
updateExceptionHandlers(instr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateExceptionHandlers(Instruction instr) {
|
||||||
|
while (exceptionHandlersStack.Count > 0) {
|
||||||
|
var ex = exceptionHandlersStack.Peek();
|
||||||
|
if (ex.TryEnd == instr) {
|
||||||
|
}
|
||||||
|
if (ex.FilterStart == instr) {
|
||||||
|
}
|
||||||
|
if (ex.HandlerStart == instr) {
|
||||||
|
if (ex.HandlerType == ExceptionHandlerType.Finally)
|
||||||
|
ilg.BeginFinallyBlock();
|
||||||
|
else
|
||||||
|
ilg.BeginCatchBlock(Resolver.getRtType(ex.CatchType));
|
||||||
|
}
|
||||||
|
if (ex.HandlerEnd == instr) {
|
||||||
|
exceptionHandlersStack.Pop();
|
||||||
|
if (exceptionHandlersStack.Count == 0 || !isSameTryBlock(ex, exceptionHandlersStack.Peek()))
|
||||||
|
ilg.EndExceptionBlock();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool addTryStart(Instruction instr) {
|
||||||
|
var list = new List<ExceptionHandler>();
|
||||||
|
foreach (var ex in allExceptionHandlers) {
|
||||||
|
if (ex.TryStart == instr)
|
||||||
|
list.Add(ex);
|
||||||
|
}
|
||||||
|
list.Reverse();
|
||||||
|
|
||||||
|
foreach (var ex in list) {
|
||||||
|
if (exceptionHandlersStack.Count == 0 || !isSameTryBlock(ex, exceptionHandlersStack.Peek()))
|
||||||
|
ilg.BeginExceptionBlock();
|
||||||
|
exceptionHandlersStack.Push(ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return list.Count > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isSameTryBlock(ExceptionHandler ex1, ExceptionHandler ex2) {
|
||||||
|
return ex1.TryStart == ex2.TryStart && ex1.TryEnd == ex2.TryEnd;
|
||||||
|
}
|
||||||
|
|
||||||
void initInstrToIndex() {
|
void initInstrToIndex() {
|
||||||
instrToIndex = new Dictionary<Instruction, int>(allInstructions.Count);
|
instrToIndex = new Dictionary<Instruction, int>(allInstructions.Count);
|
||||||
for (int i = 0; i < allInstructions.Count; i++)
|
for (int i = 0; i < allInstructions.Count; i++)
|
||||||
|
@ -118,7 +179,7 @@ namespace AssemblyData.methodsrewriter {
|
||||||
void initLocals() {
|
void initLocals() {
|
||||||
locals = new List<LocalBuilder>();
|
locals = new List<LocalBuilder>();
|
||||||
foreach (var local in methodInfo.methodDefinition.Body.Variables)
|
foreach (var local in methodInfo.methodDefinition.Body.Variables)
|
||||||
locals.Add(ilg.DeclareLocal(methodsRewriter.getRtType(local.VariableType), local.IsPinned));
|
locals.Add(ilg.DeclareLocal(Resolver.getRtType(local.VariableType), local.IsPinned));
|
||||||
tempObjLocal = ilg.DeclareLocal(typeof(object));
|
tempObjLocal = ilg.DeclareLocal(typeof(object));
|
||||||
tempObjArrayLocal = ilg.DeclareLocal(typeof(object[]));
|
tempObjArrayLocal = ilg.DeclareLocal(typeof(object[]));
|
||||||
}
|
}
|
||||||
|
@ -250,7 +311,7 @@ namespace AssemblyData.methodsrewriter {
|
||||||
case OperandType.InlineType:
|
case OperandType.InlineType:
|
||||||
case OperandType.InlineMethod:
|
case OperandType.InlineMethod:
|
||||||
case OperandType.InlineField:
|
case OperandType.InlineField:
|
||||||
var obj = methodsRewriter.getRtObject((MemberReference)instr.Operand);
|
var obj = Resolver.getRtObject((MemberReference)instr.Operand);
|
||||||
if (obj is ConstructorInfo)
|
if (obj is ConstructorInfo)
|
||||||
ilg.Emit(opcode, (ConstructorInfo)obj);
|
ilg.Emit(opcode, (ConstructorInfo)obj);
|
||||||
else if (obj is MethodInfo)
|
else if (obj is MethodInfo)
|
||||||
|
@ -279,7 +340,6 @@ namespace AssemblyData.methodsrewriter {
|
||||||
ilg.Emit(opcode, checked((byte)getLocalIndex((VariableDefinition)instr.Operand)));
|
ilg.Emit(opcode, checked((byte)getLocalIndex((VariableDefinition)instr.Operand)));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
||||||
case OperandType.InlineSig: //TODO:
|
case OperandType.InlineSig: //TODO:
|
||||||
default:
|
default:
|
||||||
throw new ApplicationException(string.Format("Unknown OperandType {0}", instr.OpCode.OperandType));
|
throw new ApplicationException(string.Format("Unknown OperandType {0}", instr.OpCode.OperandType));
|
||||||
|
|
|
@ -23,8 +23,6 @@ using Mono.Cecil;
|
||||||
|
|
||||||
namespace AssemblyData.methodsrewriter {
|
namespace AssemblyData.methodsrewriter {
|
||||||
interface IMethodsRewriter {
|
interface IMethodsRewriter {
|
||||||
Type getRtType(TypeReference typeReference);
|
|
||||||
object getRtObject(MemberReference memberReference);
|
|
||||||
Type getDelegateType(MethodBase methodBase);
|
Type getDelegateType(MethodBase methodBase);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,11 +34,56 @@ using ROpCodes = System.Reflection.Emit.OpCodes;
|
||||||
namespace AssemblyData.methodsrewriter {
|
namespace AssemblyData.methodsrewriter {
|
||||||
delegate object RewrittenMethod(object[] args);
|
delegate object RewrittenMethod(object[] args);
|
||||||
|
|
||||||
|
class MethodsFinder {
|
||||||
|
Dictionary<Module, MethodsModule> moduleToMethods = new Dictionary<Module, MethodsModule>();
|
||||||
|
|
||||||
|
class MethodsModule {
|
||||||
|
const int MAX_METHODS = 30;
|
||||||
|
List<MethodBase> methods = new List<MethodBase>(MAX_METHODS);
|
||||||
|
int next;
|
||||||
|
|
||||||
|
public MethodsModule(Module module) {
|
||||||
|
var flags = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
|
||||||
|
|
||||||
|
foreach (var type in module.GetTypes()) {
|
||||||
|
if (methods.Count >= MAX_METHODS)
|
||||||
|
break;
|
||||||
|
foreach (var method in type.GetMethods(flags)) {
|
||||||
|
if (methods.Count >= MAX_METHODS)
|
||||||
|
break;
|
||||||
|
methods.Add(method);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var method in module.GetMethods(flags)) {
|
||||||
|
if (methods.Count >= MAX_METHODS)
|
||||||
|
break;
|
||||||
|
methods.Add(method);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public MethodBase getNext() {
|
||||||
|
return methods[next++ % methods.Count];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public MethodBase getMethod(Module module) {
|
||||||
|
MethodsModule methodsModule;
|
||||||
|
if (!moduleToMethods.TryGetValue(module, out methodsModule))
|
||||||
|
moduleToMethods[module] = methodsModule = new MethodsModule(module);
|
||||||
|
return methodsModule.getNext();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class MethodsRewriter : IMethodsRewriter {
|
class MethodsRewriter : IMethodsRewriter {
|
||||||
Dictionary<Module, MModule> modules = new Dictionary<Module, MModule>();
|
MethodsFinder methodsFinder = new MethodsFinder();
|
||||||
Dictionary<MethodBase, NewMethodInfo> realMethodToNewMethod = new Dictionary<MethodBase, NewMethodInfo>();
|
Dictionary<MethodBase, NewMethodInfo> realMethodToNewMethod = new Dictionary<MethodBase, NewMethodInfo>();
|
||||||
List<NewMethodInfo> newMethodInfos = new List<NewMethodInfo>();
|
List<NewMethodInfo> newMethodInfos = new List<NewMethodInfo>();
|
||||||
|
|
||||||
|
// There's no documented way to get a dynamic method's MethodInfo. If we name the
|
||||||
|
// method and it's a unique random name, we can still find the emulated method.
|
||||||
|
Dictionary<string, NewMethodInfo> delegateNameToNewMethodInfo = new Dictionary<string, NewMethodInfo>(StringComparer.Ordinal);
|
||||||
|
|
||||||
class NewMethodInfo {
|
class NewMethodInfo {
|
||||||
// Original method
|
// Original method
|
||||||
public MethodBase oldMethod;
|
public MethodBase oldMethod;
|
||||||
|
@ -53,101 +98,26 @@ namespace AssemblyData.methodsrewriter {
|
||||||
|
|
||||||
public RewrittenMethod rewrittenMethod;
|
public RewrittenMethod rewrittenMethod;
|
||||||
|
|
||||||
public NewMethodInfo(MethodBase oldMethod) {
|
// Name of method used by delegateInstance
|
||||||
|
public string delegateMethodName;
|
||||||
|
|
||||||
|
// Name of method used by rewrittenMethod
|
||||||
|
public string rewrittenMethodName;
|
||||||
|
|
||||||
|
public NewMethodInfo(MethodBase oldMethod, int delegateIndex, string delegateMethodName, string rewrittenMethodName) {
|
||||||
this.oldMethod = oldMethod;
|
this.oldMethod = oldMethod;
|
||||||
|
this.delegateIndex = delegateIndex;
|
||||||
|
this.delegateMethodName = delegateMethodName;
|
||||||
|
this.rewrittenMethodName = rewrittenMethodName;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
MModule loadAssembly(Module module) {
|
public bool isRewrittenMethod(string name) {
|
||||||
MModule info;
|
return name == rewrittenMethodName;
|
||||||
if (modules.TryGetValue(module, out info))
|
|
||||||
return info;
|
|
||||||
|
|
||||||
info = new MModule(module, ModuleDefinition.ReadModule(module.FullyQualifiedName));
|
|
||||||
modules[module] = info;
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
|
|
||||||
MModule getModule(ModuleDefinition moduleDefinition) {
|
|
||||||
foreach (var mm in modules.Values) {
|
|
||||||
if (mm.moduleDefinition == moduleDefinition)
|
|
||||||
return mm;
|
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
MModule getModule(AssemblyNameReference assemblyRef) {
|
public bool isDelegateMethod(string name) {
|
||||||
foreach (var mm in modules.Values) {
|
return name == delegateMethodName;
|
||||||
var asm = mm.moduleDefinition.Assembly;
|
|
||||||
if (asm.Name.FullName == assemblyRef.FullName)
|
|
||||||
return mm;
|
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
MModule getModule(IMetadataScope scope) {
|
|
||||||
if (scope is ModuleDefinition)
|
|
||||||
return getModule((ModuleDefinition)scope);
|
|
||||||
else if (scope is AssemblyNameReference)
|
|
||||||
return getModule((AssemblyNameReference)scope);
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
MType getType(TypeReference typeReference) {
|
|
||||||
var module = getModule(typeReference.Scope);
|
|
||||||
if (module != null)
|
|
||||||
return module.getType(typeReference);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
MMethod getMethod(MethodReference methodReference) {
|
|
||||||
var module = getModule(methodReference.DeclaringType.Scope);
|
|
||||||
if (module != null)
|
|
||||||
return module.getMethod(methodReference);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
MField getField(FieldReference fieldReference) {
|
|
||||||
var module = getModule(fieldReference.DeclaringType.Scope);
|
|
||||||
if (module != null)
|
|
||||||
return module.getField(fieldReference);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public object getRtObject(MemberReference memberReference) {
|
|
||||||
if (memberReference is TypeReference)
|
|
||||||
return getRtType((TypeReference)memberReference);
|
|
||||||
else if (memberReference is FieldReference)
|
|
||||||
return getRtField((FieldReference)memberReference);
|
|
||||||
else if (memberReference is MethodReference)
|
|
||||||
return getRtMethod((MethodReference)memberReference);
|
|
||||||
|
|
||||||
throw new ApplicationException(string.Format("Unknown MemberReference: {0}", memberReference));
|
|
||||||
}
|
|
||||||
|
|
||||||
public Type getRtType(TypeReference typeReference) {
|
|
||||||
var mtype = getType(typeReference);
|
|
||||||
if (mtype != null)
|
|
||||||
return mtype.type;
|
|
||||||
|
|
||||||
return Resolver.resolve(typeReference);
|
|
||||||
}
|
|
||||||
|
|
||||||
public FieldInfo getRtField(FieldReference fieldReference) {
|
|
||||||
var mfield = getField(fieldReference);
|
|
||||||
if (mfield != null)
|
|
||||||
return mfield.fieldInfo;
|
|
||||||
|
|
||||||
return Resolver.resolve(fieldReference);
|
|
||||||
}
|
|
||||||
|
|
||||||
public MethodBase getRtMethod(MethodReference methodReference) {
|
|
||||||
var mmethod = getMethod(methodReference);
|
|
||||||
if (mmethod != null)
|
|
||||||
return mmethod.methodBase;
|
|
||||||
|
|
||||||
return Resolver.resolve(methodReference);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Type getDelegateType(MethodBase methodBase) {
|
public Type getDelegateType(MethodBase methodBase) {
|
||||||
|
@ -159,12 +129,13 @@ namespace AssemblyData.methodsrewriter {
|
||||||
if (newMethodInfo.rewrittenMethod != null)
|
if (newMethodInfo.rewrittenMethod != null)
|
||||||
return newMethodInfo.rewrittenMethod;
|
return newMethodInfo.rewrittenMethod;
|
||||||
|
|
||||||
var dm = new DynamicMethod("method_" + newMethodInfo.oldMethod.Name, typeof(object), new Type[] { GetType(), typeof(object[]) }, GetType(), true);
|
var dm = new DynamicMethod(newMethodInfo.rewrittenMethodName, typeof(object), new Type[] { GetType(), typeof(object[]) }, newMethodInfo.oldMethod.Module, true);
|
||||||
var ilg = dm.GetILGenerator();
|
var ilg = dm.GetILGenerator();
|
||||||
|
|
||||||
ilg.Emit(ROpCodes.Ldarg_0);
|
ilg.Emit(ROpCodes.Ldarg_0);
|
||||||
ilg.Emit(ROpCodes.Ldc_I4, newMethodInfo.delegateIndex);
|
ilg.Emit(ROpCodes.Ldc_I4, newMethodInfo.delegateIndex);
|
||||||
ilg.Emit(ROpCodes.Call, GetType().GetMethod("rtGetDelegateInstance", BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Instance));
|
ilg.Emit(ROpCodes.Call, GetType().GetMethod("rtGetDelegateInstance", BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Instance));
|
||||||
|
ilg.Emit(ROpCodes.Castclass, newMethodInfo.delegateType);
|
||||||
|
|
||||||
var args = newMethodInfo.oldMethod.GetParameters();
|
var args = newMethodInfo.oldMethod.GetParameters();
|
||||||
for (int i = 0; i < args.Length; i++) {
|
for (int i = 0; i < args.Length; i++) {
|
||||||
|
@ -192,20 +163,29 @@ namespace AssemblyData.methodsrewriter {
|
||||||
return newMethodInfo.rewrittenMethod;
|
return newMethodInfo.rewrittenMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string getDelegateMethodName(string methodName) {
|
||||||
|
string name = null;
|
||||||
|
do {
|
||||||
|
name = string.Format(" {0} DMN {1:X8} ", methodName, Utils.getRandomUint());
|
||||||
|
} while (delegateNameToNewMethodInfo.ContainsKey(name));
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
public void createMethod(MethodBase realMethod) {
|
public void createMethod(MethodBase realMethod) {
|
||||||
if (realMethodToNewMethod.ContainsKey(realMethod))
|
if (realMethodToNewMethod.ContainsKey(realMethod))
|
||||||
return;
|
return;
|
||||||
var newMethodInfo = new NewMethodInfo(realMethod);
|
var newMethodInfo = new NewMethodInfo(realMethod, newMethodInfos.Count, getDelegateMethodName(realMethod.Name), getDelegateMethodName(realMethod.Name));
|
||||||
newMethodInfo.delegateIndex = newMethodInfos.Count;
|
|
||||||
newMethodInfos.Add(newMethodInfo);
|
newMethodInfos.Add(newMethodInfo);
|
||||||
|
delegateNameToNewMethodInfo[newMethodInfo.delegateMethodName] = newMethodInfo;
|
||||||
|
delegateNameToNewMethodInfo[newMethodInfo.rewrittenMethodName] = newMethodInfo;
|
||||||
realMethodToNewMethod[realMethod] = newMethodInfo;
|
realMethodToNewMethod[realMethod] = newMethodInfo;
|
||||||
|
|
||||||
var moduleInfo = loadAssembly(realMethod.Module);
|
var moduleInfo = Resolver.loadAssembly(realMethod.Module);
|
||||||
var methodInfo = moduleInfo.getMethod(realMethod);
|
var methodInfo = moduleInfo.getMethod(realMethod);
|
||||||
if (!methodInfo.methodDefinition.HasBody || methodInfo.methodDefinition.Body.Instructions.Count == 0)
|
if (!methodInfo.methodDefinition.HasBody || methodInfo.methodDefinition.Body.Instructions.Count == 0)
|
||||||
throw new ApplicationException(string.Format("Method {0} ({1:X8}) has no body", methodInfo.methodDefinition, methodInfo.methodDefinition.MetadataToken.ToUInt32()));
|
throw new ApplicationException(string.Format("Method {0} ({1:X8}) has no body", methodInfo.methodDefinition, methodInfo.methodDefinition.MetadataToken.ToUInt32()));
|
||||||
|
|
||||||
var codeGenerator = new CodeGenerator(this);
|
var codeGenerator = new CodeGenerator(this, newMethodInfo.delegateMethodName);
|
||||||
codeGenerator.setMethodInfo(methodInfo);
|
codeGenerator.setMethodInfo(methodInfo);
|
||||||
newMethodInfo.delegateType = codeGenerator.DelegateType;
|
newMethodInfo.delegateType = codeGenerator.DelegateType;
|
||||||
|
|
||||||
|
@ -273,7 +253,7 @@ namespace AssemblyData.methodsrewriter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var method = getMethod((MethodReference)instr.Operand);
|
var method = Resolver.getMethod((MethodReference)instr.Operand);
|
||||||
if (method != null) {
|
if (method != null) {
|
||||||
createMethod(method.methodBase);
|
createMethod(method.methodBase);
|
||||||
var newMethodInfo = realMethodToNewMethod[method.methodBase];
|
var newMethodInfo = realMethodToNewMethod[method.methodBase];
|
||||||
|
@ -340,13 +320,61 @@ namespace AssemblyData.methodsrewriter {
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static FieldInfo getStackTraceStackFramesField() {
|
||||||
|
var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
|
||||||
|
return ResolverUtils.getFieldThrow(typeof(StackTrace), typeof(StackFrame[]), flags, "Could not find StackTrace's frames (StackFrame[]) field");
|
||||||
|
}
|
||||||
|
|
||||||
|
static FieldInfo getStackFrameMethodField() {
|
||||||
|
var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
|
||||||
|
return ResolverUtils.getFieldThrow(typeof(StackFrame), typeof(MethodBase), flags, "Could not find StackFrame's method (MethodBase) field");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void writeMethodBase(StackFrame frame, MethodBase method) {
|
||||||
|
var methodField = getStackFrameMethodField();
|
||||||
|
methodField.SetValue(frame, method);
|
||||||
|
if (frame.GetMethod() != method)
|
||||||
|
throw new ApplicationException(string.Format("Could not set new method: {0}", method));
|
||||||
|
}
|
||||||
|
|
||||||
|
NewMethodInfo getNewMethodInfo(string name) {
|
||||||
|
NewMethodInfo info;
|
||||||
|
delegateNameToNewMethodInfo.TryGetValue(name, out info);
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
// Called after the StackTrace ctor has been called.
|
// Called after the StackTrace ctor has been called.
|
||||||
static StackTrace static_rtFixStackTrace(StackTrace stackTrace, MethodsRewriter self) {
|
static StackTrace static_rtFixStackTrace(StackTrace stackTrace, MethodsRewriter self) {
|
||||||
return self.rtFixStackTrace(stackTrace);
|
return self.rtFixStackTrace(stackTrace);
|
||||||
}
|
}
|
||||||
|
|
||||||
StackTrace rtFixStackTrace(StackTrace stackTrace) {
|
StackTrace rtFixStackTrace(StackTrace stackTrace) {
|
||||||
//TODO:
|
var framesField = getStackTraceStackFramesField();
|
||||||
|
var frames = (StackFrame[])framesField.GetValue(stackTrace);
|
||||||
|
|
||||||
|
var newFrames = new List<StackFrame>(frames.Length);
|
||||||
|
foreach (var frame in frames) {
|
||||||
|
var method = frame.GetMethod();
|
||||||
|
var info = getNewMethodInfo(method.Name);
|
||||||
|
if (info == null) {
|
||||||
|
newFrames.Add(frame);
|
||||||
|
}
|
||||||
|
else if (info.isRewrittenMethod(method.Name)) {
|
||||||
|
// Write random method from the same module
|
||||||
|
writeMethodBase(frame, methodsFinder.getMethod(info.oldMethod.Module));
|
||||||
|
newFrames.Add(frame);
|
||||||
|
}
|
||||||
|
else if (info.isDelegateMethod(method.Name)) {
|
||||||
|
// Write original method
|
||||||
|
writeMethodBase(frame, info.oldMethod);
|
||||||
|
newFrames.Add(frame);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new ApplicationException("BUG: Shouldn't be here");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
framesField.SetValue(stackTrace, newFrames.ToArray());
|
||||||
return stackTrace;
|
return stackTrace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,5 +40,9 @@ namespace AssemblyData.methodsrewriter {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
this.data = data;
|
this.data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override string ToString() {
|
||||||
|
return "{" + type + " => " + data + "}";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,8 +24,101 @@ using Mono.Cecil;
|
||||||
using de4dot.blocks;
|
using de4dot.blocks;
|
||||||
|
|
||||||
namespace AssemblyData.methodsrewriter {
|
namespace AssemblyData.methodsrewriter {
|
||||||
public static class Resolver {
|
static class Resolver {
|
||||||
static Dictionary<string, AssemblyResolver> assemblyResolvers = new Dictionary<string, AssemblyResolver>(StringComparer.Ordinal);
|
static Dictionary<string, AssemblyResolver> assemblyResolvers = new Dictionary<string, AssemblyResolver>(StringComparer.Ordinal);
|
||||||
|
static Dictionary<Module, MModule> modules = new Dictionary<Module, MModule>();
|
||||||
|
|
||||||
|
public static MModule loadAssembly(Module module) {
|
||||||
|
MModule info;
|
||||||
|
if (modules.TryGetValue(module, out info))
|
||||||
|
return info;
|
||||||
|
|
||||||
|
info = new MModule(module, ModuleDefinition.ReadModule(module.FullyQualifiedName));
|
||||||
|
modules[module] = info;
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
static MModule getModule(ModuleDefinition moduleDefinition) {
|
||||||
|
foreach (var mm in modules.Values) {
|
||||||
|
if (mm.moduleDefinition == moduleDefinition)
|
||||||
|
return mm;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
static MModule getModule(AssemblyNameReference assemblyRef) {
|
||||||
|
foreach (var mm in modules.Values) {
|
||||||
|
var asm = mm.moduleDefinition.Assembly;
|
||||||
|
if (asm.Name.FullName == assemblyRef.FullName)
|
||||||
|
return mm;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MModule getModule(IMetadataScope scope) {
|
||||||
|
if (scope is ModuleDefinition)
|
||||||
|
return getModule((ModuleDefinition)scope);
|
||||||
|
else if (scope is AssemblyNameReference)
|
||||||
|
return getModule((AssemblyNameReference)scope);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MType getType(TypeReference typeReference) {
|
||||||
|
var module = getModule(typeReference.Scope);
|
||||||
|
if (module != null)
|
||||||
|
return module.getType(typeReference);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MMethod getMethod(MethodReference methodReference) {
|
||||||
|
var module = getModule(methodReference.DeclaringType.Scope);
|
||||||
|
if (module != null)
|
||||||
|
return module.getMethod(methodReference);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MField getField(FieldReference fieldReference) {
|
||||||
|
var module = getModule(fieldReference.DeclaringType.Scope);
|
||||||
|
if (module != null)
|
||||||
|
return module.getField(fieldReference);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static object getRtObject(MemberReference memberReference) {
|
||||||
|
if (memberReference is TypeReference)
|
||||||
|
return getRtType((TypeReference)memberReference);
|
||||||
|
else if (memberReference is FieldReference)
|
||||||
|
return getRtField((FieldReference)memberReference);
|
||||||
|
else if (memberReference is MethodReference)
|
||||||
|
return getRtMethod((MethodReference)memberReference);
|
||||||
|
|
||||||
|
throw new ApplicationException(string.Format("Unknown MemberReference: {0}", memberReference));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Type getRtType(TypeReference typeReference) {
|
||||||
|
var mtype = getType(typeReference);
|
||||||
|
if (mtype != null)
|
||||||
|
return mtype.type;
|
||||||
|
|
||||||
|
return Resolver.resolve(typeReference);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static FieldInfo getRtField(FieldReference fieldReference) {
|
||||||
|
var mfield = getField(fieldReference);
|
||||||
|
if (mfield != null)
|
||||||
|
return mfield.fieldInfo;
|
||||||
|
|
||||||
|
return Resolver.resolve(fieldReference);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MethodBase getRtMethod(MethodReference methodReference) {
|
||||||
|
var mmethod = getMethod(methodReference);
|
||||||
|
if (mmethod != null)
|
||||||
|
return mmethod.methodBase;
|
||||||
|
|
||||||
|
return Resolver.resolve(methodReference);
|
||||||
|
}
|
||||||
|
|
||||||
static AssemblyResolver getAssemblyResolver(IMetadataScope scope) {
|
static AssemblyResolver getAssemblyResolver(IMetadataScope scope) {
|
||||||
var asmName = DotNetUtils.getFullAssemblyName(scope);
|
var asmName = DotNetUtils.getFullAssemblyName(scope);
|
||||||
|
@ -35,7 +128,7 @@ namespace AssemblyData.methodsrewriter {
|
||||||
return resolver;
|
return resolver;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Type resolve(TypeReference typeReference) {
|
static Type resolve(TypeReference typeReference) {
|
||||||
var elemType = typeReference.GetElementType();
|
var elemType = typeReference.GetElementType();
|
||||||
var resolver = getAssemblyResolver(elemType.Scope);
|
var resolver = getAssemblyResolver(elemType.Scope);
|
||||||
var resolvedType = resolver.resolve(elemType);
|
var resolvedType = resolver.resolve(elemType);
|
||||||
|
@ -44,7 +137,7 @@ namespace AssemblyData.methodsrewriter {
|
||||||
throw new ApplicationException(string.Format("Could not resolve type {0} ({1:X8}) in assembly {2}", typeReference, typeReference.MetadataToken.ToUInt32(), resolver));
|
throw new ApplicationException(string.Format("Could not resolve type {0} ({1:X8}) in assembly {2}", typeReference, typeReference.MetadataToken.ToUInt32(), resolver));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static FieldInfo resolve(FieldReference fieldReference) {
|
static FieldInfo resolve(FieldReference fieldReference) {
|
||||||
var resolver = getAssemblyResolver(fieldReference.DeclaringType.Scope);
|
var resolver = getAssemblyResolver(fieldReference.DeclaringType.Scope);
|
||||||
var fieldInfo = resolver.resolve(fieldReference);
|
var fieldInfo = resolver.resolve(fieldReference);
|
||||||
if (fieldInfo != null)
|
if (fieldInfo != null)
|
||||||
|
@ -52,7 +145,7 @@ namespace AssemblyData.methodsrewriter {
|
||||||
throw new ApplicationException(string.Format("Could not resolve field {0} ({1:X8}) in assembly {2}", fieldReference, fieldReference.MetadataToken.ToUInt32(), resolver));
|
throw new ApplicationException(string.Format("Could not resolve field {0} ({1:X8}) in assembly {2}", fieldReference, fieldReference.MetadataToken.ToUInt32(), resolver));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MethodBase resolve(MethodReference methodReference) {
|
static MethodBase resolve(MethodReference methodReference) {
|
||||||
var resolver = getAssemblyResolver(methodReference.DeclaringType.Scope);
|
var resolver = getAssemblyResolver(methodReference.DeclaringType.Scope);
|
||||||
var methodBase = resolver.resolve(methodReference);
|
var methodBase = resolver.resolve(methodReference);
|
||||||
if (methodBase != null)
|
if (methodBase != null)
|
||||||
|
|
|
@ -91,9 +91,10 @@ namespace AssemblyData.methodsrewriter {
|
||||||
|
|
||||||
for (int i = 0; i < aGpargs.Length; i++) {
|
for (int i = 0; i < aGpargs.Length; i++) {
|
||||||
var aArg = aGpargs[i];
|
var aArg = aGpargs[i];
|
||||||
|
var bArg = bGpargs[i];
|
||||||
if (aArg.IsGenericParameter)
|
if (aArg.IsGenericParameter)
|
||||||
continue;
|
continue;
|
||||||
if (!compareTypes(aArg, bGpargs[i]))
|
if (!compareTypes(aArg, bArg))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -246,5 +247,74 @@ namespace AssemblyData.methodsrewriter {
|
||||||
foreach (var m in type.GetMethods(flags))
|
foreach (var m in type.GetMethods(flags))
|
||||||
yield return m;
|
yield return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class CachedMemberInfo {
|
||||||
|
Type type;
|
||||||
|
Type memberType;
|
||||||
|
public CachedMemberInfo(Type type, Type memberType) {
|
||||||
|
this.type = type;
|
||||||
|
this.memberType = memberType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode() {
|
||||||
|
return type.GetHashCode() ^ memberType.GetHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object obj) {
|
||||||
|
var other = obj as CachedMemberInfo;
|
||||||
|
if (other == null)
|
||||||
|
return false;
|
||||||
|
return type == other.type && memberType == other.memberType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Dictionary<CachedMemberInfo, FieldInfo> cachedFieldInfos = new Dictionary<CachedMemberInfo, FieldInfo>();
|
||||||
|
public static FieldInfo getField(Type type, Type fieldType, BindingFlags flags) {
|
||||||
|
var key = new CachedMemberInfo(type, fieldType);
|
||||||
|
FieldInfo fieldInfo;
|
||||||
|
if (cachedFieldInfos.TryGetValue(key, out fieldInfo))
|
||||||
|
return fieldInfo;
|
||||||
|
|
||||||
|
foreach (var field in type.GetFields(flags)) {
|
||||||
|
if (field.FieldType == fieldType) {
|
||||||
|
cachedFieldInfos[key] = field;
|
||||||
|
return field;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static FieldInfo getFieldThrow(Type type, Type fieldType, BindingFlags flags, string msg) {
|
||||||
|
var info = getField(type, fieldType, flags);
|
||||||
|
if (info != null)
|
||||||
|
return info;
|
||||||
|
throw new ApplicationException(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<FieldInfo> getFields(Type type, Type fieldType, BindingFlags flags) {
|
||||||
|
var list = new List<FieldInfo>();
|
||||||
|
foreach (var field in type.GetFields(flags)) {
|
||||||
|
if (field.FieldType == fieldType)
|
||||||
|
list.Add(field);
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Type makeInstanceType(Type type, TypeReference typeReference) {
|
||||||
|
var git = typeReference as GenericInstanceType;
|
||||||
|
if (git == null)
|
||||||
|
return type;
|
||||||
|
var types = new Type[git.GenericArguments.Count];
|
||||||
|
bool isTypeDef = true;
|
||||||
|
for (int i = 0; i < git.GenericArguments.Count; i++) {
|
||||||
|
var arg = git.GenericArguments[i];
|
||||||
|
if (!(arg is GenericParameter))
|
||||||
|
isTypeDef = false;
|
||||||
|
types[i] = Resolver.getRtType(arg);
|
||||||
|
}
|
||||||
|
if (isTypeDef)
|
||||||
|
return type;
|
||||||
|
return type.MakeGenericType(types);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
102
AssemblyData/methodsrewriter/TypeInstanceResolver.cs
Normal file
102
AssemblyData/methodsrewriter/TypeInstanceResolver.cs
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2011 de4dot@gmail.com
|
||||||
|
|
||||||
|
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;
|
||||||
|
using System.Reflection;
|
||||||
|
using Mono.Cecil;
|
||||||
|
using de4dot.blocks;
|
||||||
|
|
||||||
|
namespace AssemblyData.methodsrewriter {
|
||||||
|
class TypeInstanceResolver {
|
||||||
|
Type type;
|
||||||
|
Dictionary<string, List<MethodBase>> methods;
|
||||||
|
Dictionary<string, List<FieldInfo>> fields;
|
||||||
|
|
||||||
|
public TypeInstanceResolver(Type type, TypeReference typeReference) {
|
||||||
|
this.type = ResolverUtils.makeInstanceType(type, typeReference);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FieldInfo resolve(FieldReference fieldReference) {
|
||||||
|
initFields();
|
||||||
|
|
||||||
|
List<FieldInfo> list;
|
||||||
|
if (!fields.TryGetValue(fieldReference.Name, out list))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var git = fieldReference.DeclaringType as GenericInstanceType;
|
||||||
|
if (git != null)
|
||||||
|
fieldReference = new FieldReferenceExpander(fieldReference, git).expand();
|
||||||
|
|
||||||
|
foreach (var field in list) {
|
||||||
|
if (ResolverUtils.compareFields(field, fieldReference))
|
||||||
|
return field;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
void initFields() {
|
||||||
|
if (fields != null)
|
||||||
|
return;
|
||||||
|
fields = new Dictionary<string, List<FieldInfo>>(StringComparer.Ordinal);
|
||||||
|
|
||||||
|
var flags = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance;
|
||||||
|
foreach (var field in type.GetFields(flags)) {
|
||||||
|
List<FieldInfo> list;
|
||||||
|
if (!fields.TryGetValue(field.Name, out list))
|
||||||
|
fields[field.Name] = list = new List<FieldInfo>();
|
||||||
|
list.Add(field);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public MethodBase resolve(MethodReference methodReference) {
|
||||||
|
initMethods();
|
||||||
|
|
||||||
|
List<MethodBase> list;
|
||||||
|
if (!methods.TryGetValue(methodReference.Name, out list))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var git = methodReference.DeclaringType as GenericInstanceType;
|
||||||
|
if (git != null)
|
||||||
|
methodReference = new MethodReferenceExpander(methodReference, git).expand();
|
||||||
|
|
||||||
|
foreach (var method in list) {
|
||||||
|
if (ResolverUtils.compareMethods(method, methodReference))
|
||||||
|
return method;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
void initMethods() {
|
||||||
|
if (methods != null)
|
||||||
|
return;
|
||||||
|
methods = new Dictionary<string, List<MethodBase>>(StringComparer.Ordinal);
|
||||||
|
|
||||||
|
var flags = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance;
|
||||||
|
foreach (var method in ResolverUtils.getMethodBases(type, flags)) {
|
||||||
|
List<MethodBase> list;
|
||||||
|
if (!methods.TryGetValue(method.Name, out list))
|
||||||
|
methods[method.Name] = list = new List<MethodBase>();
|
||||||
|
list.Add(method);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,73 +21,31 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Mono.Cecil;
|
using Mono.Cecil;
|
||||||
|
using de4dot.blocks;
|
||||||
|
|
||||||
namespace AssemblyData.methodsrewriter {
|
namespace AssemblyData.methodsrewriter {
|
||||||
class TypeResolver {
|
class TypeResolver {
|
||||||
public Type type;
|
public Type type;
|
||||||
Dictionary<string, List<MethodBase>> methods;
|
Dictionary<TypeReferenceKey, TypeInstanceResolver> typeRefToInstance = new Dictionary<TypeReferenceKey, TypeInstanceResolver>();
|
||||||
Dictionary<string, List<FieldInfo>> fields;
|
|
||||||
|
|
||||||
public TypeResolver(Type type) {
|
public TypeResolver(Type type) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
public FieldInfo resolve(FieldReference fieldReference) {
|
TypeInstanceResolver getTypeInstance(TypeReference typeReference) {
|
||||||
initFields();
|
var key = new TypeReferenceKey(typeReference);
|
||||||
|
TypeInstanceResolver instance;
|
||||||
List<FieldInfo> list;
|
if (!typeRefToInstance.TryGetValue(key, out instance))
|
||||||
if (!fields.TryGetValue(fieldReference.Name, out list))
|
typeRefToInstance[key] = instance = new TypeInstanceResolver(type, typeReference);
|
||||||
return null;
|
return instance;
|
||||||
|
|
||||||
foreach (var field in list) {
|
|
||||||
if (ResolverUtils.compareFields(field, fieldReference))
|
|
||||||
return field;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void initFields() {
|
public FieldInfo resolve(FieldReference fieldReference) {
|
||||||
if (fields != null)
|
return getTypeInstance(fieldReference.DeclaringType).resolve(fieldReference);
|
||||||
return;
|
|
||||||
fields = new Dictionary<string, List<FieldInfo>>(StringComparer.Ordinal);
|
|
||||||
|
|
||||||
var flags = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance;
|
|
||||||
foreach (var field in type.GetFields(flags)) {
|
|
||||||
List<FieldInfo> list;
|
|
||||||
if (!fields.TryGetValue(field.Name, out list))
|
|
||||||
fields[field.Name] = list = new List<FieldInfo>();
|
|
||||||
list.Add(field);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public MethodBase resolve(MethodReference methodReference) {
|
public MethodBase resolve(MethodReference methodReference) {
|
||||||
initMethods();
|
return getTypeInstance(methodReference.DeclaringType).resolve(methodReference);
|
||||||
|
|
||||||
List<MethodBase> list;
|
|
||||||
if (!methods.TryGetValue(methodReference.Name, out list))
|
|
||||||
return null;
|
|
||||||
|
|
||||||
foreach (var method in list) {
|
|
||||||
if (ResolverUtils.compareMethods(method, methodReference))
|
|
||||||
return method;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
void initMethods() {
|
|
||||||
if (methods != null)
|
|
||||||
return;
|
|
||||||
methods = new Dictionary<string, List<MethodBase>>(StringComparer.Ordinal);
|
|
||||||
|
|
||||||
var flags = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance;
|
|
||||||
foreach (var method in ResolverUtils.getMethodBases(type, flags)) {
|
|
||||||
List<MethodBase> list;
|
|
||||||
if (!methods.TryGetValue(method.Name, out list))
|
|
||||||
methods[method.Name] = list = new List<MethodBase>();
|
|
||||||
list.Add(method);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,10 +19,9 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using Mono.Cecil;
|
using Mono.Cecil;
|
||||||
using de4dot.blocks;
|
|
||||||
|
|
||||||
namespace de4dot.renamer {
|
namespace de4dot.blocks {
|
||||||
abstract class Expander {
|
public abstract class Expander {
|
||||||
protected bool modified = false;
|
protected bool modified = false;
|
||||||
|
|
||||||
protected void checkModified(object a, object b) {
|
protected void checkModified(object a, object b) {
|
||||||
|
@ -31,7 +30,7 @@ namespace de4dot.renamer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class TypeReferenceExpander : Expander {
|
public class TypeReferenceExpander : Expander {
|
||||||
TypeReference typeReference;
|
TypeReference typeReference;
|
||||||
GenericInstanceType git;
|
GenericInstanceType git;
|
||||||
|
|
||||||
|
@ -144,7 +143,7 @@ namespace de4dot.renamer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class MultiTypeExpander : Expander {
|
public abstract class MultiTypeExpander : Expander {
|
||||||
GenericInstanceType git;
|
GenericInstanceType git;
|
||||||
|
|
||||||
public MultiTypeExpander(GenericInstanceType git) {
|
public MultiTypeExpander(GenericInstanceType git) {
|
||||||
|
@ -162,7 +161,7 @@ namespace de4dot.renamer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class MethodReferenceExpander : MultiTypeExpander {
|
public class MethodReferenceExpander : MultiTypeExpander {
|
||||||
MethodReference methodReference;
|
MethodReference methodReference;
|
||||||
|
|
||||||
public MethodReferenceExpander(MethodReference methodReference, GenericInstanceType git)
|
public MethodReferenceExpander(MethodReference methodReference, GenericInstanceType git)
|
||||||
|
@ -194,7 +193,21 @@ namespace de4dot.renamer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class EventReferenceExpander : MultiTypeExpander {
|
public class FieldReferenceExpander : MultiTypeExpander {
|
||||||
|
FieldReference fieldReference;
|
||||||
|
|
||||||
|
public FieldReferenceExpander(FieldReference fieldReference, GenericInstanceType git)
|
||||||
|
: base(git) {
|
||||||
|
this.fieldReference = fieldReference;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FieldReference expand() {
|
||||||
|
var fr = new FieldReference(fieldReference.Name, expandType(fieldReference.FieldType));
|
||||||
|
return getResult(fieldReference, fr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class EventReferenceExpander : MultiTypeExpander {
|
||||||
EventReference eventReference;
|
EventReference eventReference;
|
||||||
|
|
||||||
public EventReferenceExpander(EventReference eventReference, GenericInstanceType git)
|
public EventReferenceExpander(EventReference eventReference, GenericInstanceType git)
|
||||||
|
@ -208,7 +221,7 @@ namespace de4dot.renamer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class PropertyReferenceExpander : MultiTypeExpander {
|
public class PropertyReferenceExpander : MultiTypeExpander {
|
||||||
PropertyReference propertyReference;
|
PropertyReference propertyReference;
|
||||||
|
|
||||||
public PropertyReferenceExpander(PropertyReference propertyReference, GenericInstanceType git)
|
public PropertyReferenceExpander(PropertyReference propertyReference, GenericInstanceType git)
|
|
@ -43,6 +43,7 @@
|
||||||
<Compile Include="HandlerBlock.cs" />
|
<Compile Include="HandlerBlock.cs" />
|
||||||
<Compile Include="Instr.cs" />
|
<Compile Include="Instr.cs" />
|
||||||
<Compile Include="InstructionListParser.cs" />
|
<Compile Include="InstructionListParser.cs" />
|
||||||
|
<Compile Include="MemberReferenceExpander.cs" />
|
||||||
<Compile Include="MemberReferenceHelper.cs" />
|
<Compile Include="MemberReferenceHelper.cs" />
|
||||||
<Compile Include="MethodBlocks.cs" />
|
<Compile Include="MethodBlocks.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
|
|
@ -97,7 +97,6 @@
|
||||||
<Compile Include="Program.cs" />
|
<Compile Include="Program.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="renamer\DefinitionsRenamer.cs" />
|
<Compile Include="renamer\DefinitionsRenamer.cs" />
|
||||||
<Compile Include="renamer\MemberReferenceExpander.cs" />
|
|
||||||
<Compile Include="renamer\MemberRefFinder.cs" />
|
<Compile Include="renamer\MemberRefFinder.cs" />
|
||||||
<Compile Include="renamer\MemberRefs.cs" />
|
<Compile Include="renamer\MemberRefs.cs" />
|
||||||
<Compile Include="renamer\MemberRenameState.cs" />
|
<Compile Include="renamer\MemberRenameState.cs" />
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
using Mono.Cecil;
|
using Mono.Cecil;
|
||||||
|
using de4dot.blocks;
|
||||||
|
|
||||||
namespace de4dot.renamer {
|
namespace de4dot.renamer {
|
||||||
abstract class RefExpander {
|
abstract class RefExpander {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user