@@ -11,12 +11,18 @@ Author: Daniel Kroening, kroening@kroening.com
1111
1212#include " show_program.h"
1313
14+ #include < fstream>
1415#include < iostream>
1516
1617#include < goto-symex/symex_target_equation.h>
1718
1819#include < langapi/language_util.h>
1920
21+ #include < util/byte_operators.h>
22+ #include < util/exit_codes.h>
23+ #include < util/json_irep.h>
24+ #include < util/ui_message.h>
25+
2026// / Output a single SSA step
2127// / \param ns: Namespace
2228// / \param step: SSA step
@@ -78,3 +84,273 @@ void show_program(const namespacet &ns, const symex_target_equationt &equation)
7884 show_step (ns, step, " SHARED_WRITE" , count);
7985 }
8086}
87+
88+ template <typename expr_typet>
89+ std::size_t count_expr_typed (const exprt &expr)
90+ {
91+ static_assert (
92+ std::is_base_of<exprt, expr_typet>::value,
93+ " `expr_typet` is expected to be a type of `exprt`." );
94+
95+ std::size_t count = 0 ;
96+ expr.visit_pre ([&](const exprt &e) {
97+ if (can_cast_expr<expr_typet>(e))
98+ count++;
99+ });
100+
101+ return count;
102+ }
103+
104+ bool duplicated_previous_step (const SSA_stept &ssa_step)
105+ {
106+ return !(
107+ ssa_step.is_assignment () || ssa_step.is_assert () || ssa_step.is_assume () ||
108+ ssa_step.is_constraint () || ssa_step.is_shared_read () ||
109+ ssa_step.is_shared_write ());
110+ }
111+
112+ void show_ssa_step_plain (
113+ messaget::mstreamt &out,
114+ const namespacet &ns,
115+ const SSA_stept &ssa_step,
116+ const exprt &ssa_expr)
117+ {
118+ const irep_idt &function_id = ssa_step.source .function_id ;
119+ const std::string ssa_expr_as_string = from_expr (ns, function_id, ssa_expr);
120+
121+ out << messaget::faint << " // " << ssa_step.source .pc ->location_number << " " ;
122+ out << ssa_step.source .pc ->source_location .as_string () << " \n "
123+ << messaget::reset;
124+ out << ssa_expr_as_string << " \n " ;
125+ }
126+
127+ json_objectt get_ssa_step_json (
128+ const namespacet &ns,
129+ const SSA_stept &ssa_step,
130+ const exprt &ssa_expr)
131+ {
132+ const std::string key_srcloc = " sourceLocation" ;
133+ const std::string key_ssa_expr = " ssaExpr" ;
134+ const std::string key_ssa_expr_as_string = " ssaExprString" ;
135+
136+ const irep_idt &function_id = ssa_step.source .function_id ;
137+ const std::string ssa_expr_as_string = from_expr (ns, function_id, ssa_expr);
138+
139+ json_objectt json_ssa_step{
140+ {key_srcloc, json (ssa_step.source .pc ->source_location )},
141+ {key_ssa_expr_as_string, json_stringt (ssa_expr_as_string)},
142+ {key_ssa_expr, json_irept (false ).convert_from_irep (ssa_expr)}};
143+
144+ return json_ssa_step;
145+ }
146+
147+ template <typename expr_typet>
148+ void show_byte_op_plain (
149+ messaget::mstreamt &out,
150+ const namespacet &ns,
151+ const symex_target_equationt &equation)
152+ {
153+ std::size_t equation_byte_op_count = 0 ;
154+ for (const auto &step : equation.SSA_steps )
155+ {
156+ if (duplicated_previous_step (step))
157+ continue ;
158+
159+ const exprt &ssa_expr = step.get_ssa_expr ();
160+ const std::size_t ssa_expr_byte_op_count =
161+ count_expr_typed<expr_typet>(ssa_expr);
162+
163+ if (ssa_expr_byte_op_count == 0 )
164+ continue ;
165+
166+ equation_byte_op_count += ssa_expr_byte_op_count;
167+ show_ssa_step_plain (out, ns, step, ssa_expr);
168+ }
169+
170+ if (std::is_same<expr_typet, byte_extract_exprt>::value)
171+ out << ' \n ' << " Number of byte extracts: " ;
172+ else if (std::is_same<expr_typet, byte_update_exprt>::value)
173+ out << ' \n ' << " Number of byte updates: " ;
174+ else
175+ UNREACHABLE;
176+
177+ out << equation_byte_op_count << ' \n ' ;
178+ out << messaget::eom;
179+ }
180+
181+ template <typename expr_typet>
182+ std::string json_get_key_byte_op_list ()
183+ {
184+ if (std::is_same<expr_typet, byte_extract_exprt>::value)
185+ return " byteExtractList" ;
186+ else if (std::is_same<expr_typet, byte_update_exprt>::value)
187+ return " byteUpdateList" ;
188+ else
189+ UNREACHABLE;
190+ }
191+
192+ template <typename expr_typet>
193+ std::string json_get_key_byte_op_num ()
194+ {
195+ if (std::is_same<expr_typet, byte_extract_exprt>::value)
196+ return " numOfExtracts" ;
197+ else if (std::is_same<expr_typet, byte_update_exprt>::value)
198+ return " numOfUpdates" ;
199+ else
200+ UNREACHABLE;
201+ }
202+
203+ template <typename expr_typet>
204+ json_objectt
205+ get_byte_op_json (const namespacet &ns, const symex_target_equationt &equation)
206+ {
207+ // Get key values to be used in the json output based on byte operation type
208+ // 1. json_get_key_byte_op_list():
209+ // returns relevant json object key string where object records
210+ // a list of expressions for given byte operation.
211+ // 2. json_get_key_byte_op_num():
212+ // returns relevant json object key string where object number
213+ // of given byte operation.
214+
215+ const std::string key_byte_op_list = json_get_key_byte_op_list<expr_typet>();
216+ const std::string key_byte_op_num = json_get_key_byte_op_num<expr_typet>();
217+
218+ json_objectt byte_op_stats;
219+ json_arrayt &byte_op_list = byte_op_stats[key_byte_op_list].make_array ();
220+
221+ std::size_t equation_byte_op_count = 0 ;
222+ for (const auto &step : equation.SSA_steps )
223+ {
224+ if (duplicated_previous_step (step))
225+ continue ;
226+
227+ const exprt &ssa_expr = step.get_ssa_expr ();
228+ const std::size_t ssa_expr_byte_op_count =
229+ count_expr_typed<expr_typet>(ssa_expr);
230+
231+ if (ssa_expr_byte_op_count == 0 )
232+ continue ;
233+
234+ equation_byte_op_count += ssa_expr_byte_op_count;
235+ byte_op_list.push_back (get_ssa_step_json (ns, step, ssa_expr));
236+ }
237+
238+ byte_op_stats[key_byte_op_num] =
239+ json_numbert (std::to_string (equation_byte_op_count));
240+
241+ return byte_op_stats;
242+ }
243+
244+ // Get key values to be used in the json output based on byte operation type
245+ // 1. json_get_key_byte_op_stats():
246+ // returns relevant json object key string where object records
247+ // statistics for given byte operation.
248+ template <typename expr_typet>
249+ std::string json_get_key_byte_op_stats ()
250+ {
251+ if (std::is_same<expr_typet, byte_extract_exprt>::value)
252+ return " byteExtractStats" ;
253+ else if (std::is_same<expr_typet, byte_update_exprt>::value)
254+ return " byteUpdateStats" ;
255+ else
256+ UNREACHABLE;
257+ }
258+
259+ bool is_outfile_specified (const optionst &options)
260+ {
261+ const std::string &filename = options.get_option (" outfile" );
262+ return (!filename.empty () && filename != " -" );
263+ }
264+
265+ void show_byte_ops_plain (
266+ ui_message_handlert &ui_message_handler,
267+ std::ostream &out,
268+ bool outfile_given,
269+ const namespacet &ns,
270+ const symex_target_equationt &equation)
271+ {
272+ messaget msg (ui_message_handler);
273+ if (outfile_given)
274+ {
275+ stream_message_handlert mout_handler (out);
276+ messaget mout (mout_handler);
277+
278+ msg.status () << " \n Byte Extracts written to file" << messaget::eom;
279+ show_byte_op_plain<byte_extract_exprt>(mout.status (), ns, equation);
280+
281+ msg.status () << " \n Byte Updates written to file" << messaget::eom;
282+ show_byte_op_plain<byte_update_exprt>(mout.status (), ns, equation);
283+ }
284+ else
285+ {
286+ msg.status () << " \n Byte Extracts:" << messaget::eom;
287+ show_byte_op_plain<byte_extract_exprt>(msg.status (), ns, equation);
288+
289+ msg.status () << " \n Byte Updates:" << messaget::eom;
290+ show_byte_op_plain<byte_update_exprt>(msg.status (), ns, equation);
291+ }
292+ }
293+
294+ void show_byte_ops_json (
295+ std::ostream &out,
296+ const namespacet &ns,
297+ const symex_target_equationt &equation)
298+ {
299+ json_objectt byte_ops_stats{
300+ {json_get_key_byte_op_stats<byte_extract_exprt>(),
301+ get_byte_op_json<byte_extract_exprt>(ns, equation)},
302+ {json_get_key_byte_op_stats<byte_update_exprt>(),
303+ get_byte_op_json<byte_update_exprt>(ns, equation)}};
304+
305+ json_objectt json_result;
306+ json_result[" byteOpsStats" ] = byte_ops_stats;
307+
308+ out << " ,\n " << json_result;
309+ }
310+
311+ void show_byte_ops_xml (ui_message_handlert &ui_message_handler)
312+ {
313+ messaget msg (ui_message_handler);
314+ msg.error ()
315+ << " XML UI not supported for displaying byte extracts and updates."
316+ << " Try --json-ui instead" << messaget::eom;
317+
318+ return ;
319+ }
320+
321+ void show_byte_ops (
322+ const optionst &options,
323+ ui_message_handlert &ui_message_handler,
324+ const namespacet &ns,
325+ const symex_target_equationt &equation)
326+ {
327+ const std::string &filename = options.get_option (" outfile" );
328+ const bool outfile_given = is_outfile_specified (options);
329+
330+ std::ofstream of;
331+
332+ if (outfile_given)
333+ {
334+ of.open (filename, std::fstream::out);
335+ if (!of)
336+ throw invalid_command_line_argument_exceptiont (
337+ " failed to open output file: " + filename, " --outfile" );
338+ }
339+
340+ std::ostream &out = outfile_given ? of : std::cout;
341+
342+ switch (ui_message_handler.get_ui ())
343+ {
344+ case ui_message_handlert::uit::XML_UI:
345+ show_byte_ops_xml (ui_message_handler);
346+ break ;
347+
348+ case ui_message_handlert::uit::JSON_UI:
349+ show_byte_ops_json (out, ns, equation);
350+ break ;
351+
352+ case ui_message_handlert::uit::PLAIN:
353+ show_byte_ops_plain (ui_message_handler, out, outfile_given, ns, equation);
354+ break ;
355+ }
356+ }
0 commit comments