2017-03-19 6 views
0

Mono.Cecilを使用して、ターゲットメソッドのILコードを編集して、実際のコードを編集せずにそのメソッドのエントリポイントを記録できるようにしています。 ロギング操作を実行できるメソッドにコール命令を挿入できます。 しかし、ターゲットメソッドの入力パラメータをどのように記録するのか分かりません。 要するに、ターゲットメソッドに命令を挿入するには、ILコードを変更してログを作成するか、printメソッドを呼び出して、そのメソッドに渡された入力パラメータ値を記録します。Mono.Cecil:メソッドの先頭にlogステートメントを挿入

サンプルとして基本的なプログラムを試しました。

public class Target 
{ 
    // My target method. 
    public void Run(int arg0, string arg1) 
    { 
     Console.WriteLine("Run method body"); 
    } 


} 

public static class Trace{ 

// This is my log method, which i want to call in begining of Run() method. 
    public void LogEntry(string methodName, object[] params) 
    { 
     System.Console.WriteLine("******Entered in "+ methodName+" method.***********") 
    // With params :...... 
    // 
    } 
} 

ソースプログラム。

public class Sample 
{ 
    private readonly string _targetFileName; 
    private readonly ModuleDefinition _module; 

    public ModuleDefinition TargetModule { get { return _module; } } 

    public Sample(string targetFileName) 
    { 
     _targetFileName = targetFileName; 

     // Read the module with default parameters 
     _module = ModuleDefinition.ReadModule(_targetFileName); 
    } 

    public void Run(string type, string method) 
    { 

     // Retrive the target class. 
     var targetType = _module.Types.Single(t => t.Name == type); 

     // Retrieve the target method. 
     var runMethod = targetType.Methods.Single(m => m.Name == method); 

     // Get a ILProcessor for the Run method 
     var processor = runMethod.Body.GetILProcessor(); 

     // get log entry method ref to create instruction 
     var logEntryMethodReference = targetType.Methods.Single(m => m.Name == "LogEntry"); 

    // Import .. 
    // 
     var newInstruction = processor.Create(OpCodes.Call, logEntryMethodReference); 

     var firstInstruction = runMethod.Body.Instructions[0]; 

     processor.InsertBefore(firstInstruction, newInstruction); 

     // Write the module with default parameters 
     _module.Write(_targetFileName); 
    } 
} 
+0

これはinteresを鳴らし何かサンプルコードがなければ、私たちの誰も助けてくれるものはないと思っています:)あなたがこれまでに持っているものを投稿してください(敬虔ではありませんが、これは通常あなたが持つすべての質問に当てはまります今;これらのような質問のソースコードが不足していても、他の理解度の低い人々があなたに否定的な投票を与えるかもしれません)。 –

+0

@Akos私は更新しました。 – Krishnan

+0

これはOKですか?ここで 'targetType'は' Target'ですが、 'LogEntry'メソッドは' Trace'クラスにあります(クラスとメソッドの両方が静的でなければならないことに注意してください)。 'targetType.Methods.Single()'を実行して 'LogEntry'を探すと、' Trace'ではなく 'Target'でメソッドを探します。または私は何かを逃していますか? –

答えて

2

まあ、これは面白かった:) ここに私のワーキングサンプル(コード内のコメントは、明確な、何もない場合はお気軽に)です:

(実際のパラメータを書き出すに)修正されたサンプル:IL注射を処理するための

public class Target 
{ 
    // My target method. 
    public void Run(int arg0, string arg1) 
    { 
     Console.WriteLine("Run method body"); 
    } 

} 

public static class Trace 
{ 

    // This is my log method, which i want to call in begining of Run() method. 
    public static void LogEntry(string methodName, object[] parameters) 
    { 
     Console.WriteLine("******Entered in " + methodName + " method.***********"); 
     Console.WriteLine(parameters[0]); 
     Console.WriteLine(parameters[1]); 
    } 
} 

ソースプログラム:

public class Sample 
{ 
    private readonly string _targetFileName; 
    private readonly ModuleDefinition _module; 

    public ModuleDefinition TargetModule { get { return _module; } } 

    public Sample(string targetFileName) 
    { 
     _targetFileName = targetFileName; 

     // Read the module with default parameters 
     _module = ModuleDefinition.ReadModule(_targetFileName); 
    } 

    public void Run(string type, string method) 
    { 

     // Retrive the target class. 
     var targetType = _module.Types.Single(t => t.Name == type); 

     // Retrieve the target method. 
     var runMethod = targetType.Methods.Single(m => m.Name == method); 

     // Get a ILProcessor for the Run method 


     // get log entry method ref to create instruction 
     var logEntryMethodReference = _module.Types.Single(t => t.Name == "Trace").Methods.Single(m => m.Name == "LogEntry"); 


     List<Instruction> newInstructions = new List<Instruction>(); 


     var arrayDef = new VariableDefinition(new ArrayType(_module.TypeSystem.Object)); // create variable to hold the array to be passed to the LogEntry() method    
     runMethod.Body.Variables.Add(arrayDef); // add variable to the method   

     var processor = runMethod.Body.GetILProcessor(); 

     newInstructions.Add(processor.Create(OpCodes.Ldc_I4, runMethod.Parameters.Count)); // load to the stack the number of parameters      
     newInstructions.Add(processor.Create(OpCodes.Newarr, _module.TypeSystem.Object)); // create a new object[] with the number loaded to the stack   
     newInstructions.Add(processor.Create(OpCodes.Stloc, arrayDef)); // store the array in the local variable 

     // loop through the parameters of the method to run 
     for (int i = 0; i < runMethod.Parameters.Count; i++) 
     { 
      newInstructions.Add(processor.Create(OpCodes.Ldloc, arrayDef)); // load the array from the local variable 
      newInstructions.Add(processor.Create(OpCodes.Ldc_I4, i)); // load the index 
      newInstructions.Add(processor.Create(OpCodes.Ldarg, i+1)); // load the argument of the original method (note that parameter 0 is 'this', that's omitted) 

      if (runMethod.Parameters[i].ParameterType.IsValueType) 
      { 
       newInstructions.Add(processor.Create(OpCodes.Box, runMethod.Parameters[i].ParameterType)); // boxing is needed for value types 
      } 
      else 
      { 
       newInstructions.Add(processor.Create(OpCodes.Castclass, _module.TypeSystem.Object)); // casting for reference types 
      } 
      newInstructions.Add(processor.Create(OpCodes.Stelem_Ref)); // store in the array 
     } 

     newInstructions.Add(processor.Create(OpCodes.Ldstr, method)); // load the method name to the stack 
     newInstructions.Add(processor.Create(OpCodes.Ldloc, arrayDef)); // load the array to the stack 
     newInstructions.Add(processor.Create(OpCodes.Call, logEntryMethodReference)); // call the LogEntry() method 


     foreach (var newInstruction in newInstructions.Reverse<Instruction>()) // add the new instructions in referse order 
     { 
      var firstInstruction = runMethod.Body.Instructions[0]; 
      processor.InsertBefore(firstInstruction, newInstruction); 
     } 

     // Write the module with default parameters 
     _module.Write(_targetFileName); 
    } 
} 
関連する問題