Miasm2
 All Classes Namespaces Files Functions Variables Typedefs Properties Macros
ir2C.py
Go to the documentation of this file.
1 import miasm2.expression.expression as m2_expr
2 from miasm2.expression.simplifications import expr_simp
3 from miasm2.core import asmbloc
4 from miasm2.ir.translators import Translator
5 import logging
6 
7 
8 log_to_c_h = logging.getLogger("ir_helper")
9 console_handler = logging.StreamHandler()
10 console_handler.setFormatter(logging.Formatter("%(levelname)-5s: %(message)s"))
11 log_to_c_h.addHandler(console_handler)
12 log_to_c_h.setLevel(logging.WARN)
13 
14 # Miasm to C translator
15 translator = Translator.to_language("C")
16 
17 prefetch_id = []
18 prefetch_id_size = {}
19 for size in [8, 16, 32, 64]:
20  prefetch_id_size[size] = []
21  for i in xrange(20):
22  name = 'pfmem%.2d_%d' % (size, i)
23  c = m2_expr.ExprId(name, size)
24  globals()[name] = c
25  prefetch_id.append(c)
26  prefetch_id_size[size].append(c)
27 
28 def init_arch_C(arch):
29  arch.id2Cid = {}
30  for x in arch.regs.all_regs_ids + prefetch_id:
31  arch.id2Cid[x] = m2_expr.ExprId('((vm_cpu_t*)jitcpu->cpu)->' + str(x), x.size)
32 
33  arch.id2newCid = {}
34 
35  for x in arch.regs.all_regs_ids + prefetch_id:
36  arch.id2newCid[x] = m2_expr.ExprId('((vm_cpu_t*)jitcpu->cpu)->%s_new' % x, x.size)
37 
38 
39 def patch_c_id(arch, e):
40  return e.replace_expr(arch.id2Cid)
41 
42 
43 def patch_c_new_id(arch, e):
44  return e.replace_expr(arch.id2newCid)
45 
46 
47 mask_int = 0xffffffffffffffff
48 
49 
50 pre_instr_test_exception = r"""
51 // pre instruction test exception
52 if (VM_exception_flag) {
53  %s;
54  return JIT_RET_EXCEPTION;
55 }
56 """
57 
58 
59 code_exception_fetch_mem_at_instr = r"""
60 // except fetch mem at instr
61 if (VM_exception_flag & EXCEPT_DO_NOT_UPDATE_PC) {
62  %s;
63  return JIT_RET_EXCEPTION;
64 }
65 """
66 code_exception_fetch_mem_post_instr = r"""
67 // except fetch mem post instr
68 if (VM_exception_flag) {
69  %s;
70  return JIT_RET_EXCEPTION;
71 }
72 """
73 
74 
75 code_exception_fetch_mem_at_instr_noautomod = r"""
76 // except fetch mem at instr noauto
77 if ((VM_exception_flag & ~EXCEPT_CODE_AUTOMOD) & EXCEPT_DO_NOT_UPDATE_PC) {
78  %s;
79  return JIT_RET_EXCEPTION;
80 }
81 """
82 code_exception_fetch_mem_post_instr_noautomod = r"""
83 // except post instr noauto
84 if (VM_exception_flag & ~EXCEPT_CODE_AUTOMOD) {
85  %s;
86  return JIT_RET_EXCEPTION;
87 }
88 """
89 
90 
91 code_exception_at_instr = r"""
92 // except at instr
93 if (CPU_exception_flag && CPU_exception_flag > EXCEPT_NUM_UPDT_EIP) {
94  %s;
95  return JIT_RET_EXCEPTION;
96 }
97 """
98 
99 code_exception_post_instr = r"""
100 // except post instr
101 if (CPU_exception_flag) {
102  if (CPU_exception_flag > EXCEPT_NUM_UPDT_EIP) {
103  %s;
104  }
105  else {
106  %s;
107  }
108  return JIT_RET_EXCEPTION;
109 }
110 """
111 
112 
113 code_exception_at_instr_noautomod = r"""
114 if ((CPU_exception_flag & ~EXCEPT_CODE_AUTOMOD) && (CPU_exception_flag > EXCEPT_NUM_UPDT_EIP)) {
115  %s;
116  return JIT_RET_EXCEPTION;
117 }
118 """
119 
120 code_exception_post_instr_noautomod = r"""
121 if (CPU_exception_flag & ~EXCEPT_CODE_AUTOMOD) {
122  if (CPU_exception_flag > EXCEPT_NUM_UPDT_EIP) {
123  %s;
124  }
125  else {
126  %s;
127  }
128  return JIT_RET_EXCEPTION;
129 }
130 """
131 
132 goto_local_code = r"""
133 if (BlockDst->is_local) {
134  goto *local_labels[BlockDst->address];
135 }
136 else {
137  return JIT_RET_NO_EXCEPTION;
138 }
139 """
140 
141 my_size_mask = {1: 1, 2: 3, 3: 7, 7: 0x7f,
142  8: 0xFF,
143  16: 0xFFFF,
144  32: 0xFFFFFFFF,
145  64: 0xFFFFFFFFFFFFFFFFL}
146 
147 exception_flags = m2_expr.ExprId('exception_flags', 32)
148 
149 
150 def set_pc(ir_arch, src):
151  dst = ir_arch.jit_pc
152  if not isinstance(src, m2_expr.Expr):
153  src = m2_expr.ExprInt_from(dst, src)
154  e = m2_expr.ExprAff(dst, src.zeroExtend(dst.size))
155  return e
156 
157 
158 def gen_resolve_int(ir_arch, e):
159  return 'Resolve_dst(BlockDst, 0x%X, 0)' % (e.arg)
160 
161 def gen_resolve_id_lbl(ir_arch, e):
162  if e.name.name.startswith("lbl_gen_"):
163  # TODO XXX CLEAN
164  return 'Resolve_dst(BlockDst, 0x%X, 1)'%(e.name.index)
165  else:
166  return 'Resolve_dst(BlockDst, 0x%X, 0)'%(e.name.offset)
167 
168 def gen_resolve_id(ir_arch, e):
169  return 'Resolve_dst(BlockDst, %s, 0)'%(translator.from_expr(patch_c_id(ir_arch.arch, e)))
170 
171 def gen_resolve_mem(ir_arch, e):
172  return 'Resolve_dst(BlockDst, %s, 0)'%(translator.from_expr(patch_c_id(ir_arch.arch, e)))
173 
174 def gen_resolve_other(ir_arch, e):
175  return 'Resolve_dst(BlockDst, %s, 0)'%(translator.from_expr(patch_c_id(ir_arch.arch, e)))
176 
177 def gen_resolve_dst_simple(ir_arch, e):
178  if isinstance(e, m2_expr.ExprInt):
179  return gen_resolve_int(ir_arch, e)
180  elif isinstance(e, m2_expr.ExprId) and isinstance(e.name,
181  asmbloc.asm_label):
182  return gen_resolve_id_lbl(ir_arch, e)
183  elif isinstance(e, m2_expr.ExprId):
184  return gen_resolve_id(ir_arch, e)
185  elif isinstance(e, m2_expr.ExprMem):
186  return gen_resolve_mem(ir_arch, e)
187  else:
188  return gen_resolve_other(ir_arch, e)
189 
190 
191 def gen_irdst(ir_arch, e):
192  out = []
193  if isinstance(e, m2_expr.ExprCond):
194  dst_cond_c = translator.from_expr(patch_c_id(ir_arch.arch, e.cond))
195  out.append("if (%s)"%dst_cond_c)
196  out.append(' %s;'%(gen_resolve_dst_simple(ir_arch, e.src1)))
197  out.append("else")
198  out.append(' %s;'%(gen_resolve_dst_simple(ir_arch, e.src2)))
199  else:
200  out.append('%s;'%(gen_resolve_dst_simple(ir_arch, e)))
201  return out
202 
203 def Expr2C(ir_arch, l, exprs, gen_exception_code=False):
204  id_to_update = []
205  out = ["// %s" % (l)]
206  out_pc = []
207 
208  dst_dict = {}
209  src_mem = {}
210 
211  prefect_index = {8: 0, 16: 0, 32: 0, 64: 0}
212  new_expr = []
213 
214  e = set_pc(ir_arch, l.offset & mask_int)
215  #out.append("%s;" % patch_c_id(ir_arch.arch, e)))
216 
217  pc_is_dst = False
218  fetch_mem = False
219  set_exception_flags = False
220  for e in exprs:
221  assert isinstance(e, m2_expr.ExprAff)
222  assert not isinstance(e.dst, m2_expr.ExprOp)
223  if isinstance(e.dst, m2_expr.ExprId):
224  if not e.dst in dst_dict:
225  dst_dict[e.dst] = []
226  dst_dict[e.dst].append(e)
227  else:
228  new_expr.append(e)
229  # test exception flags
230  ops = m2_expr.get_expr_ops(e)
231  if set(['umod', 'udiv']).intersection(ops):
232  set_exception_flags = True
233  if e.dst == exception_flags:
234  set_exception_flags = True
235  # TODO XXX test function whose set exception_flags
236 
237  # search mem lookup for generate mem read prefetch
238  rs = e.src.get_r(mem_read=True)
239  for r in rs:
240  if (not isinstance(r, m2_expr.ExprMem)) or r in src_mem:
241  continue
242  fetch_mem = True
243  index = prefect_index[r.size]
244  prefect_index[r.size] += 1
245  pfmem = prefetch_id_size[r.size][index]
246  src_mem[r] = pfmem
247 
248  for dst, exs in dst_dict.items():
249  if len(exs) == 1:
250  new_expr += exs
251  continue
252  exs = [expr_simp(x) for x in exs]
253  log_to_c_h.debug('warning: detected multi dst to same id')
254  log_to_c_h.debug('\t'.join([str(x) for x in exs]))
255  new_expr += exs
256  out_mem = []
257 
258  # first, generate mem prefetch
259  mem_k = src_mem.keys()
260  mem_k.sort()
261  for k in mem_k:
262  str_src = translator.from_expr(patch_c_id(ir_arch.arch, k))
263  str_dst = translator.from_expr(patch_c_id(ir_arch.arch, src_mem[k]))
264  out.append('%s = %s;' % (str_dst, str_src))
265  src_w_len = {}
266  for k, v in src_mem.items():
267  src_w_len[k] = v
268  for e in new_expr:
269 
270  src, dst = e.src, e.dst
271  # reload src using prefetch
272  src = src.replace_expr(src_w_len)
273  if dst is ir_arch.IRDst:
274  out += gen_irdst(ir_arch, src)
275  continue
276 
277 
278  str_src = translator.from_expr(patch_c_id(ir_arch.arch, src))
279  str_dst = translator.from_expr(patch_c_id(ir_arch.arch, dst))
280 
281 
282 
283  if isinstance(dst, m2_expr.ExprId):
284  id_to_update.append(dst)
285  str_dst = patch_c_new_id(ir_arch.arch, dst)
286  if dst in ir_arch.arch.regs.regs_flt_expr:
287  # dont mask float affectation
288  out.append('%s = (%s);' % (str_dst, str_src))
289  else:
290  out.append('%s = (%s)&0x%X;' % (str_dst, str_src,
291  my_size_mask[src.size]))
292  elif isinstance(dst, m2_expr.ExprMem):
293  fetch_mem = True
294  str_dst = str_dst.replace('MEM_LOOKUP', 'MEM_WRITE')
295  out_mem.append('%s, %s);' % (str_dst[:-1], str_src))
296 
297  if e.dst == ir_arch.arch.pc[ir_arch.attrib]:
298  pc_is_dst = True
299  out_pc += ["return JIT_RET_NO_EXCEPTION;"]
300 
301  # if len(id_to_update) != len(set(id_to_update)):
302  # raise ValueError('Not implemented: multi dst to same id!', str([str(x)
303  # for x in exprs]))
304  out += out_mem
305 
306  if gen_exception_code:
307  if fetch_mem:
308  e = set_pc(ir_arch, l.offset & mask_int)
309  s1 = "%s" % translator.from_expr(patch_c_id(ir_arch.arch, e))
310  s1 += ';\n Resolve_dst(BlockDst, 0x%X, 0)'%(l.offset & mask_int)
311  out.append(code_exception_fetch_mem_at_instr_noautomod % s1)
312  if set_exception_flags:
313  e = set_pc(ir_arch, l.offset & mask_int)
314  s1 = "%s" % translator.from_expr(patch_c_id(ir_arch.arch, e))
315  s1 += ';\n Resolve_dst(BlockDst, 0x%X, 0)'%(l.offset & mask_int)
316  out.append(code_exception_at_instr_noautomod % s1)
317 
318  for i in id_to_update:
319  if i is ir_arch.IRDst:
320  continue
321  out.append('%s = %s;' %
322  (patch_c_id(ir_arch.arch, i), patch_c_new_id(ir_arch.arch, i)))
323 
324  post_instr = []
325  # test stop exec ####
326  if gen_exception_code:
327  if set_exception_flags:
328  if pc_is_dst:
329  post_instr.append("if (VM_exception_flag) { " +
330  "/*pc = 0x%X; */return JIT_RET_EXCEPTION; }" % (l.offset))
331  else:
332  e = set_pc(ir_arch, l.offset & mask_int)
333  s1 = "%s" % translator.from_expr(patch_c_id(ir_arch.arch, e))
334  s1 += ';\n Resolve_dst(BlockDst, 0x%X, 0)'%(l.offset & mask_int)
335  e = set_pc(ir_arch, (l.offset + l.l) & mask_int)
336  s2 = "%s" % translator.from_expr(patch_c_id(ir_arch.arch, e))
337  s2 += ';\n Resolve_dst(BlockDst, 0x%X, 0)'%((l.offset + l.l) & mask_int)
338  post_instr.append(
339  code_exception_post_instr_noautomod % (s1, s2))
340 
341  if fetch_mem:
342  if l.additional_info.except_on_instr:
343  offset = l.offset
344  else:
345  offset = l.offset + l.l
346 
347  e = set_pc(ir_arch, offset & mask_int)
348  s1 = "%s" % translator.from_expr(patch_c_id(ir_arch.arch, e))
349  s1 += ';\n Resolve_dst(BlockDst, 0x%X, 0)'%(offset & mask_int)
350  post_instr.append(
351  code_exception_fetch_mem_post_instr_noautomod % (s1))
352 
353  # pc manip after all modifications
354  return out, post_instr, post_instr + out_pc
355 
356 
358  if not isinstance(e, m2_expr.ExprId):
359  return e
360  if not isinstance(e.name, asmbloc.asm_label):
361  return e
362  return m2_expr.ExprInt_from(e, e.name.offset)
363 
364 
365 def expr2pyobj(arch, e):
366  if isinstance(e, m2_expr.ExprId):
367  if isinstance(e.name, asmbloc.asm_label):
368  src_c = 'PyString_FromStringAndSize("%s", %d)' % (
369  e.name.name, len(e.name.name))
370  else:
371  src_c = 'PyLong_FromUnsignedLongLong(%s)' % patch_c_id(arch, e)
372  else:
373  raise NotImplementedError('unknown type for e: %s' % type(e))
374  return src_c
375 
376 
377 def ir2C(ir_arch, irbloc, lbl_done,
378  gen_exception_code=False, log_mn=False, log_regs=False):
379  out = []
380  # print "TRANS"
381  # print irbloc
382  out.append(["%s:" % irbloc.label.name])
383  #out.append(['printf("%s:\n");' % irbloc.label.name])
384  assert len(irbloc.irs) == len(irbloc.lines)
385  for l, exprs in zip(irbloc.lines, irbloc.irs):
386  if l.offset not in lbl_done:
387  e = set_pc(ir_arch, l.offset & mask_int)
388  s1 = "%s" % translator.from_expr(patch_c_id(ir_arch.arch, e))
389  s1 += ';\n Resolve_dst(BlockDst, 0x%X, 0)'%(l.offset & mask_int)
390  out.append([pre_instr_test_exception % (s1)])
391  lbl_done.add(l.offset)
392 
393  if log_regs:
394  out.append([r'dump_gpregs(jitcpu->cpu);'])
395 
396  if log_mn:
397  out.append(['printf("%.8X %s\\n");' % (l.offset, str(l))])
398  # print l
399  # gen pc update
400  post_instr = ""
401  c_code, post_instr, _ = Expr2C(ir_arch, l, exprs, gen_exception_code)
402  out.append(c_code + post_instr)
403  out.append([goto_local_code ] )
404  return out
405 
406 
407 def irblocs2C(ir_arch, resolvers, label, irblocs,
408  gen_exception_code=False, log_mn=False, log_regs=False):
409  out = []
410 
411  lbls = [b.label for b in irblocs]
412  lbls_local = []
413  for l in lbls:
414  if l.name.startswith('lbl_gen_'):
415  l.index = int(l.name[8:], 16)
416  lbls_local.append(l)
417  lbl_index_min, lbl_index_max = 0, 0
418  lbls_index = [l.index for l in lbls if hasattr(l, 'index')]
419  lbls_local.sort(key=lambda x:x.index)
420 
421  if lbls_index:
422  lbl_index_min = min(lbls_index)
423  lbl_index_max = max(lbls_index)
424  for l in lbls_local:
425  l.index -= lbl_index_min
426 
427  out.append("void* local_labels[] = {%s};"%(', '.join(["&&%s"%l.name for l in lbls_local])))
428 
429  out.append("goto %s;" % label.name)
430  bloc_labels = [x.label for x in irblocs]
431  assert label in bloc_labels
432 
433  lbl_done = set([None])
434 
435  for irbloc in irblocs:
436  # XXXX TEST
437  if irbloc.label.offset is None:
438  b_out = ir2C(ir_arch, irbloc, lbl_done, gen_exception_code)
439  else:
440  b_out = ir2C(
441  ir_arch, irbloc, lbl_done, gen_exception_code, log_mn, log_regs)
442  for exprs in b_out:
443  for l in exprs:
444  out.append(l)
445  dst = irbloc.dst
446  out.append("")
447 
448  return out
449 
def patch_c_new_id
Definition: ir2C.py:43
def ir2C
Definition: ir2C.py:378
def gen_resolve_id_lbl
Definition: ir2C.py:161
def gen_resolve_other
Definition: ir2C.py:174
def set_pc
Definition: ir2C.py:150
def patch_c_id
Definition: ir2C.py:39
def gen_resolve_id
Definition: ir2C.py:168
def label2offset
Definition: ir2C.py:357
def Expr2C
Definition: ir2C.py:203
def irblocs2C
Definition: ir2C.py:408
def init_arch_C
Definition: ir2C.py:28
def gen_resolve_mem
Definition: ir2C.py:171
def gen_irdst
Definition: ir2C.py:191
def expr2pyobj
Definition: ir2C.py:365
def gen_resolve_dst_simple
Definition: ir2C.py:177
def gen_resolve_int
Definition: ir2C.py:158