I tried to write a simple code trimmer, but it fails with generics. So I
tried to skip them, but it still throws error in Cecil.
Here's my code:
var a = AssemblyDefinition.ReadAssembly(@"C:\test.exe");
var mainModule = a.MainModule;
bool print = false;
// 1. get a list of all methods
List<string> AllMethods = new List<string>();
foreach (var type in mainModule.Types) {
if (!type.HasMethods) continue;
if (type.HasGenericParameters || type.IsGenericInstance)
continue;
foreach(var method in type.Methods) {
AllMethods.Add(method.FullName);
if (print) Console.WriteLine("> " + method.FullName);
}
}
Console.WriteLine("TOTAL METHODS WITHOUT TRIM: " +
AllMethods.Count.ToString());
// 2. get all referenced methods
foreach (var type in mainModule.Types) {
if (print) Console.WriteLine(type.FullName);
foreach (var method in type.Methods) {
if (print) Console.WriteLine("\t" + method.FullName);
if (method.HasBody) {
foreach (var inst in method.Body.Instructions) {
if (inst.Operand != null) {
string operand = inst.Operand.ToString();
if (operand.Contains("(") &&
!operand.Contains("!")) { // "!" for generic argument
if (print) Console.WriteLine("> " +
operand);
AllMethods.Remove(operand);
}
}
//Console.WriteLine(inst.Operand.ToString());
}
}
}
}
Console.WriteLine("TOTAL METHODS AFTER TRIM: " +
AllMethods.Count.ToString());
// 3. remove all unreferenced
foreach (var type in mainModule.Types) {
List<MethodDefinition> MethodsToBeRemoved = new
List<MethodDefinition>();
foreach (var method in type.Methods) {
if (AllMethods.Contains(method.FullName)) {
MethodsToBeRemoved.Add(method);
}
}
foreach (var method in MethodsToBeRemoved) {
if (method.FullName.Contains("ctor")) continue;
if (method.FullName.Contains("Main")) continue;
type.Methods.Remove(method);
if (print) Console.WriteLine("REMOVING " + method.FullName);
}
}
a.Write(@"C:\test_out.exe");
Console.WriteLine("DONE");
-------------
Throws exception:
System.NullReferenceException was unhandled
HResult=-2147467261
Message=Object reference not set to an instance of an object.
Source=Mono.Cecil
StackTrace:
at Mono.Cecil.GenericInstanceMethod.get_FullName()
at Mono.Cecil.MemberReference.ToString()
at System.Text.StringBuilder.AppendFormat(IFormatProvider provider,
String format, Object[] args)
at System.String.Format(IFormatProvider provider, String format,
Object[] args)
at System.String.Format(String format, Object arg0)
at
Mono.Cecil.MetadataBuilder.CreateForeignMemberException(MemberReference member)
at Mono.Cecil.MetadataBuilder.LookupToken(IMetadataTokenProvider
provider)
at Mono.Cecil.Cil.CodeWriter.WriteOperand(Instruction instruction)
at Mono.Cecil.Cil.CodeWriter.WriteInstructions()
at Mono.Cecil.Cil.CodeWriter.WriteResolvedMethodBody(MethodDefinition
method)
at Mono.Cecil.Cil.CodeWriter.WriteMethodBody(MethodDefinition method)
at Mono.Cecil.MetadataBuilder.AddMethod(MethodDefinition method)
at Mono.Cecil.MetadataBuilder.AddMethods(TypeDefinition type)
at Mono.Cecil.MetadataBuilder.AddType(TypeDefinition type)
at Mono.Cecil.MetadataBuilder.AddTypeDefs()
at Mono.Cecil.MetadataBuilder.BuildTypes()
at Mono.Cecil.MetadataBuilder.BuildModule()
at Mono.Cecil.MetadataBuilder.BuildMetadata()
at Mono.Cecil.ModuleWriter.<BuildMetadata>b__0(MetadataBuilder builder,
MetadataReader _)
at Mono.Cecil.ModuleDefinition.Read[TItem,TRet](TItem item, Func`3 read)
at Mono.Cecil.ModuleWriter.BuildMetadata(ModuleDefinition module,
MetadataBuilder metadata)
at Mono.Cecil.ModuleWriter.WriteModuleTo(ModuleDefinition module, Stream
stream, WriterParameters parameters)
at Mono.Cecil.ModuleDefinition.Write(Stream stream, WriterParameters
parameters)
at Mono.Cecil.ModuleDefinition.Write(String fileName, WriterParameters
parameters)
at Mono.Cecil.AssemblyDefinition.Write(String fileName, WriterParameters
parameters)
at Mono.Cecil.AssemblyDefinition.Write(String fileName)
[...]
-----------
Help anyone?
--
--
mono-cecil