Static Value-Flow Analysis
GraphWriter.h
Go to the documentation of this file.
1 //===- Graphs/GraphWriter.h - Write graph to a .dot file --*- C++ -*-===//
2 //
3 // From the LLVM Project with some modifications, under the Apache License v2.0
4 // with LLVM Exceptions. See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file defines a simple interface that can be used to print out generic
10 // LLVM graphs to ".dot" files. "dot" is a tool that is part of the AT&T
11 // graphviz package (http://www.research.att.com/sw/tools/graphviz/) which can
12 // be used to turn the files output by this interface into a variety of
13 // different graphics formats.
14 //
15 // Graphs do not need to implement any interface past what is already required
16 // by the GraphTraits template, but they can choose to implement specializations
17 // of the DOTGraphTraits template if they want to customize the graphs output in
18 // any way.
19 //
20 //===----------------------------------------------------------------------===//
21 
22 #ifndef GRAPHS_GRAPHWRITER_H
23 #define GRAPHS_GRAPHWRITER_H
24 
25 #include "Graphs/GraphTraits.h"
26 #include "Graphs/DOTGraphTraits.h"
27 #include <algorithm>
28 #include <cstddef>
29 #include <iterator>
30 #include <string>
31 #include <type_traits>
32 #include <vector>
33 #include <fstream>
34 #include <sstream>
35 #include <iostream>
36 
37 namespace SVF
38 {
39 
40 namespace DOT // Private functions...
41 {
42 
44 
45 } // end namespace DOT
46 
47 namespace GraphProgram
48 {
49 
50 enum Name
51 {
52  DOT,
53  FDP,
56  CIRCO
57 };
58 
59 } // end namespace GraphProgram
60 
61 template<typename GraphType>
63 {
64  std::ofstream &O;
65  const GraphType &G;
66 
69  using NodeRef = typename GTraits::NodeRef;
70  using node_iterator = typename GTraits::nodes_iterator;
71  using child_iterator = typename GTraits::ChildIteratorType;
73 
74  static_assert(std::is_pointer<NodeRef>::value,
75  "FIXME: Currently GraphWriter requires the NodeRef type to be "
76  "a pointer.\nThe pointer usage should be moved to "
77  "DOTGraphTraits, and removed from GraphWriter itself.");
78 
79  // Writes the edge labels of the node to O and returns true if there are any
80  // edge labels not equal to the empty string "".
81  bool getEdgeSourceLabels(std::stringstream &O2, NodeRef Node)
82  {
83  child_iterator EI = GTraits::child_begin(Node);
84  child_iterator EE = GTraits::child_end(Node);
85  bool hasEdgeSourceLabels = false;
86 
87  for (unsigned i = 0; EI != EE && i != 64; ++EI, ++i)
88  {
89  std::string label = DTraits.getEdgeSourceLabel(Node, EI);
90 
91  if (label.empty())
92  continue;
93 
94  hasEdgeSourceLabels = true;
95 
96  if (i)
97  O2 << "|";
98 
99  O2 << "<s" << i << ">" << DOT::EscapeStr(label);
100  }
101 
102  if (EI != EE && hasEdgeSourceLabels)
103  O2 << "|<s64>truncated...";
104 
105  return hasEdgeSourceLabels;
106  }
107 
108 public:
109  GraphWriter(std::ofstream &o, const GraphType &g, bool SN) : O(o), G(g)
110  {
111  DTraits = DOTTraits(SN);
112  }
113 
114  void writeGraph(const std::string &Title = "")
115  {
116  // Output the header for the graph...
117  writeHeader(Title);
118 
119  // Emit all of the nodes in the graph...
120  writeNodes();
121 
122  // Output any customizations on the graph
124 
125  // Output the end of the graph
126  writeFooter();
127  }
128 
129  void writeHeader(const std::string &Title)
130  {
131  std::string GraphName(DTraits.getGraphName(G));
132 
133  if (!Title.empty())
134  O << "digraph \"" << DOT::EscapeStr(Title) << "\" {\n";
135  else if (!GraphName.empty())
136  O << "digraph \"" << DOT::EscapeStr(GraphName) << "\" {\n";
137  else
138  O << "digraph unnamed {\n";
139 
141  O << "\trankdir=\"BT\";\n";
142 
143  if (!Title.empty())
144  O << "\tlabel=\"" << DOT::EscapeStr(Title) << "\";\n";
145  else if (!GraphName.empty())
146  O << "\tlabel=\"" << DOT::EscapeStr(GraphName) << "\";\n";
148  O << "\n";
149  }
150 
151  void writeFooter()
152  {
153  // Finish off the graph
154  O << "}\n";
155  }
156 
157  void writeNodes()
158  {
159  // Loop over the graph, printing it out...
160  for (const auto Node : nodes<GraphType>(G))
161  if (!isNodeHidden(Node))
162  writeNode(Node);
163  }
164 
166  {
167  return DTraits.isNodeHidden(Node, G);
168  }
169 
170  void writeNode(NodeRef Node)
171  {
172  std::string NodeAttributes = DTraits.getNodeAttributes(Node, G);
173 
174  O << "\tNode" << static_cast<const void*>(Node) << " [shape=record,";
175  if (!NodeAttributes.empty()) O << NodeAttributes << ",";
176  O << "label=\"{";
177 
179  {
181 
182  // If we should include the address of the node in the label, do so now.
184  if (!Id.empty())
185  O << "|" << DOT::EscapeStr(Id);
186 
187  std::string NodeDesc = DTraits.getNodeDescription(Node, G);
188  if (!NodeDesc.empty())
189  O << "|" << DOT::EscapeStr(NodeDesc);
190  }
191 
192  std::string edgeSourceLabels;
193  std::stringstream EdgeSourceLabels(edgeSourceLabels);
194  bool hasEdgeSourceLabels = getEdgeSourceLabels(EdgeSourceLabels, Node);
195 
196  if (hasEdgeSourceLabels)
197  {
198  if (!DTraits.renderGraphFromBottomUp()) O << "|";
199 
200  O << "{" << EdgeSourceLabels.str() << "}";
201 
202  if (DTraits.renderGraphFromBottomUp()) O << "|";
203  }
204 
206  {
208 
209  // If we should include the address of the node in the label, do so now.
211  if (!Id.empty())
212  O << "|" << DOT::EscapeStr(Id);
213 
214  std::string NodeDesc = DTraits.getNodeDescription(Node, G);
215  if (!NodeDesc.empty())
216  O << "|" << DOT::EscapeStr(NodeDesc);
217  }
218 
220  {
221  O << "|{";
222 
223  unsigned i = 0, e = DTraits.numEdgeDestLabels(Node);
224  for (; i != e && i != 64; ++i)
225  {
226  if (i) O << "|";
227  O << "<d" << i << ">"
229  }
230 
231  if (i != e)
232  O << "|<d64>truncated...";
233  O << "}";
234  }
235 
236  O << "}\"];\n"; // Finish printing the "node" line
237 
238  // Output all of the edges now
239  child_iterator EI = GTraits::child_begin(Node);
240  child_iterator EE = GTraits::child_end(Node);
241  for (unsigned i = 0; EI != EE && i != 64; ++EI, ++i)
242  if (!DTraits.isNodeHidden(*EI, G))
243  writeEdge(Node, i, EI);
244  for (; EI != EE; ++EI)
245  if (!DTraits.isNodeHidden(*EI, G))
246  writeEdge(Node, 64, EI);
247  }
248 
249  void writeEdge(NodeRef Node, unsigned edgeidx, child_iterator EI)
250  {
251  if (NodeRef TargetNode = *EI)
252  {
253  int DestPort = -1;
254  if (DTraits.edgeTargetsEdgeSource(Node, EI))
255  {
256  child_iterator TargetIt = DTraits.getEdgeTarget(Node, EI);
257 
258  // Figure out which edge this targets...
259  unsigned Offset =
260  (unsigned)std::distance(GTraits::child_begin(TargetNode), TargetIt);
261  DestPort = static_cast<int>(Offset);
262  }
263 
264  if (DTraits.getEdgeSourceLabel(Node, EI).empty())
265  edgeidx = -1;
266 
267  emitEdge(static_cast<const void*>(Node), edgeidx,
268  static_cast<const void*>(TargetNode), DestPort,
269  DTraits.getEdgeAttributes(Node, EI, G));
270  }
271  }
272 
274  void emitSimpleNode(const void *ID, const std::string &Attr,
275  const std::string &Label, unsigned NumEdgeSources = 0,
276  const std::vector<std::string> *EdgeSourceLabels = nullptr)
277  {
278  O << "\tNode" << ID << "[ ";
279  if (!Attr.empty())
280  O << Attr << ",";
281  O << " label =\"";
282  if (NumEdgeSources) O << "{";
283  O << DOT::EscapeStr(Label);
284  if (NumEdgeSources)
285  {
286  O << "|{";
287 
288  for (unsigned i = 0; i != NumEdgeSources; ++i)
289  {
290  if (i) O << "|";
291  O << "<s" << i << ">";
292  if (EdgeSourceLabels) O << DOT::EscapeStr((*EdgeSourceLabels)[i]);
293  }
294  O << "}}";
295  }
296  O << "\"];\n";
297  }
298 
300  void emitEdge(const void *SrcNodeID, int SrcNodePort,
301  const void *DestNodeID, int DestNodePort,
302  const std::string &Attrs)
303  {
304  if (SrcNodePort > 64) return; // Emanating from truncated part?
305  if (DestNodePort > 64) DestNodePort = 64; // Targeting the truncated part?
306 
307  O << "\tNode" << SrcNodeID;
308  if (SrcNodePort >= 0)
309  O << ":s" << SrcNodePort;
310  O << " -> Node" << DestNodeID;
311  if (DestNodePort >= 0 && DTraits.hasEdgeDestLabels())
312  O << ":d" << DestNodePort;
313 
314  if (!Attrs.empty())
315  O << "[" << Attrs << "]";
316  O << ";\n";
317  }
318 
321  std::ofstream &getOStream()
322  {
323  return O;
324  }
325 };
326 
327 template<typename GraphType>
328 std::ofstream &WriteGraph(std::ofstream &O, const GraphType &G,
329  bool ShortNames = false)
330 {
331  // Start the graph emission process...
332  GraphWriter<GraphType> W(O, G, ShortNames);
333 
334  // Emit the graph.
335  W.writeGraph("");
336 
337  return O;
338 }
339 
344 template <typename GraphType>
345 std::string WriteGraph(const GraphType &G,
346  bool ShortNames = false,
347  std::string Filename = "")
348 {
349 
350  std::ofstream O(Filename);
351 
352  if (O.fail())
353  {
354  std::cerr << "error opening file '" << Filename << "' for writing!\n";
355  O.close();
356  return "";
357  }
358 
359  SVF::WriteGraph(O, G, ShortNames);
360  O.close();
361 
362  std::cerr << " done. \n";
363 
364  return Filename;
365 }
366 
370 template<typename GraphType>
371 void ViewGraph(const GraphType &G,const std::string& name,
372  bool ShortNames = false,
374 {
375  SVF::WriteGraph(G, ShortNames);
376 }
377 
378 } // end namespace llvm
379 
380 #endif // LLVM_SUPPORT_GRAPHWRITER_H
const char *const name
Definition: cJSON.h:264
const char *const string
Definition: cJSON.h:172
const GraphType & G
Definition: GraphWriter.h:65
void emitSimpleNode(const void *ID, const std::string &Attr, const std::string &Label, unsigned NumEdgeSources=0, const std::vector< std::string > *EdgeSourceLabels=nullptr)
emitSimpleNode - Outputs a simple (non-record) node
Definition: GraphWriter.h:274
void writeNode(NodeRef Node)
Definition: GraphWriter.h:170
DOTGraphTraits< GraphType > DOTTraits
Definition: GraphWriter.h:67
std::ofstream & O
Definition: GraphWriter.h:64
void emitEdge(const void *SrcNodeID, int SrcNodePort, const void *DestNodeID, int DestNodePort, const std::string &Attrs)
emitEdge - Output an edge from a simple node into the graph...
Definition: GraphWriter.h:300
DOTTraits DTraits
Definition: GraphWriter.h:72
void writeEdge(NodeRef Node, unsigned edgeidx, child_iterator EI)
Definition: GraphWriter.h:249
bool isNodeHidden(NodeRef Node)
Definition: GraphWriter.h:165
bool getEdgeSourceLabels(std::stringstream &O2, NodeRef Node)
Definition: GraphWriter.h:81
typename GTraits::nodes_iterator node_iterator
Definition: GraphWriter.h:70
void writeHeader(const std::string &Title)
Definition: GraphWriter.h:129
typename GTraits::NodeRef NodeRef
Definition: GraphWriter.h:69
typename GTraits::ChildIteratorType child_iterator
Definition: GraphWriter.h:71
void writeGraph(const std::string &Title="")
Definition: GraphWriter.h:114
std::ofstream & getOStream()
Definition: GraphWriter.h:321
GraphWriter(std::ofstream &o, const GraphType &g, bool SN)
Definition: GraphWriter.h:109
std::string EscapeStr(const std::string &Label)
Definition: GraphWriter.cpp:12
for isBitcode
Definition: BasicTypes.h:68
void ViewGraph(const GraphType &G, const std::string &name, bool ShortNames=false, GraphProgram::Name Program=GraphProgram::DOT)
Definition: GraphWriter.h:371
std::ofstream & WriteGraph(std::ofstream &O, const GraphType &G, bool ShortNames=false)
Definition: GraphWriter.h:328
std::string getNodeLabel(const void *, const GraphType &)
static std::string getNodeIdentifierLabel(const void *, const GraphType &)
static std::string getNodeAttributes(const void *, const GraphType &)
static std::string getGraphName(const GraphType &)
static void addCustomGraphFeatures(const GraphType &, GraphWriter &)
static std::string getEdgeDestLabel(const void *, unsigned)
static std::string getEdgeSourceLabel(const void *, EdgeIter)
static bool edgeTargetsEdgeSource(const void *, EdgeIter)
static unsigned numEdgeDestLabels(const void *)
static EdgeIter getEdgeTarget(const void *, EdgeIter I)
static std::string getEdgeAttributes(const void *, EdgeIter, const GraphType &)
static bool isNodeHidden(const void *, const GraphType &)
static bool renderGraphFromBottomUp()
static std::string getNodeDescription(const void *, const GraphType &)
static std::string getGraphProperties(const GraphType &)
typename GraphType::UnknownGraphTypeError NodeRef
Definition: GraphTraits.h:80