private void ExtractBasicBlocksOfMethod(MethodDefinition definition) { _done.Add(definition); // Make sure definition assembly is loaded. String full_name = definition.Module.FullyQualifiedName; LoadAssembly(full_name); if (definition.Body == null) { System.Console.WriteLine("WARNING: METHOD BODY NULL! " + definition); return; } int instruction_count = definition.Body.Instructions.Count; StackQueue <Mono.Cecil.Cil.Instruction> leader_list = new StackQueue <Mono.Cecil.Cil.Instruction>(); // Each method is a leader of a block. CFGVertex v = (CFGVertex)this.AddVertex(_node_number++); v.Method = definition; v.HasReturnValue = definition.IsReuseSlot; v._entry = v; this._entries.Add(v); v._ordered_list_of_blocks = new List <CFGVertex>(); v._ordered_list_of_blocks.Add(v); for (int j = 0; j < instruction_count; ++j) { // accumulate jump to locations since these split blocks. Mono.Cecil.Cil.Instruction mi = definition.Body.Instructions[j]; //System.Console.WriteLine(mi); Inst i = Inst.Wrap(mi, this); Mono.Cecil.Cil.OpCode op = i.OpCode; Mono.Cecil.Cil.FlowControl fc = op.FlowControl; v._instructions.Add(i); // Verify that mi not owned already. CFG.CFGVertex asdfasdf; Debug.Assert(!partition_of_instructions.TryGetValue(mi, out asdfasdf)); // Update ownership. partition_of_instructions.Add(mi, v); if (fc == Mono.Cecil.Cil.FlowControl.Next) { continue; } if (fc == Mono.Cecil.Cil.FlowControl.Branch || fc == Mono.Cecil.Cil.FlowControl.Cond_Branch) { // Save leader target of branch. object o = i.Operand; // Two cases that I know of: operand is just and instruction, // or operand is an array of instructions (via a switch instruction). Mono.Cecil.Cil.Instruction oo = o as Mono.Cecil.Cil.Instruction; Mono.Cecil.Cil.Instruction[] ooa = o as Mono.Cecil.Cil.Instruction[]; if (oo != null) { leader_list.Push(oo); } else if (ooa != null) { foreach (Mono.Cecil.Cil.Instruction ins in ooa) { Debug.Assert(ins != null); leader_list.Push(ins); } } else { throw new Exception("Unknown operand type for basic block partitioning."); } } } StackQueue <int> ordered_leader_list = new StackQueue <int>(); for (int j = 0; j < instruction_count; ++j) { // Order jump targets. These denote locations // where to split blocks. However, it's ordered, // so that splitting is done from last instruction in block // to first instruction in block. Mono.Cecil.Cil.Instruction i = definition.Body.Instructions[j]; //System.Console.WriteLine("Looking for " + i); if (leader_list.Contains(i)) { ordered_leader_list.Push(j); } } // Split block at jump targets in reverse. while (ordered_leader_list.Count > 0) { int i = ordered_leader_list.Pop(); CFG.CFGVertex new_node = v.Split(i); } //this.Dump(); StackQueue <CFG.CFGVertex> stack = new StackQueue <CFG.CFGVertex>(); foreach (CFG.CFGVertex node in this.VertexNodes) { stack.Push(node); } while (stack.Count > 0) { // Split blocks at branches, not including calls, with following // instruction a leader of new block. CFG.CFGVertex node = stack.Pop(); int node_instruction_count = node._instructions.Count; for (int j = 0; j < node_instruction_count; ++j) { Inst i = node._instructions[j]; Mono.Cecil.Cil.OpCode op = i.OpCode; Mono.Cecil.Cil.FlowControl fc = op.FlowControl; if (fc == Mono.Cecil.Cil.FlowControl.Next) { continue; } if (fc == Mono.Cecil.Cil.FlowControl.Call) { continue; } if (fc == Mono.Cecil.Cil.FlowControl.Meta) { continue; } if (fc == Mono.Cecil.Cil.FlowControl.Phi) { continue; } if (j + 1 >= node_instruction_count) { continue; } CFG.CFGVertex new_node = node.Split(j + 1); stack.Push(new_node); break; } } //this.Dump(); stack = new StackQueue <CFG.CFGVertex>(); foreach (CFG.CFGVertex node in this.VertexNodes) { stack.Push(node); } while (stack.Count > 0) { // Add in all final non-fallthrough branch edges. CFG.CFGVertex node = stack.Pop(); int node_instruction_count = node._instructions.Count; Inst i = node._instructions[node_instruction_count - 1]; Mono.Cecil.Cil.OpCode op = i.OpCode; Mono.Cecil.Cil.FlowControl fc = op.FlowControl; switch (fc) { case Mono.Cecil.Cil.FlowControl.Branch: case Mono.Cecil.Cil.FlowControl.Cond_Branch: { // Two cases: i.Operand is a single instruction, or an array of instructions. if (i.Operand as Mono.Cecil.Cil.Instruction != null) { Mono.Cecil.Cil.Instruction target_instruction = i.Operand as Mono.Cecil.Cil.Instruction; CFGVertex target_node = this.VertexNodes.First( (CFGVertex x) => { if (!x._instructions.First().Instruction.Equals(target_instruction)) { return(false); } return(true); }); if (Options.Singleton.Get(Options.OptionType.DisplaySSAComputation)) { System.Console.WriteLine("Create edge a " + node.Name + " to " + target_node.Name); } this.AddEdge(node, target_node); } else if (i.Operand as Mono.Cecil.Cil.Instruction[] != null) { foreach (Mono.Cecil.Cil.Instruction target_instruction in (i.Operand as Mono.Cecil.Cil.Instruction[])) { CFGVertex target_node = this.VertexNodes.First( (CFGVertex x) => { if (!x._instructions.First().Instruction.Equals(target_instruction)) { return(false); } return(true); }); System.Console.WriteLine("Create edge a " + node.Name + " to " + target_node.Name); this.AddEdge(node, target_node); } } else { throw new Exception("Unknown operand type for conditional branch."); } break; } case Mono.Cecil.Cil.FlowControl.Break: break; case Mono.Cecil.Cil.FlowControl.Call: { // We no longer split at calls. Splitting causes // problems because interprocedural edges are // produced. That's not good because it makes // code too "messy". break; object o = i.Operand; if (o as Mono.Cecil.MethodReference != null) { Mono.Cecil.MethodReference r = o as Mono.Cecil.MethodReference; Mono.Cecil.MethodDefinition d = r.Resolve(); IEnumerable <CFGVertex> target_node_list = this.VertexNodes.Where( (CFGVertex x) => { return(x.Method.FullName == r.FullName && x._entry == x); }); int c = target_node_list.Count(); if (c >= 1) { // target_node is the entry for a method. Also get the exit. CFGVertex target_node = target_node_list.First(); CFGVertex exit_node = target_node.Exit; // check if this is a recursive call. DO NOT BOTHER!! if (node.Method == target_node.Method) { } else { // Create edges from exit to successor blocks of the call. foreach (CFGEdge e in node._Successors) { System.Console.WriteLine("Create edge c " + exit_node.Name + " to " + e.to.Name); this._interprocedure_graph.AddEdge(exit_node, e.to); } // Create edge from node to method entry. System.Console.WriteLine("Create edge b " + node.Name + " to " + target_node.Name); this._interprocedure_graph.AddEdge(node, target_node); } } } break; } case Mono.Cecil.Cil.FlowControl.Meta: break; case Mono.Cecil.Cil.FlowControl.Next: break; case Mono.Cecil.Cil.FlowControl.Phi: break; case Mono.Cecil.Cil.FlowControl.Return: break; case Mono.Cecil.Cil.FlowControl.Throw: break; } } //this.Dump(); }
public void Add(Mono.Cecil.MethodDefinition definition) { // Do not analyze Campy modules generally... if (Options.Singleton.Get(Options.OptionType.DoNotAnalyzeCampyAssemblies)) { if (definition.Module != null && Analysis.IsCampyModuleName(definition.Module.Name)) { return; } } if (_done.Contains(definition)) { return; } if (_to_do.Contains(definition)) { return; } bool ignore = false; foreach (KeyValuePair <String, String> pair in _analysis._filter) { String pat = pair.Key; String ty = pair.Value; // Match based on type "ty". if (ty.Equals("-method")) { // match on name/parameters. Regex reg = new Regex(@"^" + pat + @"$"); String def = definition.ToString(); Match m = reg.Match(def); int ind = m.Index; int l = m.Length; if (!(ind >= 0 && l > 0)) { continue; } ignore = true; break; } else if (ty.Equals("+method")) { // match on name/parameters. Regex reg = new Regex(@"^" + pat + @"$"); String def = definition.ToString(); Match m = reg.Match(def); int ind = m.Index; int l = m.Length; if (!(ind >= 0 && l > 0)) { continue; } ignore = false; break; } else if (ty.Equals("-namespace")) { // match on name/parameters. Regex reg = new Regex(@"^" + pat + @"$"); String def = definition.DeclaringType.Namespace.ToString(); Match m = reg.Match(def); int ind = m.Index; int l = m.Length; if (!(ind >= 0 && l > 0)) { continue; } ignore = true; break; } else if (ty.Equals("+namespace")) { // match on name/parameters. Regex reg = new Regex(@"^" + pat + @"$"); String def = definition.DeclaringType.Namespace.ToString(); Match m = reg.Match(def); int ind = m.Index; int l = m.Length; if (!(ind >= 0 && l > 0)) { continue; } ignore = false; break; } else if (ty.Equals("-assembly")) { // match on name/parameters. Regex reg = new Regex(@"^" + pat + @"$"); String def = definition.Module.Assembly.ToString(); Match m = reg.Match(def); int ind = m.Index; int l = m.Length; if (!(ind >= 0 && l > 0)) { continue; } ignore = true; break; } else if (ty.Equals("+assembly")) { // match on name/parameters. Regex reg = new Regex(@"^" + pat + @"$"); String def = definition.Module.Assembly.ToString(); Match m = reg.Match(def); int ind = m.Index; int l = m.Length; if (!(ind >= 0 && l > 0)) { continue; } ignore = false; break; } } if (Options.Singleton.Get(Options.OptionType.DisplaySSAComputation)) { System.Console.WriteLine((ignore ? "Ignoring " : "Adding ") + definition); } if (ignore) { return; } _to_do.Push(definition); }