JUUUUUUHUUUUUU works now :
Here the code, maybe somebody else needs the snippeds sometime :-)
---------------------------------
internal class AssemblyTracing
{
/// <nn />
private readonly string _assemblyPath;
/// <summary>
/// Constructor taking initializing parameter.
/// </summary>
/// <param name="assemblyPath">The path of the assembly where to inject
tracing code.</param>
public AssemblyTracing(string assemblyPath)
{
_assemblyPath = assemblyPath;
}
/// <summary>
/// Injects tracing code to the assembly that this class instance has
been created for.
/// </summary>
public void InjectTracingToAssembly()
{
var assemblyDefinition =
AssemblyDefinition.ReadAssembly(_assemblyPath);
Console.WriteLine("Injecting trace code to assembly \"{0}\"",
_assemblyPath);
foreach (var moduleDefinition in assemblyDefinition.Modules)
{
foreach (var typeDefinition in moduleDefinition.Types)
{
InjectTracingToTypeOfModule(typeDefinition, moduleDefinition);
}
}
assemblyDefinition.Write(_assemblyPath, new WriterParameters {
WriteSymbols = true });
}
/// <nn />
private void InjectTracingToTypeOfModule(TypeDefinition type,
ModuleDefinition moduleDefinition)
{
if (type.IsInterface || type.IsEnum || !type.IsClass)
{
return;
}
foreach (var typeDefinition in type.NestedTypes)
{
InjectTracingToTypeOfModule(typeDefinition, moduleDefinition);
}
FieldDefinition fTraceDomainField = AddFTraceDomainFieldToType(type,
moduleDefinition);
MethodDefinition staticConstructor = GetStaticConstructor(type);
if (staticConstructor == null)
{
staticConstructor = AddStaticConstructorForFTraceDomain(type,
moduleDefinition);
}
AddInitialisationOfFTraceDomainFieldToStaticConstructor(
moduleDefinition,
type,
staticConstructor,
fTraceDomainField);
foreach (var methodDefinition in type.Methods)
{
if (methodDefinition.IsConstructor /*&& methodDefinition.IsStatic*/)
{
continue;
}
if (methodDefinition.HasBody)
{
EncapsulateMethodBodyWithTryFinallyBlock(moduleDefinition,
methodDefinition, fTraceDomainField);
}
}
}
/// <nn />
private static MethodDefinition GetStaticConstructor(TypeDefinition
type)
{
foreach (var method in type.Methods)
{
if (method.IsConstructor && method.IsStatic)
{
return method;
}
}
return null;
}
/// <nn />
private static Instruction
FindFirstInstructionSkipCtor(MethodDefinition med)
{
MethodBody body = med.Body;
if (med.IsConstructor && !med.IsStatic)
{
return body.Instructions.Skip(2).First();
}
return body.Instructions.First();
}
/// <nn />
private static Instruction FixReturns(MethodDefinition med,
ModuleDefinition mod)
{
MethodBody body = med.Body;
Instruction formallyLastInstruction = body.Instructions.Last();
Instruction lastLeaveInstruction = null;
if (med.ReturnType == mod.TypeSystem.Void)
{
var instructions = body.Instructions;
var lastRet = Instruction.Create(OpCodes.Ret);
instructions.Add(lastRet);
for (var index = 0; index < instructions.Count - 1; index++)
{
var instruction = instructions[index];
if (instruction.OpCode == OpCodes.Ret)
{
Instruction leaveInstruction =
Instruction.Create(OpCodes.Leave, lastRet);
if (instruction == formallyLastInstruction)
{
lastLeaveInstruction = leaveInstruction;
}
instructions[index] = leaveInstruction;
}
}
FixBranchTargets(lastLeaveInstruction, formallyLastInstruction,
body);
return lastRet;
}
else
{
var instructions = body.Instructions;
var returnVariable = new VariableDefinition("methodTimerReturn",
med.ReturnType);
body.Variables.Add(returnVariable);
var lastLd = Instruction.Create(OpCodes.Ldloc, returnVariable);
instructions.Add(lastLd);
instructions.Add(Instruction.Create(OpCodes.Ret));
for (var index = 0; index < instructions.Count - 2; index++)
{
var instruction = instructions[index];
if (instruction.OpCode == OpCodes.Ret)
{
Instruction leaveInstruction =
Instruction.Create(OpCodes.Leave, lastLd);
if (instruction == formallyLastInstruction)
{
lastLeaveInstruction = leaveInstruction;
}
instructions[index] = leaveInstruction;
instructions.Insert(index, Instruction.Create(OpCodes.Stloc,
returnVariable));
index++;
}
}
FixBranchTargets(lastLeaveInstruction, formallyLastInstruction,
body);
return lastLd;
}
}
/// <nn />
private static void FixBranchTargets(
Instruction lastLeaveInstruction,
Instruction formallyLastRetInstruction,
MethodBody body)
{
for (var index = 0; index < body.Instructions.Count - 2; index++)
{
var instruction = body.Instructions[index];
if (instruction.Operand != null && instruction.Operand ==
formallyLastRetInstruction)
{
instruction.Operand = lastLeaveInstruction;
}
}
}
/// <nn />
private static void EncapsulateMethodBodyWithTryFinallyBlock(
ModuleDefinition mod,
MethodDefinition med,
FieldDefinition fTraceDomainField)
{
if (med.Body == null || med.Body.Instructions.Count <= 0)
{
Console.WriteLine(med.Name + " has not body or no instructions in
body");
return;
}
med.Body.SimplifyMacros();
ILProcessor ilProcessor = med.Body.GetILProcessor();
var firstInstruction = FindFirstInstructionSkipCtor(med);
Instruction returnInstruction = FixReturns(med, mod);
var beforeReturn = Instruction.Create(OpCodes.Endfinally);
ilProcessor.InsertBefore(returnInstruction, beforeReturn);
var fTraceVar = new VariableDefinition("FTraceVar",
mod.Import(typeof(syngo.Common.Diagnostics.Tracing.FTrace)));
med.Body.Variables.Add(fTraceVar);
/////////////// Start of try block
Instruction nopInstruction1 = Instruction.Create(OpCodes.Nop);
ilProcessor.InsertBefore(firstInstruction, nopInstruction1);
Instruction loadDomainInstruction =
Instruction.Create(OpCodes.Ldsfld, fTraceDomainField);
ilProcessor.InsertAfter(nopInstruction1 , loadDomainInstruction);
Instruction loadMethodNameInstr = Instruction.Create(OpCodes.Ldstr,
med.Name);
ilProcessor.InsertAfter(loadDomainInstruction, loadMethodNameInstr);
var constructor =
typeof(syngo.Common.Diagnostics.Tracing.FTrace).GetConstructor(
new[]
{
typeof(syngo.Common.Diagnostics.Tracing.FTraceDomain),
typeof(string)
});
var constructorReference = mod.Import(constructor);
Instruction newConstructorInstruction =
Instruction.Create(OpCodes.Newobj, constructorReference);
ilProcessor.InsertAfter(loadMethodNameInstr,
newConstructorInstruction); // create new instance of person
Instruction popFTraceVariableInstruction =
Instruction.Create(OpCodes.Stloc, fTraceVar);
////Pop a value from stack and store into local variable at index.
ilProcessor.InsertAfter(newConstructorInstruction,
popFTraceVariableInstruction);
//////// Start Finally block
Instruction nopInstruction2 = Instruction.Create(OpCodes.Nop);
ilProcessor.InsertBefore(beforeReturn, nopInstruction2);
Instruction loadFTraceVarInstruction =
Instruction.Create(OpCodes.Ldloca, fTraceVar);
ilProcessor.InsertAfter(nopInstruction2, loadFTraceVarInstruction);
//Loads local variable onto stack
Instruction callDisposeInstruction = Instruction.Create(OpCodes.Call,
mod.Import(typeof(syngo.Common.Diagnostics.Tracing.FTrace).GetMethod("Dispose")));
ilProcessor.InsertAfter(loadFTraceVarInstruction,
callDisposeInstruction); // calls dispose
///////// End finally block
var handler = new ExceptionHandler(ExceptionHandlerType.Finally)
{
TryStart = nopInstruction1,
TryEnd = nopInstruction2,
HandlerStart = nopInstruction2,
HandlerEnd = returnInstruction,
};
med.Body.ExceptionHandlers.Add(handler);
med.Body.InitLocals = true;
med.Body.OptimizeMacros();
}
/// <nn />
private static FieldDefinition
AddFTraceDomainFieldToType(TypeDefinition type, ModuleDefinition mod)
{
const string FIELDNAME = "FTRACEDOMAIN";
FieldDefinition fTraceDomain = new FieldDefinition(
FIELDNAME,
Mono.Cecil.FieldAttributes.Static |
Mono.Cecil.FieldAttributes.InitOnly,
mod.Import(typeof(syngo.Common.Diagnostics.Tracing.FTraceDomain)));
type.Fields.Add(fTraceDomain);
return fTraceDomain;
}
/// <nn />
private static MethodDefinition AddStaticConstructorForFTraceDomain(
TypeDefinition type,
ModuleDefinition mod)
{
var methodAttributes =
MethodAttributes.Static |
MethodAttributes.HideBySig |
MethodAttributes.SpecialName |
MethodAttributes.RTSpecialName;
var method = new MethodDefinition(".cctor", methodAttributes,
mod.TypeSystem.Void);
method.Body.Instructions.Add(Instruction.Create(OpCodes.Ret));
type.Methods.Add(method);
return method;
}
/// <nn />
private static void
AddInitialisationOfFTraceDomainFieldToStaticConstructor(
ModuleDefinition mod,
TypeDefinition type,
MethodDefinition staticConstructor,
FieldDefinition fTraceDomainField)
{
staticConstructor.Body.SimplifyMacros();
Instruction firstInstruction =
staticConstructor.Body.Instructions.First();
ILProcessor ilProcessor = staticConstructor.Body.GetILProcessor();
var writeLineMethod = typeof(Console).GetMethod("WriteLine", new
Type[] { typeof(string) });
var writeLineRef = mod.Import(writeLineMethod);
Instruction loadInstruction = Instruction.Create(OpCodes.Ldstr,
"Static Constructor of class " + type.Name);
ilProcessor.InsertBefore(firstInstruction, loadInstruction);
Instruction writeInstruction = Instruction.Create(OpCodes.Call,
writeLineRef);
ilProcessor.InsertAfter(loadInstruction, writeInstruction);
Instruction loadClassTypeInstruction =
Instruction.Create(OpCodes.Ldtoken, type);
ilProcessor.InsertAfter(writeInstruction, loadClassTypeInstruction);
Instruction callGetTypeInstruction = Instruction.Create(OpCodes.Call,
mod.Import(typeof(System.Type).GetMethod("GetTypeFromHandle")));
ilProcessor.InsertAfter(loadClassTypeInstruction,
callGetTypeInstruction);
var domainConstructor =
typeof(syngo.Common.Diagnostics.Tracing.FTraceDomain).GetConstructor(new[]
{ typeof(Type) });
var domainConstructorReference = mod.Import(domainConstructor);
Instruction domainConstructorInstruction =
Instruction.Create(OpCodes.Newobj, domainConstructorReference);
ilProcessor.InsertAfter(callGetTypeInstruction,
domainConstructorInstruction); // create new instance of person
Instruction popFTraceDomainVariableInstruction =
Instruction.Create(OpCodes.Stsfld, fTraceDomainField);
//Pop a value from stack and store into local variable at index.
ilProcessor.InsertAfter(domainConstructorInstruction,
popFTraceDomainVariableInstruction);
staticConstructor.Body.OptimizeMacros();
}
}
----------------------------------
Am Freitag, 9. Januar 2015 10:00:40 UTC+1 schrieb Reh Gina:
>
> Yes, thats clear for me, but I am so desperate. I found some more help on
> this page
>
> http://stackoverflow.com/questions/12769699/mono-cecil-injecting-try-finally/12798309#12798309
>
> Everything works fine until I do not add some more custom code and only
> the try finally block. If adding own variables and calls, the il code is
> not valid anymore.
>
> I will talk to my Dev Manager because of 'professional help'. Thanks :-)
>
> Am Freitag, 9. Januar 2015 09:37:38 UTC+1 schrieb Jb Evain:
>>
>> Hi,
>>
>> If this group is all for helping people use Cecil, its purpose is not
>> to debug other people code.
>>
>> If you want professional services around Cecil you can contact me
>> privately.
>>
>> Thanks!
>>
>> Jb
>>
>> On Thu, Jan 8, 2015 at 5:11 PM, Reh Gina <[email protected]> wrote:
>> > I would like to kill my computer, but for now I will go home and
>> restart
>> > tomorrow. Thanks for your help, would it be possible you'll help me a
>> little
>> > bit more?
>> >
>> > Am Donnerstag, 8. Januar 2015 17:08:27 UTC+1 schrieb Reh Gina:
>> >>
>> >> Now I replace the ret instruction by using following code
>> >> [....]
>> >>
>> >>
>> >> Instruction popFTraceVariableInstruction =
>> >> Instruction.Create(OpCodes.Stloc, fTraceVar);
>> >> //Pop a value from stack and store into local variable at index.
>> >> ilProcessor.InsertAfter(newConstructorInstruction,
>> >> popFTraceVariableInstruction);
>> >>
>> >> var endFinally = Instruction.Create(OpCodes.Endfinally);
>> >> var leave = Instruction.Create(OpCodes.Leave, endFinally);
>> >> var ret = Instruction.Create(OpCodes.Ret);
>> >>
>> >> for (int i = 0; i < med.Body.Instructions.Count; i++)
>> >> {
>> >> Instruction instr = med.Body.Instructions[i];
>> >> //Console.WriteLine(instr.ToString());
>> >> if (instr.OpCode == OpCodes.Ret)
>> >> {
>> >> Instruction previous = instr.Previous;
>> >> ilProcessor.Remove(instr);
>> >> ilProcessor.InsertAfter(previous,
>> >> Instruction.Create(OpCodes.Leave, ret));
>> >> }
>> >> }
>> >>
>> >>
>> >> //////// Start Finally block
>> >> Instruction loadFTraceVarInstruction =
>> >> Instruction.Create(OpCodes.Ldloca, fTraceVar);
>> >> ilProcessor.InsertAfter(med.Body.Instructions.Last(),
>> >> loadFTraceVarInstruction); //Loads local variable onto stack
>> >> //ilProcessor.InsertBefore(lastInstruction,
>> >> loadFTraceVarInstruction); //Loads local variable onto stack
>> >>
>> >> [...]
>> >> [...]
>> >>
>> >> ilProcessor.InsertAfter(callDisposeInstruction, endFinally);
>> >> //ilProcessor.InsertAfter(leave, endFinally);
>> >> Instruction nopInstruction = Instruction.Create(OpCodes.Nop);
>> >> ilProcessor.InsertAfter(endFinally, nopInstruction);
>> >> ilProcessor.InsertAfter(nopInstruction, ret);
>> >>
>> >> ///////// End finally block
>> >>
>> >> var handler = new ExceptionHandler(ExceptionHandlerType.Finally)
>> >> {
>> >> TryStart = med.Body.Instructions.First(),
>> >> TryEnd = callDisposeInstruction,
>> >> HandlerStart = callDisposeInstruction,
>> >> HandlerEnd = nopInstruction,
>> >> //CatchType = mod.Import(typeof(Exception)),
>> >> };
>> >> [...]
>> >>
>> >> PEVerify says:
>> >> [IL]: Error:
>> >>
>> [O:\bin\x64\Debug\MeVis.BizLogic.Applications.LiverAnalysis.Viewing.ViewingCP.dll
>>
>>
>> >> :
>> >>
>> MeVis.BizLogic.Applications.LiverAnalysis.Viewing.ViewingCP.AbstractTaskStepBEHandler::Dispose][offset
>>
>>
>> >> 0x000000A9] Stack underflow.
>> >> [IL]: Error:
>> >>
>> [O:\bin\x64\Debug\MeVis.BizLogic.Applications.LiverAnalysis.Viewing.ViewingCP.dll
>>
>>
>> >> :
>> >>
>> MeVis.BizLogic.Applications.LiverAnalysis.Viewing.ViewingCP.AbstractTaskStepBEHandler::set_IsActive][offset
>>
>>
>> >> 0x00000027] jmp / exception into the middle of an instruction.
>> >> [IL]: Error:
>> >>
>> [O:\bin\x64\Debug\MeVis.BizLogic.Applications.LiverAnalysis.Viewing.ViewingCP.dll
>>
>>
>> >> :
>> >> .....
>> >>
>> >>
>> >> ARRRRGGGHHHHH
>> >>
>> >> Am Donnerstag, 8. Januar 2015 16:35:31 UTC+1 schrieb Jb Evain:
>> >>>
>> >>> The error means you can not have a ret instruction inside a protected
>> >>> block.
>> >>>
>> >>> It means that if you're injecting protected blocks, you must make
>> sure
>> >>> that rets in them are replaced by into leave opcodes, that are
>> jumping
>> >>> outside of the protected block where you'll be able to return.
>> >>>
>> >>> I'm afraid there's nothing built-in for this, you'll have to
>> implement
>> >>> it.
>> >>>
>> >>> Jb
>> >>>
>> >>> On Thu, Jan 8, 2015 at 4:27 PM, Reh Gina <[email protected]> wrote:
>> >>> > Something with a return which ist not correct in try block, but how
>> to
>> >>> > I
>> >>> > remove it. Trying this to get work for almost 2 weeks
>> >>> >
>> >>> > Am Donnerstag, 8. Januar 2015 16:25:13 UTC+1 schrieb Reh Gina:
>> >>> >>>
>> >>> >>> Now the correct file attached
>> >>> >
>> >>> > --
>> >>> > --
>> >>> > --
>> >>> > mono-cecil
>> >>> > ---
>> >>> > You received this message because you are subscribed to the Google
>> >>> > Groups
>> >>> > "mono-cecil" group.
>> >>> > To unsubscribe from this group and stop receiving emails from it,
>> send
>> >>> > an
>> >>> > email to [email protected].
>> >>> > For more options, visit https://groups.google.com/d/optout.
>> >
>> > --
>> > --
>> > --
>> > mono-cecil
>> > ---
>> > You received this message because you are subscribed to the Google
>> Groups
>> > "mono-cecil" group.
>> > To unsubscribe from this group and stop receiving emails from it, send
>> an
>> > email to [email protected].
>> > For more options, visit https://groups.google.com/d/optout.
>>
>
--
--
--
mono-cecil
---
You received this message because you are subscribed to the Google Groups
"mono-cecil" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.