CBMC
dot.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: Dump Goto-Program as DOT Graph
4 
5 Author: Daniel Kroening, kroening@kroening.com
6 
7 \*******************************************************************/
8 
11 
12 #include "dot.h"
13 
14 #include <sstream>
15 
17 
18 #include <langapi/language_util.h>
19 
20 #define DOTGRAPHSETTINGS "color=black;" \
21  "orientation=portrait;" \
22  "fontsize=20;"\
23  "compound=true;"\
24  "size=\"30,40\";"\
25  "ratio=compress;"
26 
27 class dott
28 {
29 public:
30  explicit dott(
31  const goto_modelt &_goto_model):
32  goto_model(_goto_model),
34  {
35  }
36 
37  void output(std::ostream &out);
38 
39 protected:
41 
42  unsigned subgraphscount;
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  {
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";
225  subgraphscount++;
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";
265  subgraphscount++;
266  }
267  }
268 }
269 
270 void 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 
289 std::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,
342  const goto_programt::instructiont &from,
343  const goto_programt::instructiont &to,
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 
359 void dot(const goto_modelt &src, std::ostream &out)
360 {
361  dott dot(src);
362  dot.output(out);
363 }
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
function_mapt function_map
symbol_tablet symbol_table
Symbol table.
Definition: goto_model.h:31
goto_functionst goto_functions
GOTO functions.
Definition: goto_model.h:34
This class represents an instruction in the GOTO intermediate representation.
Definition: goto_program.h:181
unsigned location_number
A globally unique number to identify a program location.
Definition: goto_program.h:559
bool is_backwards_goto() const
Returns true if the instruction is a backwards branch.
Definition: goto_program.h:569
A generic container class for the GOTO intermediate representation of one function.
Definition: goto_program.h:73
instructionst instructions
The list of instructions in the goto program.
Definition: goto_program.h:622
instructionst::const_iterator const_targett
Definition: goto_program.h:615
std::list< instructiont > instructionst
Definition: goto_program.h:612
std::list< const_targett > const_targetst
Definition: goto_program.h:617
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:94
#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)
#define size_type
Definition: unistd.c:347