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 <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
37namespace SVF
38{
39
40namespace DOT // Private functions...
41{
42
43std::string EscapeStr(const std::string &Label);
44
45} // end namespace DOT
46
47namespace GraphProgram
48{
49
58
59} // end namespace GraphProgram
60
61template<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
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
108public:
109 GraphWriter(std::ofstream &o, const GraphType &g, bool SN) : O(o), G(g)
110 {
112 }
113
114 void writeGraph(const std::string &Title = "")
115 {
116 // Output the header for the graph...
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
152 {
153 // Finish off the graph
154 O << "}\n";
155 }
156
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
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.
183 std::string Id = DTraits.getNodeIdentifierLabel(Node, G);
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);
195
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.
210 std::string Id = DTraits.getNodeIdentifierLabel(Node, G);
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
250 {
251 if (NodeRef TargetNode = *EI)
252 {
253 int DestPort = -1;
255 {
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 << "{";
284 if (NumEdgeSources)
285 {
286 O << "|{";
287
288 for (unsigned i = 0; i != NumEdgeSources; ++i)
289 {
290 if (i) O << "|";
291 O << "<s" << 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;
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
327template<typename GraphType>
328std::ofstream &WriteGraph(std::ofstream &O, const GraphType &G,
329 bool ShortNames = false)
330{
331 // Start the graph emission process...
333
334 // Emit the graph.
335 W.writeGraph("");
336
337 return O;
338}
339
344template <typename GraphType>
345std::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
360 O.close();
361
362 std::cerr << " done. \n";
363
364 return Filename;
365}
366
370template<typename GraphType>
371void ViewGraph(const GraphType &G,const std::string& name,
372 bool ShortNames = false,
374{
376}
377
378} // end namespace llvm
379
380#endif // LLVM_SUPPORT_GRAPHWRITER_H
const char *const name
Definition cJSON.h:264
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
void writeNode(NodeRef Node)
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...
DOTTraits DTraits
Definition GraphWriter.h:72
void writeEdge(NodeRef Node, unsigned edgeidx, child_iterator EI)
GenericGraphTraits< GraphType > GTraits
Definition GraphWriter.h:68
bool isNodeHidden(NodeRef Node)
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)
typename GTraits::NodeRef NodeRef
Definition GraphWriter.h:69
typename GTraits::ChildIteratorType child_iterator
Definition GraphWriter.h:71
void writeGraph(const std::string &Title="")
std::ofstream & getOStream()
GraphWriter(std::ofstream &o, const GraphType &g, bool SN)
std::string EscapeStr(const std::string &Label)
for isBitcode
Definition BasicTypes.h:68
void ViewGraph(const GraphType &G, const std::string &name, bool ShortNames=false, GraphProgram::Name Program=GraphProgram::DOT)
llvm::IRBuilder IRBuilder
Definition BasicTypes.h:74
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