static public string BuildDotImage (Digraph graph) { if (graph == null) return null; string dotfile = Path.GetTempFileName (); string pngfile = Path.ChangeExtension (dotfile, "png"); using (StreamWriter sw = new StreamWriter (dotfile)) { string dot = graph.ToString (); sw.WriteLine (dot); sw.Close (); } string dotexe = null; if (Environment.OSVersion.Platform == PlatformID.Unix) { dotexe = "dot"; } else { // bad but not really supported so... dotexe = @"C:\Program Files\ATT\Graphviz\bin\dot.exe"; // -Tcmap } string options = String.Format ("-Tpng \"{0}\" -o \"{1}\"", dotfile, pngfile); // process output dot file to get a PNG image ProcessStartInfo psi = new ProcessStartInfo (dotexe, options); psi.WindowStyle = ProcessWindowStyle.Hidden; Process p = System.Diagnostics.Process.Start (psi); Console.WriteLine ("{0} {1}", psi.FileName, psi.Arguments); p.WaitForExit (); // return image filename return pngfile; }
static public string BuildDotImage(Digraph graph) { if (graph == null) { return(null); } string dotfile = Path.GetTempFileName(); string pngfile = Path.ChangeExtension(dotfile, "png"); using (StreamWriter sw = new StreamWriter(dotfile)) { string dot = graph.ToString(); sw.WriteLine(dot); sw.Close(); } string dotexe = null; if (Environment.OSVersion.Platform == PlatformID.Unix) { dotexe = "dot"; } else { // bad but not really supported so... dotexe = @"C:\Program Files\ATT\Graphviz\bin\dot.exe"; // -Tcmap } string options = String.Format("-Tpng \"{0}\" -o \"{1}\"", dotfile, pngfile); // process output dot file to get a PNG image ProcessStartInfo psi = new ProcessStartInfo(dotexe, options); psi.WindowStyle = ProcessWindowStyle.Hidden; Process p = System.Diagnostics.Process.Start(psi); Console.WriteLine("{0} {1}", psi.FileName, psi.Arguments); p.WaitForExit(); // return image filename return(pngfile); }
// FIXME : Determine a maximum to stop generation public void AddToDot (Digraph dot) { Subgraph sg = new Subgraph (); // // some things don't go inside the cluster // StringBuilder noncluster = new StringBuilder (); // StringBuilder dot = new StringBuilder (); // dot.AppendFormat ("\tsubgraph cluster{0} {{{1}", Math.Abs (GetHashCode ()), Environment.NewLine); bool publicType = false; TypeDefinition type = (_type as TypeDefinition); if (type != null) { // much more interesting info in a definition if ((type.Attributes & TypeAttributes.Public) != 0) { publicType = true; // dot.AppendFormat ("\t\tcolor=blue"); sg.Color = "blue"; } } sg.Label = GetClassLabel (); sg.LabelLoc = "b"; sg.LabelJust = "l"; sg.FontName = "tahoma"; sg.FontSize = 8; // dot.AppendFormat ("\t\tlabel = \"{0}\";{1}", GetClassLabel (), Environment.NewLine); // dot.AppendFormat ("\t\tstyle=filled;{0}\t\tcolor=lightgrey;{0}", Environment.NewLine); // dot.AppendFormat ("\t\tfontname=tahoma;{0}\t\tfontsize=8;{0}", Environment.NewLine); // dot.AppendFormat ("\t\tlabelloc=b;{0}\t\tlabeljust=l;{0}", Environment.NewLine); // dot.AppendFormat ("\t\tnode [style=filled,color=white];{0}", Environment.NewLine); // dot.AppendFormat ("fontname=tahoma;fontsize=8;,labelfontname=tahoma,labelfontsize=8];{0}", Environment.NewLine); // icalls if (HasInternalCall) { foreach (MethodDefinition method in _internalcalls) { string icall = Helper.GetMethodString (method); Node node = new Node (icall); node.Attributes ["shape"] = "box"; node.Attributes ["peripheries"] = "2"; DecorateNode (node, method); sg.Nodes.Add (node); // dot.AppendFormat ("\t\t\"{0}\" [shape=box,peripheries=2];{1}", icall, Environment.NewLine); // noncluster.AppendFormat ("\t\"{0}\" -> \"runtime\" [label=\"icall\"{1}];{2}", icall, Helper.GetSecurity (method, null), Environment.NewLine); Edge edge = new Edge (icall, "runtime"); edge.Attributes ["label"] = "icall" + Helper.GetSecurity (method, null); dot.Edges.Add (edge); } } // publics if (HasPublic) { foreach (MethodDefinition method in _publics) { string pub = Helper.GetMethodString (method); Node node = new Node (pub); // string url = Helper.Url (method); // string style = String.Empty; if ((method.Attributes & MethodAttributes.Static) == MethodAttributes.Static) node.Attributes ["style"] = "bold"; if ((method.Attributes & (MethodAttributes.Virtual | MethodAttributes.Final)) == MethodAttributes.Virtual) node.Attributes ["style"] = "dashed"; // dot.AppendFormat ("\t\t\"{0}\" [shape=box,color=blue{1}{2}];{3}", pub, url, style, Environment.NewLine); node.Attributes ["shape"] = "box"; node.Attributes ["color"] = "blue"; string caller = "any code from\\n"; if (publicType) { caller += "anywhere"; } else { caller += GetScopeName (_type.Scope); } DecorateNode (node, method); sg.Nodes.Add (node); // noncluster.AppendFormat ("\t\"{0}\" -> \"{1}\" [style=dotted{2}];{3}", caller, pub, Helper.GetSecurity (null, method), Environment.NewLine); Edge edge = new Edge (caller, pub); edge.Attributes ["style"] = "dotted"; dot.Edges.Add (edge); } } // protected if (HasProtected) { foreach (MethodDefinition method in _protected) { string pub = Helper.GetMethodString (method); Node node = new Node (pub); node.Attributes ["shape"] = "box"; node.Attributes ["color"] = "blueviolet"; DecorateNode (node, method); sg.Nodes.Add (node); // string url = Helper.Url (method); if ((method.Attributes & (MethodAttributes.Virtual | MethodAttributes.Final)) == MethodAttributes.Virtual) { string style; if (node.Attributes.TryGetValue ("style", out style)) node.Attributes ["style"] = style + ",dashed"; else node.Attributes ["style"] = "dashed"; } // dot.AppendFormat ("\t\t\"{0}\" [shape=box,color=blueviolet{1}{2}];{3}", pub, style, url, Environment.NewLine); string caller = "any inherited class"; if (!publicType) { caller += String.Concat (" from\\n", GetScopeName (_type.Scope)); } // noncluster.AppendFormat ("\t\"{0}\" -> \"{1}\" [style=dotted{2}];{3}", caller, pub, Helper.GetSecurity (null, method), Environment.NewLine); Edge edge = new Edge (caller, pub); edge.Attributes ["style"] = "dotted"; dot.Edges.Add (edge); } } // specials (e.g. .cctor) if (HasSpecial) { // no URL available for internal stuff foreach (MethodDefinition method in _specials) { string pub = Helper.GetMethodString (method); Node node = new Node (pub); node.Attributes ["shape"] = "box"; node.Attributes ["color"] = "green"; DecorateNode (node, method); sg.Nodes.Add (node); // dot.AppendFormat ("\t\t\"{0}\" [shape=box,color=green];{1}", pub, Environment.NewLine); // noncluster.AppendFormat ("\t\"unknown caller\" -> \"{0}\" [style=dotted{1}];{2}", pub, Helper.GetSecurity (null, method), Environment.NewLine); Edge edge = new Edge ("unknown caller", pub); edge.Attributes ["style"] = "dotted"; dot.Edges.Add (edge); } } // others if ((_others != null) && (_others.Count > 0)) { // no URL available for internal stuff foreach (MethodDefinition method in _others) { string pub = Helper.GetMethodString (method); Node node = new Node (pub); node.Attributes ["shape"] = "box"; DecorateNode (node, method); sg.Nodes.Add (node); // dot.AppendFormat ("\t\t\"{0}\" [shape=box{1}];{2}", pub, Helper.GetSecurity (null, method), Environment.NewLine); } } // dot.AppendFormat ("\t}}{0}{0}", Environment.NewLine).Append (noncluster); // return dot.ToString (); dot.Subgraphs.Add (sg); }
private Digraph BuildDotFile (MethodDefinition method) { Digraph dot = new Digraph (); dot.Name = "AssemblyDependencies"; dot.AutoConcentrate = true; dot.Label = method.ToString (); dot.LabelLoc = "t"; dot.FontName = "tahoma"; dot.FontSize = 10; bool hasInternalCall = false; bool hasPublic = false; bool hasProtected = false; bool hasSpecial = false; foreach (Cluster c in clusters.Values) { hasInternalCall |= c.HasInternalCall; hasPublic |= c.HasPublic; hasProtected |= c.HasProtected; hasSpecial |= c.HasSpecial; c.AddToDot (dot); } if (hasInternalCall) dot.Nodes.Add (new Node ("runtime")); // if (hasPublic) // dot.AppendFormat ("\t\"any public code\";{0}", Environment.NewLine); // if (hasProtected) // dot.AppendFormat ("\t\"any inherited code\";{0}", Environment.NewLine); if (hasSpecial) dot.Nodes.Add (new Node ("unknown caller")); // calls if (extra_edges.Count > 0) { foreach (Edge edge in extra_edges) { dot.Edges.Add (edge); } } return dot; }
// internal stuff private Digraph GetIlSourceAsDot (MethodDefinition method) { Digraph dot = new Digraph (); dot.Name = "IL"; dot.Label = method.ToString (); dot.LabelLoc = "t"; dot.FontName = "tahoma"; dot.FontSize = 10; if (method.Body != null) { List<IlInstruction> instructions = new List<IlInstruction> (); foreach (Instruction instr in method.Body.Instructions) { IlInstruction i = new IlInstruction (instr); i.Name = instr.OpCode.Name; switch (instr.OpCode.OperandType) { case OperandType.InlineNone: break; case OperandType.InlineSwitch: int[] brchs = instr.Operand as int[]; i.Calls = new List<string> (brchs.Length); for (int j = 0; j < brchs.Length; j++) { string switchtarget = String.Format ("IL_{0}", brchs[j].ToString ("X4")); i.Name += String.Format ("\t{0}{1}", (j > 0) ? ", " : String.Empty, switchtarget); i.Calls.Add (switchtarget); } break; case OperandType.ShortInlineBrTarget: case OperandType.InlineBrTarget: Instruction ins = (instr.Operand as Instruction); string target = String.Format ("IL_{0}", ins.Offset.ToString ("X4")); i.Name = String.Format ("{0} {1}", i.Name, target); i.Calls = new List<string> (1); i.Calls.Add (target); break; case OperandType.InlineString: i.Name = String.Format ("{0} '{1}'", i.Name, instr.Operand); break; default: i.Name = String.Format ("{0} {1}", i.Name, instr.Operand); break; } // add instruction instructions.Add (i); } // build dot for each instructions // first add the nodes foreach (IlInstruction i in instructions) { Node n = i.GetNode (true); dot.Nodes.Add (n); } // then add the edges for (int j = 0; j < instructions.Count; j++) { IlInstruction i = instructions[j]; Node n = i.GetNode (false); if (i.Calls != null) { foreach (string callee in i.Calls) { IlInstruction target = FindCallee (callee, instructions); Node t = target.GetNode (false); Edge e = new Edge (n, t); string label = target.Label; if (label.Length > 0) e.Attributes["label"] = label; dot.Edges.Add (e); } } // by default execution continues to the next instruction // unless - we have an unconditional branch or it's the last instruction if ((j < instructions.Count - 1) && !i.IsUnconditionalBranch ()) { IlInstruction next = (IlInstruction)instructions[j + 1]; Edge e = new Edge (n, next.GetNode (false)); string label = next.Label; if (label.Length > 0) e.Attributes["label"] = label; dot.Edges.Add (e); } } } return dot; }
private Digraph GetDotData (AssemblyDefinition assembly) { if (assembly == null) return null; clusters.Clear (); partial_trust_callers.Clear (); trusted_callers.Clear (); Digraph dot = new Digraph (); dot.Name = "AssemblyDependencies"; dot.AutoConcentrate = true; dot.Label = GetTitleName (assembly.Name); dot.LabelLoc = "t"; dot.FontName = "tahoma"; dot.FontSize = 10; RecurseAssembly (assembly, dot); // process clusters (by public key tokens) foreach (KeyValuePair<string,List<AssemblyNameReference>> kpv in clusters) { Subgraph sg = new Subgraph (); sg.Label = kpv.Key; sg.LabelLoc = "b"; dot.Subgraphs.Add (sg); foreach (AssemblyNameReference reference in kpv.Value) { Node n = new Node (); n.Label = GetFriendlyName (reference); n.Attributes["shape"] = "box"; AssemblyDefinition ad = GetAssemblyFromReference (reference); if (ad != null) { // reference assembly is loaded in memory so we can do more analysis if (HasUnverifiableCode (ad)) { n.Attributes["color"] = "red"; } } else { // default if assembly isn't loaded n.Attributes["style"] = "dashed"; } sg.Nodes.Add (n); } } // process edges (i.e. callers) foreach (string s in partial_trust_callers) { Edge e = new Edge ("partially\\ntrusted\\ncallers\\n", s); e.Attributes["style"] = "dotted"; dot.Edges.Add (e); } foreach (string s in trusted_callers) { Edge e = new Edge ("trusted\\ncallers\\n", s); e.Attributes["style"] = "dotted"; dot.Edges.Add (e); } return dot; }
private void RecurseAssembly (AssemblyDefinition assembly, Digraph dot) { // 2 assemblies can depend on each other (e.g. System.dll and System.Xml.dll) if (!AddToCluster (assembly.Name)) return; string name = GetFriendlyName (assembly.Name); if (AllowPartiallyTrustedCallers (assembly)) { if (!partial_trust_callers.Contains (name)) partial_trust_callers.Add (name); } else { if (!trusted_callers.Contains (name)) trusted_callers.Add (name); } foreach (ModuleDefinition module in assembly.Modules) { foreach (AssemblyNameReference reference in module.AssemblyReferences) { AddToCluster (reference); string refname = GetFriendlyName (reference); dot.Edges.Add (new Edge (name, refname)); AssemblyDefinition ad = GetAssemblyFromReference (reference); if (ad != null) { RecurseAssembly (ad, dot); } } } }