CBMC
show_program.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: Output of the program (SSA) constraints
4 
5 Author: Daniel Kroening, kroening@kroening.com
6 
7 \*******************************************************************/
8 
11 
12 #include "show_program.h"
13 
14 #include <fstream>
15 #include <iostream>
16 
18 
19 #include <langapi/language_util.h>
20 
21 #include <util/byte_operators.h>
22 #include <util/json_irep.h>
23 #include <util/ui_message.h>
24 
30 static void show_step(
31  const namespacet &ns,
32  const SSA_stept &step,
33  const std::string &annotation,
34  std::size_t &count)
35 {
36  const irep_idt &function_id = step.source.function_id;
37 
38  std::string string_value = (step.is_shared_read() || step.is_shared_write())
39  ? from_expr(ns, function_id, step.ssa_lhs)
40  : from_expr(ns, function_id, step.cond_expr);
41  if(step.ignore)
42  std::cout << "(sliced) ";
43  else
44  std::cout << '(' << count << ") ";
45  if(annotation.empty())
46  std::cout << string_value;
47  else
48  std::cout << annotation << '(' << string_value << ')';
49  std::cout << '\n';
50 
51  if(!step.guard.is_true())
52  {
53  const std::string guard_string = from_expr(ns, function_id, step.guard);
54  std::cout << std::string(std::to_string(count).size() + 3, ' ');
55  std::cout << "guard: " << guard_string << '\n';
56  }
57 
58  ++count;
59 }
60 
61 void show_program(const namespacet &ns, const symex_target_equationt &equation)
62 {
63  std::size_t count = 1;
64 
65  std::cout << '\n' << "Program constraints:" << '\n';
66 
67  for(const auto &step : equation.SSA_steps)
68  {
69  std::cout << "// " << step.source.pc->location_number << " ";
70  std::cout << step.source.pc->source_location().as_string() << "\n";
71 
72  if(step.is_assignment())
73  show_step(ns, step, "", count);
74  else if(step.is_assert())
75  show_step(ns, step, "ASSERT", count);
76  else if(step.is_assume())
77  show_step(ns, step, "ASSUME", count);
78  else if(step.is_constraint())
79  {
80  PRECONDITION(step.guard.is_true());
81  show_step(ns, step, "CONSTRAINT", count);
82  }
83  else if(step.is_shared_read())
84  show_step(ns, step, "SHARED_READ", count);
85  else if(step.is_shared_write())
86  show_step(ns, step, "SHARED_WRITE", count);
87  }
88 }
89 
90 template <typename expr_typet>
91 std::size_t count_expr_typed(const exprt &expr)
92 {
93  static_assert(
94  std::is_base_of<exprt, expr_typet>::value,
95  "`expr_typet` is expected to be a type of `exprt`.");
96 
97  std::size_t count = 0;
98  expr.visit_pre([&](const exprt &e) {
99  if(can_cast_expr<expr_typet>(e))
100  count++;
101  });
102 
103  return count;
104 }
105 
106 bool duplicated_previous_step(const SSA_stept &ssa_step)
107 {
108  return !(
109  ssa_step.is_assignment() || ssa_step.is_assert() || ssa_step.is_assume() ||
110  ssa_step.is_constraint() || ssa_step.is_shared_read() ||
111  ssa_step.is_shared_write());
112 }
113 
115  messaget::mstreamt &out,
116  const namespacet &ns,
117  const SSA_stept &ssa_step,
118  const exprt &ssa_expr)
119 {
120  const irep_idt &function_id = ssa_step.source.function_id;
121  const std::string ssa_expr_as_string = from_expr(ns, function_id, ssa_expr);
122 
123  out << messaget::faint << "// " << ssa_step.source.pc->location_number << " ";
124  out << ssa_step.source.pc->source_location().as_string() << "\n"
125  << messaget::reset;
126  out << ssa_expr_as_string << "\n";
127 }
128 
130  const namespacet &ns,
131  const SSA_stept &ssa_step,
132  const exprt &ssa_expr)
133 {
134  const std::string key_srcloc = "sourceLocation";
135  const std::string key_ssa_expr = "ssaExpr";
136  const std::string key_ssa_expr_as_string = "ssaExprString";
137 
138  const irep_idt &function_id = ssa_step.source.function_id;
139  const std::string ssa_expr_as_string = from_expr(ns, function_id, ssa_expr);
140 
141  json_objectt json_ssa_step{
142  {key_srcloc, json(ssa_step.source.pc->source_location())},
143  {key_ssa_expr_as_string, json_stringt(ssa_expr_as_string)},
144  {key_ssa_expr, json_irept(false).convert_from_irep(ssa_expr)}};
145 
146  return json_ssa_step;
147 }
148 
149 template <typename expr_typet>
151  messaget::mstreamt &out,
152  const namespacet &ns,
153  const symex_target_equationt &equation)
154 {
155  std::size_t equation_byte_op_count = 0;
156  for(const auto &step : equation.SSA_steps)
157  {
158  if(duplicated_previous_step(step))
159  continue;
160 
161  const exprt &ssa_expr = step.get_ssa_expr();
162  const std::size_t ssa_expr_byte_op_count =
163  count_expr_typed<expr_typet>(ssa_expr);
164 
165  if(ssa_expr_byte_op_count == 0)
166  continue;
167 
168  equation_byte_op_count += ssa_expr_byte_op_count;
169  show_ssa_step_plain(out, ns, step, ssa_expr);
170  }
171 
172  if(std::is_same<expr_typet, byte_extract_exprt>::value)
173  out << '\n' << "Number of byte extracts: ";
174  else if(std::is_same<expr_typet, byte_update_exprt>::value)
175  out << '\n' << "Number of byte updates: ";
176  else
177  UNREACHABLE;
178 
179  out << equation_byte_op_count << '\n';
180  out << messaget::eom;
181 }
182 
183 template <typename expr_typet>
185 {
186  if(std::is_same<expr_typet, byte_extract_exprt>::value)
187  return "byteExtractList";
188  else if(std::is_same<expr_typet, byte_update_exprt>::value)
189  return "byteUpdateList";
190  else
191  UNREACHABLE;
192 }
193 
194 template <typename expr_typet>
196 {
197  if(std::is_same<expr_typet, byte_extract_exprt>::value)
198  return "numOfExtracts";
199  else if(std::is_same<expr_typet, byte_update_exprt>::value)
200  return "numOfUpdates";
201  else
202  UNREACHABLE;
203 }
204 
205 template <typename expr_typet>
208 {
209  // Get key values to be used in the json output based on byte operation type
210  // 1. json_get_key_byte_op_list():
211  // returns relevant json object key string where object records
212  // a list of expressions for given byte operation.
213  // 2. json_get_key_byte_op_num():
214  // returns relevant json object key string where object number
215  // of given byte operation.
216 
217  const std::string key_byte_op_list = json_get_key_byte_op_list<expr_typet>();
218  const std::string key_byte_op_num = json_get_key_byte_op_num<expr_typet>();
219 
220  json_objectt byte_op_stats;
221  json_arrayt &byte_op_list = byte_op_stats[key_byte_op_list].make_array();
222 
223  std::size_t equation_byte_op_count = 0;
224  for(const auto &step : equation.SSA_steps)
225  {
226  if(duplicated_previous_step(step))
227  continue;
228 
229  const exprt &ssa_expr = step.get_ssa_expr();
230  const std::size_t ssa_expr_byte_op_count =
231  count_expr_typed<expr_typet>(ssa_expr);
232 
233  if(ssa_expr_byte_op_count == 0)
234  continue;
235 
236  equation_byte_op_count += ssa_expr_byte_op_count;
237  byte_op_list.push_back(get_ssa_step_json(ns, step, ssa_expr));
238  }
239 
240  byte_op_stats[key_byte_op_num] =
241  json_numbert(std::to_string(equation_byte_op_count));
242 
243  return byte_op_stats;
244 }
245 
246 // Get key values to be used in the json output based on byte operation type
247 // 1. json_get_key_byte_op_stats():
248 // returns relevant json object key string where object records
249 // statistics for given byte operation.
250 template <typename expr_typet>
252 {
253  if(std::is_same<expr_typet, byte_extract_exprt>::value)
254  return "byteExtractStats";
255  else if(std::is_same<expr_typet, byte_update_exprt>::value)
256  return "byteUpdateStats";
257  else
258  UNREACHABLE;
259 }
260 
261 bool is_outfile_specified(const optionst &options)
262 {
263  const std::string &filename = options.get_option("outfile");
264  return (!filename.empty() && filename != "-");
265 }
266 
268  ui_message_handlert &ui_message_handler,
269  std::ostream &out,
270  bool outfile_given,
271  const namespacet &ns,
272  const symex_target_equationt &equation)
273 {
274  messaget msg(ui_message_handler);
275  if(outfile_given)
276  {
277  stream_message_handlert mout_handler(out);
278  messaget mout(mout_handler);
279 
280  msg.status() << "\nByte Extracts written to file" << messaget::eom;
281  show_byte_op_plain<byte_extract_exprt>(mout.status(), ns, equation);
282 
283  msg.status() << "\nByte Updates written to file" << messaget::eom;
284  show_byte_op_plain<byte_update_exprt>(mout.status(), ns, equation);
285  }
286  else
287  {
288  msg.status() << "\nByte Extracts:" << messaget::eom;
289  show_byte_op_plain<byte_extract_exprt>(msg.status(), ns, equation);
290 
291  msg.status() << "\nByte Updates:" << messaget::eom;
292  show_byte_op_plain<byte_update_exprt>(msg.status(), ns, equation);
293  }
294 }
295 
297  std::ostream &out,
298  const namespacet &ns,
299  const symex_target_equationt &equation)
300 {
301  json_objectt byte_ops_stats{
302  {json_get_key_byte_op_stats<byte_extract_exprt>(),
303  get_byte_op_json<byte_extract_exprt>(ns, equation)},
304  {json_get_key_byte_op_stats<byte_update_exprt>(),
305  get_byte_op_json<byte_update_exprt>(ns, equation)}};
306 
307  json_objectt json_result;
308  json_result["byteOpsStats"] = byte_ops_stats;
309 
310  out << ",\n" << json_result;
311 }
312 
313 void show_byte_ops_xml(ui_message_handlert &ui_message_handler)
314 {
315  messaget msg(ui_message_handler);
316  msg.error()
317  << "XML UI not supported for displaying byte extracts and updates."
318  << " Try --json-ui instead" << messaget::eom;
319 
320  return;
321 }
322 
324  const optionst &options,
325  ui_message_handlert &ui_message_handler,
326  const namespacet &ns,
327  const symex_target_equationt &equation)
328 {
329  const std::string &filename = options.get_option("outfile");
330  const bool outfile_given = is_outfile_specified(options);
331 
332  std::ofstream of;
333 
334  if(outfile_given)
335  {
336  of.open(filename, std::fstream::out);
337  if(!of)
339  "failed to open output file: " + filename, "--outfile");
340  }
341 
342  std::ostream &out = outfile_given ? of : std::cout;
343 
344  switch(ui_message_handler.get_ui())
345  {
347  show_byte_ops_xml(ui_message_handler);
348  break;
349 
351  show_byte_ops_json(out, ns, equation);
352  break;
353 
355  show_byte_ops_plain(ui_message_handler, out, outfile_given, ns, equation);
356  break;
357  }
358 }
messaget
Class that provides messages with a built-in verbosity 'level'.
Definition: message.h:154
UNREACHABLE
#define UNREACHABLE
This should be used to mark dead code.
Definition: invariant.h:503
dstringt
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition: dstring.h:36
json_numbert
Definition: json.h:290
show_program
void show_program(const namespacet &ns, const symex_target_equationt &equation)
Print the steps of equation on the standard output.
Definition: show_program.cpp:61
symex_target_equation.h
ui_message_handlert
Definition: ui_message.h:21
messaget::reset
static const commandt reset
return to default formatting, as defined by the terminal
Definition: message.h:343
is_outfile_specified
bool is_outfile_specified(const optionst &options)
Definition: show_program.cpp:261
ui_message_handlert::uit::XML_UI
@ XML_UI
optionst
Definition: options.h:22
show_step
static void show_step(const namespacet &ns, const SSA_stept &step, const std::string &annotation, std::size_t &count)
Output a single SSA step.
Definition: show_program.cpp:30
duplicated_previous_step
bool duplicated_previous_step(const SSA_stept &ssa_step)
Definition: show_program.cpp:106
optionst::get_option
const std::string get_option(const std::string &option) const
Definition: options.cpp:67
show_byte_op_plain
void show_byte_op_plain(messaget::mstreamt &out, const namespacet &ns, const symex_target_equationt &equation)
Definition: show_program.cpp:150
SSA_stept
Single SSA step in the equation.
Definition: ssa_step.h:46
symex_targett::sourcet::pc
goto_programt::const_targett pc
Definition: symex_target.h:42
messaget::status
mstreamt & status() const
Definition: message.h:414
SSA_stept::is_assert
bool is_assert() const
Definition: ssa_step.h:52
get_ssa_step_json
json_objectt get_ssa_step_json(const namespacet &ns, const SSA_stept &ssa_step, const exprt &ssa_expr)
Definition: show_program.cpp:129
exprt
Base class for all expressions.
Definition: expr.h:55
json_get_key_byte_op_stats
std::string json_get_key_byte_op_stats()
Definition: show_program.cpp:251
to_string
std::string to_string(const string_not_contains_constraintt &expr)
Used for debug printing.
Definition: string_constraint.cpp:58
messaget::eom
static eomt eom
Definition: message.h:297
SSA_stept::guard
exprt guard
Definition: ssa_step.h:139
exprt::is_true
bool is_true() const
Return whether the expression is a constant representing true.
Definition: expr.cpp:34
SSA_stept::source
symex_targett::sourcet source
Definition: ssa_step.h:49
json_irep.h
SSA_stept::is_constraint
bool is_constraint() const
Definition: ssa_step.h:72
json_arrayt
Definition: json.h:164
SSA_stept::is_shared_write
bool is_shared_write() const
Definition: ssa_step.h:107
SSA_stept::is_shared_read
bool is_shared_read() const
Definition: ssa_step.h:102
json_objectt
Definition: json.h:299
ui_message_handlert::get_ui
virtual uit get_ui() const
Definition: ui_message.h:33
namespacet
A namespacet is essentially one or two symbol tables bound together, to allow for symbol lookups in t...
Definition: namespace.h:90
show_byte_ops_json
void show_byte_ops_json(std::ostream &out, const namespacet &ns, const symex_target_equationt &equation)
Definition: show_program.cpp:296
byte_operators.h
Expression classes for byte-level operators.
messaget::error
mstreamt & error() const
Definition: message.h:399
messaget::faint
static const commandt faint
render text with faint font
Definition: message.h:385
SSA_stept::ssa_lhs
ssa_exprt ssa_lhs
Definition: ssa_step.h:143
ui_message_handlert::uit::JSON_UI
@ JSON_UI
json_get_key_byte_op_list
std::string json_get_key_byte_op_list()
Definition: show_program.cpp:184
language_util.h
SSA_stept::cond_expr
exprt cond_expr
Definition: ssa_step.h:149
show_ssa_step_plain
void show_ssa_step_plain(messaget::mstreamt &out, const namespacet &ns, const SSA_stept &ssa_step, const exprt &ssa_expr)
Definition: show_program.cpp:114
PRECONDITION
#define PRECONDITION(CONDITION)
Definition: invariant.h:463
json
static void json(json_objectT &result, const irep_idt &property_id, const property_infot &property_info)
Definition: properties.cpp:120
jsont::make_array
json_arrayt & make_array()
Definition: json.h:420
SSA_stept::ignore
bool ignore
Definition: ssa_step.h:174
json_irept::convert_from_irep
json_objectt convert_from_irep(const irept &) const
To convert to JSON from an irep structure by recursively generating JSON for the different sub trees.
Definition: json_irep.cpp:31
symex_target_equationt
Inheriting the interface of symex_targett this class represents the SSA form of the input program as ...
Definition: symex_target_equation.h:33
show_byte_ops_plain
void show_byte_ops_plain(ui_message_handlert &ui_message_handler, std::ostream &out, bool outfile_given, const namespacet &ns, const symex_target_equationt &equation)
Definition: show_program.cpp:267
ui_message_handlert::uit::PLAIN
@ PLAIN
symex_target_equationt::SSA_steps
SSA_stepst SSA_steps
Definition: symex_target_equation.h:250
SSA_stept::is_assignment
bool is_assignment() const
Definition: ssa_step.h:62
exprt::visit_pre
void visit_pre(std::function< void(exprt &)>)
Definition: expr.cpp:245
get_byte_op_json
json_objectt get_byte_op_json(const namespacet &ns, const symex_target_equationt &equation)
Definition: show_program.cpp:207
json_get_key_byte_op_num
std::string json_get_key_byte_op_num()
Definition: show_program.cpp:195
messaget::mstreamt
Definition: message.h:223
count_expr_typed
std::size_t count_expr_typed(const exprt &expr)
Definition: show_program.cpp:91
show_program.h
json_irept
Definition: json_irep.h:20
show_byte_ops_xml
void show_byte_ops_xml(ui_message_handlert &ui_message_handler)
Definition: show_program.cpp:313
symex_targett::sourcet::function_id
irep_idt function_id
Definition: symex_target.h:39
invalid_command_line_argument_exceptiont
Thrown when users pass incorrect command line arguments, for example passing no files to analysis or ...
Definition: exception_utils.h:50
show_byte_ops
void show_byte_ops(const optionst &options, ui_message_handlert &ui_message_handler, const namespacet &ns, const symex_target_equationt &equation)
Count and display all byte extract and byte update operations from equation on standard output or fil...
Definition: show_program.cpp:323
from_expr
std::string from_expr(const namespacet &ns, const irep_idt &identifier, const exprt &expr)
Definition: language_util.cpp:38
json_arrayt::push_back
jsont & push_back(const jsont &json)
Definition: json.h:212
SSA_stept::is_assume
bool is_assume() const
Definition: ssa_step.h:57
json_stringt
Definition: json.h:269
ui_message.h
stream_message_handlert
Definition: message.h:110