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;
		}
Exemple #2
0
        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);
					}
				}
			}
		}