1 "Helper to quickly build instruction's semantic side effects"
12 """AST visitor translating DSL to Miasm expression
14 memX[Y] -> ExprMem(Y, X)
16 X if Y else Z -> ExprCond(Y, X, Z)
17 'X'(Y) -> ExprOp('X', Y)
18 ('X' % Y)(Z) -> ExprOp('X' % Y, Z)
22 parse_integer = re.compile(
"^i([0-9]+)$")
23 parse_mem = re.compile(
"^mem([0-9]+)$")
27 """iX(Y) -> ExprIntX(Y),
28 'X'(Y) -> ExprOp('X', Y), ('X' % Y)(Z) -> ExprOp('X' % Y, Z)"""
31 node = self.generic_visit(node)
33 if isinstance(node.func, ast.Name):
35 fc_name = node.func.id
39 integer = self.parse_integer.search(fc_name)
42 if integer
is not None:
43 new_name =
"ExprInt%s" % integer.groups()[0]
46 node.func.id = new_name
48 elif (isinstance(node.func, ast.Str)
or
49 (isinstance(node.func, ast.BinOp)
and
50 isinstance(node.func.op, ast.Mod)
and
51 isinstance(node.func.left, ast.Str))):
57 node.func = ast.Name(id=
"ExprOp", ctx=ast.Load())
58 node.args[0:0] = [op_name]
63 """memX[Y] -> ExprMem(Y, X)"""
66 node = self.generic_visit(node)
69 if not isinstance(node.value, ast.Name):
72 mem = self.parse_mem.search(name)
77 addr = self.visit(node.slice.value)
78 call = ast.Call(func=ast.Name(id=
'ExprMem', ctx=ast.Load()),
79 args=[addr, ast.Num(n=int(mem.groups()[0]))],
80 keywords=[], starargs=
None, kwargs=
None)
84 """X if Y else Z -> ExprCond(Y, X, Z)"""
86 node = self.generic_visit(node)
89 call = ast.Call(func=ast.Name(id=
'ExprCond', ctx=ast.Load()),
90 args=[self.visit(node.test),
91 self.visit(node.body),
92 self.visit(node.orelse)],
93 keywords=[], starargs=
None, kwargs=
None)
98 """Helper for building instruction's semantic side effects method
100 This class provides a decorator @parse to use on them.
101 The context in which the function will be parsed must be supplied on
106 """Create a SemBuilder
107 @ctx: context dictionnary used during parsing
111 self.
_ctx = dict(m2_expr.__dict__)
112 self.
_ctx[
"irbloc"] = irbloc
116 self._ctx.update(ctx)
120 """Return a dictionnary name -> func of parsed functions"""
121 return self._functions.copy()
125 """Return the AST standing for label creations"""
126 out = ast.parse(
"lbl_end = ExprId(ir.get_next_instr(instr))").body
127 out += ast.parse(
"lbl_if = ExprId(ir.gen_label())").body
131 """Recursive function transforming a @body to a block expression
133 - AST to append to body (real python statements)
134 - a list of blocks, ie list of affblock, ie list of ExprAff (AST)"""
142 for statement
in body:
144 if isinstance(statement, ast.Assign):
145 src = self.transformer.visit(statement.value)
146 dst = self.transformer.visit(statement.targets[0])
148 if (isinstance(dst, ast.Name)
and
149 dst.id
not in argument_names
and
150 dst.id
not in self.
_ctx):
153 statement.value = src
154 real_body.append(statement)
159 res = ast.Call(func=ast.Name(id=
'ExprAff',
166 blocks[-1][-1].append(res)
168 elif (isinstance(statement, ast.Expr)
and
169 isinstance(statement.value, ast.Str)):
171 real_body.append(statement)
173 elif (isinstance(statement, ast.If)
and
174 not statement.orelse):
176 cond = statement.test
179 lbl_end = ast.Name(id=
'lbl_end', ctx=ast.Load())
180 lbl_if = ast.Name(id=
'lbl_if', ctx=ast.Load())
181 dst = ast.Call(func=ast.Name(id=
'ExprCond',
190 if (isinstance(cond, ast.UnaryOp)
and
191 isinstance(cond.op, ast.Not)):
193 dst.args[1:] = dst.args[1:][::-1]
194 dst.args[0] = cond.operand
196 IRDst = ast.Attribute(value=ast.Name(id=
'ir',
198 attr=
'IRDst', ctx=ast.Load())
199 blocks[-1][-1].append(ast.Call(func=ast.Name(id=
'ExprAff',
207 sub_blocks, sub_body = self.
_parse_body(statement.body,
209 if len(sub_blocks) > 1:
210 raise RuntimeError(
"Imbricated if unimplemented")
213 jmp_end = ast.Call(func=ast.Name(id=
'ExprAff',
215 args=[IRDst, lbl_end],
219 sub_blocks[-1][-1].append(jmp_end)
220 sub_blocks[-1][-1] = ast.List(elts=sub_blocks[-1][-1],
222 sub_blocks[-1] = ast.List(elts=sub_blocks[-1],
226 lbl_if_name = ast.Attribute(value=ast.Name(id=
'lbl_if',
228 attr=
'name', ctx=ast.Load())
230 sub_blocks[-1] = ast.Call(func=ast.Name(id=
'irbloc',
238 real_body += sub_body
245 raise RuntimeError(
"Unimplemented %s" % statement)
247 return blocks, real_body
250 """Function decorator, returning a correct method from a pseudo-Python
254 parsed = ast.parse(inspect.getsource(func))
255 fc_ast = parsed.body[0]
256 argument_names = [name.id
for name
in fc_ast.args.args]
259 blocks, body = self.
_parse_body(fc_ast.body, argument_names)
262 fc_ast.args.args[0:0] = [ast.Name(id=
'ir', ctx=ast.Param()),
263 ast.Name(id=
'instr', ctx=ast.Param())]
264 cur_instr = blocks[0][0]
265 if len(blocks[-1][0]) == 0:
268 other_blocks = blocks[1:]
269 body.append(ast.Return(value=ast.Tuple(elts=[ast.List(elts=cur_instr,
271 ast.List(elts=other_blocks,
275 ret = ast.Module([ast.FunctionDef(name=fc_ast.name,
284 fixed = ast.fix_missing_locations(ret)
285 codeobj = compile(fixed,
'<string>',
'exec')
286 ctx = self._ctx.copy()
290 self.
_functions[fc_ast.name] = ctx[fc_ast.name]
291 return ctx[fc_ast.name]