Hi Mort,

>
> Does anyone know what sort of algorithm is used to find matching push
> and pop instructions. I assume that an instruction that pops something
> off the stack can have many instructions that could have pushed it
> when a loop is involved.
>

I have been using ControlFlowGraph from Cecil.Decompiler to do
something similar in a project of mine. You are correct that there are
potentially different possible execution paths that could yield the
stack item(s) at a particular instruction. Take this simple example:

        class Test {
                static void Main()
                {
                        string a = null;
                        string b = "foo";
                        string c = a ?? b;
                }
        }

The IL generated by gmcs for Main() is:

        IL_0000:  ldnull
        IL_0001:  stloc.0
        IL_0002:  ldstr "foo"
        IL_0007:  stloc.1
        IL_0008:  ldloc.0
        IL_0009:  dup
        IL_000a:  brtrue IL_0011

        IL_000f:  pop
        IL_0010:  ldloc.1

        IL_0011:  stloc.2
        IL_0012:  ret

Note that either IL_0008 or IL_0010 could be responsible for the top
stack item at IL_0011. If you would like to use Cecil.Decompiler, here
are a couple extension methods I cooked up for my project that might
help you too:

        using Mono.Cecil.Cil;
        using Cecil.Decompiler;
        using System.Linq;

        // Finds the first instruction(s) responsible for the item at the top
of the stack as visible from the specified instruction.
        public static IEnumerable<Instruction> FindLastStackItem (this
ControlFlowGraph cfg, InstructionBlock block, Instruction current)
        {
                return cfg.FindStackHeight (block, current, cfg.GetData
(current).StackBefore - 1);
        }

        // Finds the last instruction(s) at the specified stack height as
visible from the specified instruction
        public static IEnumerable<Instruction> FindStackHeight (this
ControlFlowGraph cfg, InstructionBlock block, Instruction current, int
stackHeight)
        {       
                while (cfg.GetData (current).StackBefore > stackHeight) {
                        if (current == block.First) {
                                return cfg.GetPredecessors (block).Select (b =>
cfg.FindStackHeight (b, b.Last, stackHeight)).Flatten ().Distinct ();
                        } else
                                current = current.Previous;
                }
                        
                if (current.OpCode == OpCodes.Dup)
                        return cfg.FindLastStackItem (block, current);
                        
                return new Instruction [] { current };
        }
        
        // utility:     
        public static IEnumerable<InstructionBlock> GetPredecessors (this
ControlFlowGraph cfg, InstructionBlock ib)
        {
                return cfg.Blocks.Where (b => b.Successors.Contains (ib));
        }
        public static IEnumerable<T> Flatten<T> (this
IEnumerable<IEnumerable<T>> enumerable)
        {
                foreach (var subenumerable in enumerable)
                        foreach (var item in subenumerable)
                                yield return item;
        }


These methods have worked for me so far, but I am not an expert in
static analysis by any means. Hope this is helpful!

-Alex

-- 
--
mono-cecil

Reply via email to