2011-09-27 07:48:47 +08:00
/ *
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 {
2011-09-28 04:06:43 +08:00
static class Resolver {
2011-09-27 07:48:47 +08:00
static Dictionary < string , AssemblyResolver > assemblyResolvers = new Dictionary < string , AssemblyResolver > ( StringComparer . Ordinal ) ;
2011-09-28 04:06:43 +08:00
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 ) {
2011-10-03 15:36:46 +08:00
if ( typeReference = = null )
return null ;
2011-09-28 04:06:43 +08:00
var module = getModule ( typeReference . Scope ) ;
if ( module ! = null )
return module . getType ( typeReference ) ;
return null ;
}
public static MMethod getMethod ( MethodReference methodReference ) {
2011-10-03 15:36:46 +08:00
if ( methodReference = = null )
return null ;
2011-09-28 04:06:43 +08:00
var module = getModule ( methodReference . DeclaringType . Scope ) ;
if ( module ! = null )
return module . getMethod ( methodReference ) ;
return null ;
}
public static MField getField ( FieldReference fieldReference ) {
2011-10-03 15:36:46 +08:00
if ( fieldReference = = null )
return null ;
2011-09-28 04:06:43 +08:00
var module = getModule ( fieldReference . DeclaringType . Scope ) ;
if ( module ! = null )
return module . getField ( fieldReference ) ;
return null ;
}
public static object getRtObject ( MemberReference memberReference ) {
2011-10-03 15:36:46 +08:00
if ( memberReference = = null )
return null ;
else if ( memberReference is TypeReference )
2011-09-28 04:06:43 +08:00
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 ) ;
}
2011-09-27 07:48:47 +08:00
static AssemblyResolver getAssemblyResolver ( IMetadataScope scope ) {
var asmName = DotNetUtils . getFullAssemblyName ( scope ) ;
AssemblyResolver resolver ;
if ( ! assemblyResolvers . TryGetValue ( asmName , out resolver ) )
assemblyResolvers [ asmName ] = resolver = new AssemblyResolver ( asmName ) ;
return resolver ;
}
2011-09-28 04:06:43 +08:00
static Type resolve ( TypeReference typeReference ) {
2011-10-03 15:36:46 +08:00
if ( typeReference = = null )
return null ;
2011-09-27 07:48:47 +08:00
var elemType = typeReference . GetElementType ( ) ;
var resolver = getAssemblyResolver ( elemType . Scope ) ;
var resolvedType = resolver . resolve ( elemType ) ;
if ( resolvedType ! = null )
return fixType ( typeReference , resolvedType ) ;
throw new ApplicationException ( string . Format ( "Could not resolve type {0} ({1:X8}) in assembly {2}" , typeReference , typeReference . MetadataToken . ToUInt32 ( ) , resolver ) ) ;
}
2011-09-28 04:06:43 +08:00
static FieldInfo resolve ( FieldReference fieldReference ) {
2011-10-03 15:36:46 +08:00
if ( fieldReference = = null )
return null ;
2011-09-27 07:48:47 +08:00
var resolver = getAssemblyResolver ( fieldReference . DeclaringType . Scope ) ;
var fieldInfo = resolver . resolve ( fieldReference ) ;
if ( fieldInfo ! = null )
return fieldInfo ;
throw new ApplicationException ( string . Format ( "Could not resolve field {0} ({1:X8}) in assembly {2}" , fieldReference , fieldReference . MetadataToken . ToUInt32 ( ) , resolver ) ) ;
}
2011-09-28 04:06:43 +08:00
static MethodBase resolve ( MethodReference methodReference ) {
2011-10-03 15:36:46 +08:00
if ( methodReference = = null )
return null ;
2011-09-27 07:48:47 +08:00
var resolver = getAssemblyResolver ( methodReference . DeclaringType . Scope ) ;
var methodBase = resolver . resolve ( methodReference ) ;
if ( methodBase ! = null )
return methodBase ;
throw new ApplicationException ( string . Format ( "Could not resolve method {0} ({1:X8}) in assembly {2}" , methodReference , methodReference . MetadataToken . ToUInt32 ( ) , resolver ) ) ;
}
static Type fixType ( TypeReference typeReference , Type type ) {
while ( typeReference is TypeSpecification ) {
var ts = ( TypeSpecification ) typeReference ;
if ( typeReference is ArrayType ) {
var arrayType = ( ArrayType ) typeReference ;
if ( arrayType . IsVector )
type = type . MakeArrayType ( ) ;
else
type = type . MakeArrayType ( arrayType . Rank ) ;
}
else if ( typeReference is ByReferenceType ) {
type = type . MakeByRefType ( ) ;
}
else if ( typeReference is PointerType ) {
type = type . MakePointerType ( ) ;
}
else if ( typeReference is GenericInstanceType ) {
var git = ( GenericInstanceType ) typeReference ;
var args = new Type [ git . GenericArguments . Count ] ;
bool isGenericTypeDef = true ;
for ( int i = 0 ; i < args . Length ; i + + ) {
var typeRef = git . GenericArguments [ i ] ;
if ( ! ( typeRef . GetElementType ( ) is GenericParameter ) )
isGenericTypeDef = false ;
args [ i ] = Resolver . resolve ( typeRef ) ;
}
if ( ! isGenericTypeDef )
type = type . MakeGenericType ( args ) ;
}
typeReference = ts . ElementType ;
}
return type ;
}
}
}