HAL  v4.5.0-83-g30c8f0afc
The Hardware Analyzer - a comprehensive reverse engineering and manipulation framework for gate-level netlists.
converter.cpp
Go to the documentation of this file.
2 
4 #include "z3_utils/z3_utils.h"
5 
6 #include <iomanip>
7 #include <queue>
8 #include <set>
9 #include <sstream>
10 
11 namespace hal
12 {
13  namespace z3_utils
14  {
15  // UTILS
16  std::string Converter::integer_with_leading_zeros(const u32 i, const u32 total_length) const
17  {
18  std::stringstream ss;
19  ss << std::setw(total_length) << std::setfill('0') << i;
20  return ss.str();
21  }
22 
23  std::string Converter::replace_all(const std::string& str, const std::string& from, const std::string& to) const
24  {
25  std::string r_str = str;
26  size_t start_index = 0;
27  while (true)
28  {
29  size_t found_index = r_str.find(from, start_index);
30  if (found_index == std::string::npos)
31  {
32  break;
33  }
34 
35  r_str = r_str.replace(found_index, from.size(), to);
36 
37  start_index = found_index + to.size();
38  }
39 
40  return r_str;
41  }
42 
44  {
45  std::string op_str;
46 
47  switch (op)
48  {
49  case Converter::bvand:
50  op_str = "bvand";
51  break;
52  case Converter::bvnot:
53  op_str = "bvnot";
54  break;
55  case Converter::bvor:
56  op_str = "bvor";
57  break;
58  case Converter::bvxor:
59  op_str = "bvxor";
60  break;
61  default:
62  log_error("z3_utils", "Tried to convert unkown operation to string.");
63  op_str = "NOT IMPLEMENTED REACHED";
64  }
65 
66  return op_str;
67  }
68 
69  // METHODS
70  bool Converter::does_line_contain_assignment(const std::string& l) const
71  {
72  return l.find("let") != std::string::npos;
73  }
74 
75  std::string Converter::extract_lhs(const std::string& l) const
76  {
77  auto start_index = l.find_first_of('x');
78  auto end_index = l.find_first_of(' ', start_index);
79 
80  return l.substr(start_index, end_index - start_index);
81  }
82 
83  std::map<u32, u32> Converter::extract_paranthesis_pairs(const std::string& l) const
84  {
85  std::map<u32, u32> pairs;
86  auto start_index = 0;
87  while (true)
88  {
89  auto found_index = l.find_first_of('(', start_index);
90  if (found_index == std::string::npos)
91  {
92  break;
93  }
94 
95  // search for closing bracket after finding an open open one
96  u32 count = 1;
97  for (u32 i = found_index + 1; i < l.size(); i++)
98  {
99  if (l.at(i) == '(')
100  {
101  count++;
102  }
103  else if (l.at(i) == ')')
104  {
105  count--;
106  }
107 
108  if (count == 0)
109  {
110  pairs.insert({found_index, i});
111  break;
112  }
113  }
114 
115  start_index = found_index + 1;
116  log_debug("z3_utils", "Trying to find paranthesis_pairs.");
117  }
118 
119  return pairs;
120  }
121 
122  bool Converter::contains_one_operation(const std::string& l) const
123  {
124  u32 count = 0;
125 
126  for (const auto& op : m_operations)
127  {
128  size_t start_index = 0;
129  auto op_str = operation_to_string(op);
130  while (true)
131  {
132  size_t found_index = l.find(op_str, start_index);
133  if (found_index == std::string::npos)
134  {
135  break;
136  }
137  count++;
138 
139  start_index = found_index + op_str.size();
140  log_debug("z3_utils", "{}", op_str);
141  }
142  }
143 
144  return count == 1;
145  }
146 
147  std::map<std::string, std::string> Converter::extract_sub_exrepssions(const std::string& l) const
148  {
149  // stores the start and end position of each pair of parenthesis
150  std::map<u32, u32> parentheses = extract_paranthesis_pairs(l);
151  // stores the sub expressions with a name in the form of "sub_<count>"
152  std::map<std::string, std::string> sub_expressions;
153  u32 count = 0;
154  for (const auto& [start, end] : parentheses)
155  {
156  auto sub_expression = l.substr(start, end - start + 1);
157  std::string sub_name = "sub_" + integer_with_leading_zeros(count, 5);
158  sub_expressions.insert({sub_name, sub_expression});
159  count++;
160  }
161 
162  // eliminate duplicates:
163  std::set<std::string> to_erase;
164  for (const auto& [dom_name, dom_expr] : sub_expressions)
165  {
166  for (const auto& [sub_name, sub_expr] : sub_expressions)
167  {
168  if (dom_expr == sub_expr && dom_name != sub_name && to_erase.find(dom_name) == to_erase.end())
169  {
170  to_erase.insert(sub_name);
171  }
172  }
173  }
174  for (const auto& n : to_erase)
175  {
176  sub_expressions.erase(n);
177  }
178 
179  // push names to waiting q
180  std::queue<std::string> q;
181  for (const auto& [n, e] : sub_expressions)
182  {
183  q.push(n);
184  }
185 
186  // replace all sub expressions in higher order expressions with their name
187  while (!q.empty())
188  {
189  auto f_name = q.front();
190  auto f_expr = sub_expressions.at(f_name);
191  q.pop();
192 
193  if (contains_one_operation(f_expr))
194  {
195  for (auto [n, e] : sub_expressions)
196  {
197  if (f_expr == e)
198  {
199  continue;
200  }
201 
202  sub_expressions.at(n) = replace_all(e, f_expr, f_name);
203  }
204  }
205  else
206  {
207  q.push(f_name);
208  }
209 
210  if (!q.empty())
211  {
212  log_debug("z3_utils", "Queue: {} at front {}.", q.size(), q.front());
213  log_debug("z3_utils", "Sub: {}", sub_expressions.at(q.front()));
214  }
215  }
216 
217  return sub_expressions;
218  }
219 
221  {
222  for (const auto& op : m_operations)
223  {
224  auto op_str = operation_to_string(op);
225  if (se.find(op_str) != std::string::npos)
226  {
227  return op;
228  }
229  }
230 
231  log_error("z3_utils", "Unkown operation in subexpression {}", se);
232  return Converter::NONE;
233  }
234 
235  std::vector<std::string> Converter::extract_operands(const std::string& se) const
236  {
237  // remove parentheses
238  std::string shortend_string = se.substr(1);
239  shortend_string.pop_back();
240 
241  std::vector<std::string> operands;
242 
243  std::istringstream iss(shortend_string);
244  std::string tmp;
245  while (getline(iss, tmp, ' '))
246  {
247  operands.push_back(tmp);
248  }
249 
250  // remove first element, since this is the operation and not an operand
251  operands.erase(operands.begin());
252 
253  return operands;
254  }
255 
256  std::map<std::string, std::string> Converter::translate_sub_expressions(const std::map<std::string, std::string>& se) const
257  {
258  std::map<std::string, std::string> translated_sub_expressions;
259 
260  for (const auto& [n, s] : se)
261  {
263  std::vector<std::string> operands = extract_operands(s);
264 
265  translated_sub_expressions.insert({n, build_operation(operation, operands)});
266  }
267 
268  return translated_sub_expressions;
269  }
270 
271  std::string Converter::merge_sub_expressions(const std::map<std::string, std::string>& translated_sub_expressions) const
272  {
273  std::string assignment = translated_sub_expressions.at("sub_00000"); // first element contains main expression
274 
275  // replace the sub_<id> placeholders in the sub expressions
276  std::map<std::string, std::string> merged_sub_expressions = translated_sub_expressions;
277  for (const auto& [n, e] : merged_sub_expressions)
278  {
279  for (auto [m, f] : merged_sub_expressions)
280  {
281  merged_sub_expressions.at(m) = replace_all(f, n, e);
282  }
283  }
284 
285  // replace in assignment
286  for (const auto& [n, e] : merged_sub_expressions)
287  {
288  assignment = replace_all(assignment, n, e);
289  }
290 
291  return assignment;
292  }
293 
294  std::string Converter::convert_z3_expr_to_func(const z3::expr& e) const
295  {
296  std::string assignments = "";
297 
298  // TODO remove this is only for debugging
299  // auto test_ctx = std::make_unique<z3::context>();
300  // z3::expr t_1 = test_ctx->bv_const("1001", 1);
301  // z3::expr t_2 = {*test_ctx, Z3_mk_bvnot(*test_ctx, t_1)};
302  // z3::expr t_3 = {*test_ctx, Z3_mk_bvnot(*test_ctx, t_2)};
303  // auto wrap_t3 = z3Wrapper(std::move(test_ctx), t_3);
304 
305  auto smt = z3_utils::to_smt2(e);
306 
307  // std::cout << "SMT: " << smt << std::endl;
308 
309  std::istringstream iss(smt);
310  for (std::string line; std::getline(iss, line);)
311  {
313  {
314  auto assignment = generate_assignment(line);
315  assignments = assignments + assignment;
316  ;
317  }
318  }
319 
320  log_debug("z3_utils", "found {} assignments.", assignments.size());
321 
322  if (assignments.empty())
323  {
324  // in order to stay compliant with the rest of the converter structure we simply simulate a dummy assignment with a double negation.
325  auto dummy_assignment = "(let ((?x1 (bvnot (bvnot " + e.to_string() + ")))))";
326  assignments += generate_assignment(dummy_assignment);
327  }
328 
329  const auto input_vars = utils::to_vector(z3_utils::get_variable_names(e));
330 
331  std::string initialization = generate_initialization(input_vars);
332 
333  return construct_function(assignments, initialization, input_vars);
334  }
335  } //namespace z3_utils
336 } // namespace hal
std::string replace_all(const std::string &str, const std::string &from, const std::string &to) const
Definition: converter.cpp:23
bool does_line_contain_assignment(const std::string &l) const
Definition: converter.cpp:70
std::map< std::string, std::string > extract_sub_exrepssions(const std::string &l) const
Definition: converter.cpp:147
bool contains_one_operation(const std::string &l) const
Definition: converter.cpp:122
std::string integer_with_leading_zeros(const u32 i, const u32 total_length) const
Definition: converter.cpp:16
std::string extract_lhs(const std::string &l) const
Definition: converter.cpp:75
std::map< std::string, std::string > translate_sub_expressions(const std::map< std::string, std::string > &se) const
Definition: converter.cpp:256
std::vector< std::string > extract_operands(const std::string &se) const
Definition: converter.cpp:235
std::string convert_z3_expr_to_func(const z3::expr &e) const
Definition: converter.cpp:294
std::string merge_sub_expressions(const std::map< std::string, std::string > &translated_sub_expressions) const
Definition: converter.cpp:271
std::map< u32, u32 > extract_paranthesis_pairs(const std::string &l) const
Definition: converter.cpp:83
virtual std::string construct_function(const std::string &assignments, const std::string &initalization, const std::vector< std::string > &input_vars) const =0
std::string operation_to_string(const Operation &op) const
Definition: converter.cpp:43
Operation extract_operation(const std::string &se) const
Definition: converter.cpp:220
virtual std::string build_operation(const Operation &operation, const std::vector< std::string > &operands) const =0
virtual std::string generate_assignment(const std::string &l) const =0
virtual std::string generate_initialization(const std::vector< std::string > &input_vars) const =0
std::vector< Operation > m_operations
Definition: converter.h:224
uint32_t u32
Definition: defines.h:41
#define log_error(channel,...)
Definition: log.h:78
#define log_debug(channel,...)
Definition: log.h:74
S to(const T &str)
std::vector< T > to_vector(const Container< T, Args... > &container)
Definition: utils.h:515
std::set< std::string > get_variable_names(const z3::expr &e)
Extracts all variable names from a z3 expression.
Definition: z3_utils.cpp:481
std::string to_smt2(const z3::expr &e)
Definition: z3_utils.cpp:449
Definition: defines.h:45
u32 start_index