cil - Use Cecil to insert begin/end block around functions -


this simple code works fine , allows add beginsample/endsample call around each update/lateupdate/fixedupdate function. doesn't take in consideration return instructions, example result of condition. know how write similar function take in considerations returns endsample call executed under every circumstance?

note not cecil expert, learning now. appears me cecil automatically updates operations returns after calling insertbefore , similar functions. if br opcode jumping specific instruction address, address updated after insertions in order jump original instruction. ok in of cases, in case means if statement skip last inserted operation br operation still point directly final ret instruction. note update, lateupdate , fixedupdate void functions.

foreach (var method in type.methods) {     if ((method.name == "update" || method.name == "lateupdate" || method.name == "fixedupdate") &&         method.hasparameters == false)     {         var beginmethod =             module.importreference(typeof (profiler).getmethod("beginsample",                                                                new[] {typeof (string)}));         var endmethod =             module.importreference(typeof (profiler).getmethod("endsample",                                                                bindingflags.static |                                                                bindingflags.public));          debug.log(method.name + " method found in class: " + type.name);          var ilprocessor = method.body.getilprocessor();          var first = method.body.instructions[0];         ilprocessor.insertbefore(first,                                  instruction.create(opcodes.ldstr,                                                     type.fullname + "." + method.name));         ilprocessor.insertbefore(first, instruction.create(opcodes.call, beginmethod));          var lastret = method.body.instructions[method.body.instructions.count - 1];         ilprocessor.insertbefore(lastret, instruction.create(opcodes.call, endmethod));          changed = true;     } } 

as bonus, if can explain me difference between emit , append newly created instruction same operand. append execute emit under hood or more?

i may have found solution, @ least apparently works. followed code used solve similar problem here:

https://groups.google.com/forum/#!msg/mono-cecil/ne6jbjvefcq/mqv6tgdcb4aj

i adapted purposes , seemed work, although may find out other issues. complete code:

 static bool processassembly(assemblydefinition assembly)  {      var changed = false;       var moduleg = assembly.mainmodule;       var attributeconstructor =              moduleg.importreference(                  typeof(ramjetprofilerpostprocessedassemblyattribute).getconstructor(type.emptytypes));      var attribute = new customattribute(attributeconstructor);      var ramjet = moduleg.importreference(typeof(ramjetprofilerpostprocessedassemblyattribute));      if (assembly.hascustomattributes)      {          var attributes = assembly.customattributes;          foreach (var attr in attributes)          {              if (attr.attributetype.fullname == ramjet.fullname)              {                  debug.logwarning("<color=yellow>skipping already-patched assembly:</color>  " + assembly.name);                  return false;              }          }      }      assembly.customattributes.add(attribute);       foreach (var module in assembly.modules)      {          foreach (var type in module.types)          {              // skip classes related ramjetprofiler              if (type.name.contains("assemblypostprocessor") || type.name.contains("ramjetprofiler"))              {                  // todo: use actual type equals, not string matching                  debug.log("skipping self class : " + type.name);                  continue;              }               if (type.basetype != null && type.basetype.fullname.contains("unityengine.monobehaviour"))              {                  foreach (var method in type.methods)                  {                      if ((method.name == "update" || method.name == "lateupdate" || method.name == "fixedupdate") &&                          method.hasparameters == false)                      {                          var beginmethod =                              module.importreference(typeof(profiler).getmethod("beginsample",                                                                                 new[] { typeof(string) }));                          var endmethod =                              module.importreference(typeof(profiler).getmethod("endsample",                                                                                 bindingflags.static |                                                                                 bindingflags.public));                           debug.log(method.name + " method found in class: " + type.name);                           var ilprocessor = method.body.getilprocessor();                           var first = method.body.instructions[0];                          ilprocessor.insertbefore(first,                                                   instruction.create(opcodes.ldstr,                                                                      type.fullname + "." + method.name));                          ilprocessor.insertbefore(first, instruction.create(opcodes.call, beginmethod));                           var lastcall = instruction.create(opcodes.call, endmethod);                           fixreturns(method, lastcall);                           changed = true;                      }                  }              }          }      }       return changed;  }   static void fixreturns(methoddefinition med, instruction lastcall)  {      methodbody body = med.body;       var instructions = body.instructions;      instruction formallylastinstruction = instructions[instructions.count - 1];      instruction lastleaveinstruction = null;       var lastret = instruction.create(opcodes.ret);      instructions.add(lastcall);      instructions.add(lastret);       (var index = 0; index < instructions.count - 1; index++)      {          var instruction = instructions[index];          if (instruction.opcode == opcodes.ret)          {              instruction leaveinstruction = instruction.create(opcodes.leave, lastcall);              if (instruction == formallylastinstruction)              {                  lastleaveinstruction = leaveinstruction;              }               instructions[index] = leaveinstruction;          }      }       fixbranchtargets(lastleaveinstruction, formallylastinstruction, body);  }   private static void fixbranchtargets(      instruction lastleaveinstruction,      instruction formallylastretinstruction,      methodbody body)  {      (var index = 0; index < body.instructions.count - 2; index++)      {          var instruction = body.instructions[index];          if (instruction.operand != null && instruction.operand == formallylastretinstruction)          {              instruction.operand = lastleaveinstruction;          }      }  } 

basically add ret instuction, replace previous ret (usually one, why should more one?) leave function (don't know means :) ), previous jumps remain valid. differently original code, make leave instruction point endsample call before last ret


Comments

Popular posts from this blog

networking - Vagrant-provisioned VirtualBox VM is not reachable from Ubuntu host -

c# - ASP.NET Core - There is already an object named 'AspNetRoles' in the database -

ruby on rails - ArgumentError: Missing host to link to! Please provide the :host parameter, set default_url_options[:host], or set :only_path to true -