CBMC
Loading...
Searching...
No Matches
dot.cpp
Go to the documentation of this file.
1/*******************************************************************\
2
3Module: Dump Goto-Program as DOT Graph
4
5Author: Daniel Kroening, kroening@kroening.com
6
7\*******************************************************************/
8
11
12#include "dot.h"
13
14#include <sstream>
15
17
19
20#define DOTGRAPHSETTINGS "color=black;" \
21 "orientation=portrait;" \
22 "fontsize=20;"\
23 "compound=true;"\
24 "size=\"30,40\";"\
25 "ratio=compress;"
26
27class dott
28{
29public:
30 explicit dott(
34 {
35 }
36
37 void output(std::ostream &out);
38
39protected:
41
43
44 std::list<std::pair<std::string, exprt>> function_calls;
45 std::list<exprt> clusters;
46
47 void
48 write_dot_subgraph(std::ostream &, const irep_idt &, const goto_programt &);
49
50 void do_dot_function_calls(std::ostream &);
51
52 std::string &escape(std::string &str);
53
54 void write_edge(std::ostream &,
57 const std::string &);
58
59 void find_next(
62 std::set<goto_programt::const_targett, goto_programt::target_less_than> &,
63 std::set<goto_programt::const_targett, goto_programt::target_less_than> &);
64};
65
72 std::ostream &out,
73 const irep_idt &function_id,
74 const goto_programt &goto_program)
75{
76 clusters.push_back(exprt("cluster"));
77 clusters.back().set("name", function_id);
78 clusters.back().set("nr", subgraphscount);
79
80 out << "subgraph \"cluster_" << function_id << "\" {\n";
81 out << "label=\"" << function_id << "\";\n";
82
83 const goto_programt::instructionst &instructions =
84 goto_program.instructions;
85
86 if(instructions.empty())
87 {
88 out << "Node_" << subgraphscount << "_0 " <<
89 "[shape=Mrecord,fontsize=22,label=\"?\"];\n";
90 }
91 else
92 {
93 const namespacet ns(goto_model.symbol_table);
94
95 std::set<goto_programt::const_targett, goto_programt::target_less_than>
96 seen;
98 worklist.push_back(instructions.begin());
99
100 while(!worklist.empty())
101 {
102 goto_programt::const_targett it=worklist.front();
103 worklist.pop_front();
104
105 if(it==instructions.end() ||
106 seen.find(it)!=seen.end()) continue;
107
108 std::stringstream tmp;
109 if(it->is_goto())
110 {
111 if(it->condition().is_true())
112 tmp.str("Goto");
113 else
114 {
115 std::string t = from_expr(ns, function_id, it->condition());
116 while(t[ t.size()-1 ]=='\n')
117 t = t.substr(0, t.size()-1);
118 tmp << escape(t) << "?";
119 }
120 }
121 else if(it->is_assume())
122 {
123 std::string t = from_expr(ns, function_id, it->condition());
124 while(t[ t.size()-1 ]=='\n')
125 t = t.substr(0, t.size()-1);
126 tmp << "Assume\\n(" << escape(t) << ")";
127 }
128 else if(it->is_assert())
129 {
130 std::string t = from_expr(ns, function_id, it->condition());
131 while(t[ t.size()-1 ]=='\n')
132 t = t.substr(0, t.size()-1);
133 tmp << "Assert\\n(" << escape(t) << ")";
134 }
135 else if(it->is_skip())
136 tmp.str("Skip");
137 else if(it->is_end_function())
138 tmp.str("End of Function");
139 else if(it->is_location())
140 tmp.str("Location");
141 else if(it->is_dead())
142 tmp.str("Dead");
143 else if(it->is_atomic_begin())
144 tmp.str("Atomic Begin");
145 else if(it->is_atomic_end())
146 tmp.str("Atomic End");
147 else if(it->is_function_call())
148 {
149 const code_function_callt function_call(
150 it->call_lhs(), it->call_function(), it->call_arguments());
151 std::string t = from_expr(ns, function_id, function_call);
152 while(t[ t.size()-1 ]=='\n')
153 t = t.substr(0, t.size()-1);
154 tmp.str(escape(t));
155
156 std::stringstream ss;
157 ss << "Node_" << subgraphscount << "_" << it->location_number;
158 function_calls.push_back(
159 std::pair<std::string, exprt>(ss.str(), it->call_function()));
160 }
161 else if(
162 it->is_assign() || it->is_decl() || it->is_set_return_value() ||
163 it->is_other())
164 {
165 std::string t = from_expr(ns, function_id, it->code());
166 while(t[ t.size()-1 ]=='\n')
167 t = t.substr(0, t.size()-1);
168 tmp.str(escape(t));
169 }
170 else if(it->is_start_thread())
171 tmp.str("Start of Thread");
172 else if(it->is_end_thread())
173 tmp.str("End of Thread");
174 else if(it->is_throw())
175 tmp.str("THROW");
176 else if(it->is_catch())
177 tmp.str("CATCH");
178 else
179 tmp.str("UNKNOWN");
180
181 out << "Node_" << subgraphscount << "_" << it->location_number;
182 out << " [shape=";
183 if(it->is_goto() && !it->condition().is_constant())
184 out << "diamond";
185 else
186 out <<"Mrecord";
187 out << ",fontsize=22,label=\"";
188 out << tmp.str();
189 out << "\"];\n";
190
191 std::set<goto_programt::const_targett, goto_programt::target_less_than>
192 tres;
193 std::set<goto_programt::const_targett, goto_programt::target_less_than>
194 fres;
195 find_next(instructions, it, tres, fres);
196
197 std::string tlabel;
198 std::string flabel;
199 if(!fres.empty() && !tres.empty())
200 {
201 tlabel = "true";
202 flabel = "false";
203 }
204
205 typedef std::
206 set<goto_programt::const_targett, goto_programt::target_less_than>
207 t;
208
209 for(t::iterator trit=tres.begin();
210 trit!=tres.end();
211 trit++)
212 write_edge(out, *it, **trit, tlabel);
213 for(t::iterator frit=fres.begin();
214 frit!=fres.end();
215 frit++)
216 write_edge(out, *it, **frit, flabel);
217
218 seen.insert(it);
219 const auto temp=goto_program.get_successors(it);
220 worklist.insert(worklist.end(), temp.begin(), temp.end());
221 }
222 }
223
224 out << "}\n";
226}
227
229 std::ostream &out)
230{
231 for(const auto &call : function_calls)
232 {
233 std::list<exprt>::const_iterator cit=clusters.begin();
234 for( ; cit!=clusters.end(); cit++)
235 if(cit->get("name") == call.second.get(ID_identifier))
236 break;
237
238 if(cit!=clusters.end())
239 {
240 out << call.first
241 << " -> "
242 "Node_"
243 << cit->get("nr") << "_0"
244 << " [lhead=\"cluster_" << call.second.get(ID_identifier) << "\","
245 << "color=blue];\n";
246 }
247 else
248 {
249 out << "subgraph \"cluster_" << call.second.get(ID_identifier)
250 << "\" {\n";
251 out << "rank=sink;\n";
252 out << "label=\"" << call.second.get(ID_identifier) << "\";\n";
253 out << "Node_" << subgraphscount << "_0 " <<
254 "[shape=Mrecord,fontsize=22,label=\"?\"];\n";
255 out << "}\n";
256 clusters.push_back(exprt("cluster"));
257 clusters.back().set("name", call.second.get(ID_identifier));
258 clusters.back().set("nr", subgraphscount);
259 out << call.first
260 << " -> "
261 "Node_"
262 << subgraphscount << "_0"
263 << " [lhead=\"cluster_" << call.second.get("identifier") << "\","
264 << "color=blue];\n";
266 }
267 }
268}
269
270void dott::output(std::ostream &out)
271{
272 out << "digraph G {\n";
273 out << DOTGRAPHSETTINGS << '\n';
274
275 for(const auto &gf_entry : goto_model.goto_functions.function_map)
276 {
277 if(gf_entry.second.body_available())
278 write_dot_subgraph(out, gf_entry.first, gf_entry.second.body);
279 }
280
282
283 out << "}\n";
284}
285
289std::string &dott::escape(std::string &str)
290{
291 for(std::string::size_type i=0; i<str.size(); i++)
292 {
293 if(str[i]=='\n')
294 {
295 str[i] = 'n';
296 str.insert(i, "\\");
297 }
298 else if(str[i]=='\"' ||
299 str[i]=='|' ||
300 str[i]=='\\' ||
301 str[i]=='>' ||
302 str[i]=='<' ||
303 str[i]=='{' ||
304 str[i]=='}')
305 {
306 str.insert(i, "\\");
307 i++;
308 }
309 }
310
311 return str;
312}
313
318 const goto_programt::instructionst &instructions,
320 std::set<goto_programt::const_targett, goto_programt::target_less_than> &tres,
321 std::set<goto_programt::const_targett, goto_programt::target_less_than> &fres)
322{
323 if(it->is_goto() && !it->condition().is_false())
324 {
325 for(const auto &target : it->targets)
326 tres.insert(target);
327 }
328
329 if(it->is_goto() && it->condition().is_true())
330 return;
331
332 goto_programt::const_targett next = it; next++;
333 if(next!=instructions.end())
334 fres.insert(next);
335}
336
341 std::ostream &out,
344 const std::string &label)
345{
346 out << "Node_" << subgraphscount << "_" << from.location_number;
347 out << " -> ";
348 out << "Node_" << subgraphscount << "_" << to.location_number << " ";
349 if(!label.empty())
350 {
351 out << "[fontsize=20,label=\"" << label << "\"";
352 if(from.is_backwards_goto() && from.location_number > to.location_number)
353 out << ",color=red";
354 out << "]";
355 }
356 out << ";\n";
357}
358
359void dot(const goto_modelt &src, std::ostream &out)
360{
361 dott dot(src);
362 dot.output(out);
363}
virtual void output(const namespacet &ns, const irep_idt &function_id, const goto_programt &goto_program, std::ostream &out) const
Output the abstract states for a single function.
Definition ai.cpp:39
ait supplies three of the four components needed: an abstract interpreter (in this case handling func...
Definition ai.h:562
goto_instruction_codet representation of a function call statement.
Definition dot.cpp:28
std::list< std::pair< std::string, exprt > > function_calls
Definition dot.cpp:44
std::list< exprt > clusters
Definition dot.cpp:45
std::string & escape(std::string &str)
Escapes a string.
Definition dot.cpp:289
unsigned subgraphscount
Definition dot.cpp:42
void do_dot_function_calls(std::ostream &)
Definition dot.cpp:228
void find_next(const goto_programt::instructionst &, const goto_programt::const_targett &, std::set< goto_programt::const_targett, goto_programt::target_less_than > &, std::set< goto_programt::const_targett, goto_programt::target_less_than > &)
finds an instructions successors (for goto graphs)
Definition dot.cpp:317
void write_dot_subgraph(std::ostream &, const irep_idt &, const goto_programt &)
Write the dot graph that corresponds to the goto program to the output stream.
Definition dot.cpp:71
const goto_modelt & goto_model
Definition dot.cpp:40
dott(const goto_modelt &_goto_model)
Definition dot.cpp:30
void output(std::ostream &out)
Definition dot.cpp:270
void write_edge(std::ostream &, const goto_programt::instructiont &, const goto_programt::instructiont &, const std::string &)
writes an edge from the from node to the to node and with the given label to the output stream (dot f...
Definition dot.cpp:340
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition dstring.h:38
Base class for all expressions.
Definition expr.h:56
This class represents an instruction in the GOTO intermediate representation.
A generic container class for the GOTO intermediate representation of one function.
instructionst instructions
The list of instructions in the goto program.
instructionst::const_iterator const_targett
std::list< instructiont > instructionst
std::list< const_targett > const_targetst
std::list< Target > get_successors(Target target) const
Get control-flow successors of a given instruction.
A namespacet is essentially one or two symbol tables bound together, to allow for symbol lookups in t...
Definition namespace.h:91
#define DOTGRAPHSETTINGS
Definition dot.cpp:20
void dot(const goto_modelt &src, std::ostream &out)
Definition dot.cpp:359
Dump Goto-Program as DOT Graph.
Symbol Table + CFG.
std::string from_expr(const namespacet &ns, const irep_idt &identifier, const exprt &expr)