Static Value-Flow Analysis
Loading...
Searching...
No Matches
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"
27#include "Util/Options.h"
28#include <algorithm>
29#include <cstddef>
30#include <iterator>
31#include <string>
32#include <type_traits>
33#include <vector>
34#include <fstream>
35#include <sstream>
36#include <iostream>
37
38namespace SVF
39{
40
41namespace DOT // Private functions...
42{
43
44std::string EscapeStr(const std::string &Label);
45
46} // end namespace DOT
47
48namespace GraphProgram
49{
50
59
60} // end namespace GraphProgram
61
62template<typename GraphType>
64{
65 std::ofstream &O;
66 const GraphType &G;
67
70 using NodeRef = typename GTraits::NodeRef;
71 using node_iterator = typename GTraits::nodes_iterator;
72 using child_iterator = typename GTraits::ChildIteratorType;
74
75 static_assert(std::is_pointer<NodeRef>::value,
76 "FIXME: Currently GraphWriter requires the NodeRef type to be "
77 "a pointer.\nThe pointer usage should be moved to "
78 "DOTGraphTraits, and removed from GraphWriter itself.");
79
80 // Writes the edge labels of the node to O and returns true if there are any
81 // edge labels not equal to the empty string "".
82 bool getEdgeSourceLabels(std::stringstream &O2, NodeRef Node)
83 {
84 child_iterator EI = GTraits::child_begin(Node);
85 child_iterator EE = GTraits::child_end(Node);
86 bool hasEdgeSourceLabels = false;
87
88 for (unsigned i = 0; EI != EE && i != 64; ++EI, ++i)
89 {
90 std::string label = DTraits.getEdgeSourceLabel(Node, EI);
91
92 if (label.empty())
93 continue;
94
96
97 if (i)
98 O2 << "|";
99
100 O2 << "<s" << i << ">" << DOT::EscapeStr(label);
101 }
102
103 if (EI != EE && hasEdgeSourceLabels)
104 O2 << "|<s64>truncated...";
105
106 return hasEdgeSourceLabels;
107 }
108
109public:
110 GraphWriter(std::ofstream &o, const GraphType &g, bool SN) : O(o), G(g)
111 {
113 }
114
115 void writeGraph(const std::string &Title = "")
116 {
117 // Output the header for the graph...
119
120 // Emit all of the nodes in the graph...
121 writeNodes();
122
123 // Output any customizations on the graph
125
126 // Output the end of the graph
127 writeFooter();
128 }
129
130 void writeHeader(const std::string &Title)
131 {
132 std::string GraphName(DTraits.getGraphName(G));
133
134 if (!Title.empty())
135 O << "digraph \"" << DOT::EscapeStr(Title) << "\" {\n";
136 else if (!GraphName.empty())
137 O << "digraph \"" << DOT::EscapeStr(GraphName) << "\" {\n";
138 else
139 O << "digraph unnamed {\n";
140
142 O << "\trankdir=\"BT\";\n";
143
144 if (!Title.empty())
145 O << "\tlabel=\"" << DOT::EscapeStr(Title) << "\";\n";
146 else if (!GraphName.empty())
147 O << "\tlabel=\"" << DOT::EscapeStr(GraphName) << "\";\n";
149 O << "\n";
150 }
151
153 {
154 // Finish off the graph
155 O << "}\n";
156 }
157
159 {
160 // Loop over the graph, printing it out...
161 for (const auto Node : nodes<GraphType>(G))
162 if (!isNodeHidden(Node))
163 writeNode(Node);
164 }
165
167 {
168 return DTraits.isNodeHidden(Node, G);
169 }
170
172 {
173 std::string NodeAttributes = DTraits.getNodeAttributes(Node, G);
174
175 O << "\tNode" << static_cast<const void*>(Node) << " [";
176 if (!NodeAttributes.empty()) O << NodeAttributes << ",";
177 O << "label=\"{";
178
180 {
181 std::string label = DTraits.getNodeLabel(Node, G);
182 if (label.length() > Options::MaxNodeLabelLength())
183 {
184 label = label.substr(0, Options::MaxNodeLabelLength()) + "...";
185 }
186
188
189 // If we should include the address of the node in the label, do so now.
190 std::string Id = DTraits.getNodeIdentifierLabel(Node, G);
191 if (!Id.empty())
192 O << "|" << DOT::EscapeStr(Id);
193
194 std::string NodeDesc = DTraits.getNodeDescription(Node, G);
195 if (!NodeDesc.empty())
196 O << "|" << DOT::EscapeStr(NodeDesc);
197 }
198
199 std::string edgeSourceLabels;
200 std::stringstream EdgeSourceLabels(edgeSourceLabels);
202
204 {
205 if (!DTraits.renderGraphFromBottomUp()) O << "|";
206
207 O << "{" << EdgeSourceLabels.str() << "}";
208
209 if (DTraits.renderGraphFromBottomUp()) O << "|";
210 }
211
213 {
215
216 // If we should include the address of the node in the label, do so now.
217 std::string Id = DTraits.getNodeIdentifierLabel(Node, G);
218 if (!Id.empty())
219 O << "|" << DOT::EscapeStr(Id);
220
221 std::string NodeDesc = DTraits.getNodeDescription(Node, G);
222 if (!NodeDesc.empty())
223 O << "|" << DOT::EscapeStr(NodeDesc);
224 }
225
227 {
228 O << "|{";
229
230 unsigned i = 0, e = DTraits.numEdgeDestLabels(Node);
231 for (; i != e && i != 64; ++i)
232 {
233 if (i) O << "|";
234 O << "<d" << i << ">"
236 }
237
238 if (i != e)
239 O << "|<d64>truncated...";
240 O << "}";
241 }
242
243 O << "}\"];\n"; // Finish printing the "node" line
244
245 // Output all of the edges now
246 child_iterator EI = GTraits::child_begin(Node);
247 child_iterator EE = GTraits::child_end(Node);
248 for (unsigned i = 0; EI != EE && i != 64; ++EI, ++i)
249 if (!DTraits.isNodeHidden(*EI, G))
250 writeEdge(Node, i, EI);
251 for (; EI != EE; ++EI)
252 if (!DTraits.isNodeHidden(*EI, G))
253 writeEdge(Node, 64, EI);
254 }
255
257 {
258 if (NodeRef TargetNode = *EI)
259 {
260 int DestPort = -1;
262 {
264
265 // Figure out which edge this targets...
266 unsigned Offset =
267 (unsigned)std::distance(GTraits::child_begin(TargetNode), TargetIt);
268 DestPort = static_cast<int>(Offset);
269 }
270
271 if (DTraits.getEdgeSourceLabel(Node, EI).empty())
272 edgeidx = -1;
273
274 emitEdge(static_cast<const void*>(Node), edgeidx,
275 static_cast<const void*>(TargetNode), DestPort,
276 DTraits.getEdgeAttributes(Node, EI, G));
277 }
278 }
279
281 void emitSimpleNode(const void *ID, const std::string &Attr,
282 const std::string &Label, unsigned NumEdgeSources = 0,
283 const std::vector<std::string> *EdgeSourceLabels = nullptr)
284 {
285 O << "\tNode" << ID << "[ ";
286 if (!Attr.empty())
287 O << Attr << ",";
288 O << " label =\"";
289 if (NumEdgeSources) O << "{";
291 if (NumEdgeSources)
292 {
293 O << "|{";
294
295 for (unsigned i = 0; i != NumEdgeSources; ++i)
296 {
297 if (i) O << "|";
298 O << "<s" << i << ">";
300 }
301 O << "}}";
302 }
303 O << "\"];\n";
304 }
305
307 void emitEdge(const void *SrcNodeID, int SrcNodePort,
308 const void *DestNodeID, int DestNodePort,
309 const std::string &Attrs)
310 {
311 if (SrcNodePort > 64) return; // Emanating from truncated part?
312 if (DestNodePort > 64) DestNodePort = 64; // Targeting the truncated part?
313
314 O << "\tNode" << SrcNodeID;
315 if (SrcNodePort >= 0)
316 O << ":s" << SrcNodePort;
317 O << " -> Node" << DestNodeID;
319 O << ":d" << DestNodePort;
320
321 if (!Attrs.empty())
322 O << "[" << Attrs << "]";
323 O << ";\n";
324 }
325
328 std::ofstream &getOStream()
329 {
330 return O;
331 }
332};
333
334template<typename GraphType>
335std::ofstream &WriteGraph(std::ofstream &O, const GraphType &G,
336 bool ShortNames = false)
337{
338 // Start the graph emission process...
340
341 // Emit the graph.
342 W.writeGraph("");
343
344 return O;
345}
346
351template <typename GraphType>
352std::string WriteGraph(const GraphType &G,
353 bool ShortNames = false,
354 std::string Filename = "")
355{
356
357 std::ofstream O(Filename);
358
359 if (O.fail())
360 {
361 std::cerr << "error opening file '" << Filename << "' for writing!\n";
362 O.close();
363 return "";
364 }
365
367 O.close();
368
369 std::cerr << " done. \n";
370
371 return Filename;
372}
373
377template<typename GraphType>
378void ViewGraph(const GraphType &G,const std::string& name,
379 bool ShortNames = false,
381{
383}
384
385} // end namespace llvm
386
387#endif // LLVM_SUPPORT_GRAPHWRITER_H
const char *const name
Definition cJSON.h:264
const GraphType & G
Definition GraphWriter.h:66
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
void writeNode(NodeRef Node)
DOTGraphTraits< GraphType > DOTTraits
Definition GraphWriter.h:68
std::ofstream & O
Definition GraphWriter.h:65
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...
DOTTraits DTraits
Definition GraphWriter.h:73
void writeEdge(NodeRef Node, unsigned edgeidx, child_iterator EI)
GenericGraphTraits< GraphType > GTraits
Definition GraphWriter.h:69
bool isNodeHidden(NodeRef Node)
bool getEdgeSourceLabels(std::stringstream &O2, NodeRef Node)
Definition GraphWriter.h:82
typename GTraits::nodes_iterator node_iterator
Definition GraphWriter.h:71
void writeHeader(const std::string &Title)
typename GTraits::NodeRef NodeRef
Definition GraphWriter.h:70
typename GTraits::ChildIteratorType child_iterator
Definition GraphWriter.h:72
void writeGraph(const std::string &Title="")
std::ofstream & getOStream()
GraphWriter(std::ofstream &o, const GraphType &g, bool SN)
static const Option< u32_t > MaxNodeLabelLength
Definition Options.h:271
std::string EscapeStr(const std::string &Label)
for isBitcode
Definition BasicTypes.h:70
void ViewGraph(const GraphType &G, const std::string &name, bool ShortNames=false, GraphProgram::Name Program=GraphProgram::DOT)
llvm::IRBuilder IRBuilder
Definition BasicTypes.h:76
std::ofstream & WriteGraph(std::ofstream &O, const GraphType &G, bool ShortNames=false)
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