Skip to content

Commit 419829f

Browse files
committed
ARM: support for predicate/ternary assignment
1 parent 4707cff commit 419829f

File tree

1 file changed

+251
-3
lines changed

1 file changed

+251
-3
lines changed

chb/arm/opcodes/ARMMove.py

Lines changed: 251 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,33 @@ class ARMMoveXData(ARMOpcodeXData):
6161
6262
- c expressions:
6363
0: cresult
64+
65+
Aggregates:
66+
67+
- expressions with predicate / ternary assignments
68+
69+
- nondet:
70+
- predicate: none
71+
- ternary:
72+
0: true assign (constant)
73+
1: false assign (constant)
74+
75+
- predicate:
76+
0: p
77+
1: xp
78+
79+
- ternary:
80+
0: p
81+
1: xp
82+
2: true assign (constant)
83+
3: false assign (constant)
84+
85+
- c expressions with predicate /ternary assignments
86+
87+
- nondet: none
88+
89+
- predicate/ternary:
90+
0: p
6491
"""
6592

6693
def __init__(self, xdata: InstrXData) -> None:
@@ -70,6 +97,22 @@ def __init__(self, xdata: InstrXData) -> None:
7097
def vrd(self) -> "XVariable":
7198
return self.var(0, "vrd")
7299

100+
@property
101+
def is_predicate_assign(self) -> bool:
102+
return self.xdata.is_predicate_assignment
103+
104+
@property
105+
def is_nondet_predicate_assign(self) -> bool:
106+
return self.xdata.is_nondet_predicate_assignment
107+
108+
@property
109+
def is_ternary_assign(self) -> bool:
110+
return self.xdata.is_ternary_assignment
111+
112+
@property
113+
def is_nondet_ternary_assign(self) -> bool:
114+
return self.xdata.is_nondet_ternary_assignment
115+
73116
@property
74117
def xrm(self) -> "XXpr":
75118
return self.xpr(0, "xrm")
@@ -90,6 +133,37 @@ def cresult(self) -> "XXpr":
90133
def is_cresult_ok(self) -> bool:
91134
return self.is_cxpr_ok(0)
92135

136+
@property
137+
def predicate(self) -> "XXpr":
138+
# known to be valid
139+
return self.xpr(0, "p") # known to be valid
140+
141+
@property
142+
def xpredicate(self) -> "XXpr":
143+
return self.xpr(1, "xp") # known to be valid
144+
145+
@property
146+
def cpredicate(self) -> "XXpr":
147+
return self.cxpr(0, "cxp")
148+
149+
@property
150+
def is_cpredicate_ok(self) -> bool:
151+
return self.is_cxpr_ok(0)
152+
153+
@property
154+
def tern_assign_true(self) -> "XXpr": # known to be valid
155+
if self.is_nondet_ternary_assign:
156+
return self.xpr(1, "xp1")
157+
else:
158+
return self.xpr(3, "xp1")
159+
160+
@property
161+
def tern_assign_false(self) -> "XXpr": # known to be valid
162+
if self.is_nondet_ternary_assign:
163+
return self.xpr(0, "xp2")
164+
else:
165+
return self.xpr(2, "xp2")
166+
93167
def has_instruction_condition(self) -> bool:
94168
return self.xdata.has_instruction_condition()
95169

@@ -102,10 +176,37 @@ def has_valid_instruction_c_condition(self) -> bool:
102176
def get_instruction_c_condition(self) -> "XXpr":
103177
return self.xdata.get_instruction_c_condition()
104178

179+
def predicate_assignment_ann(self) -> str:
180+
if self.is_nondet_predicate_assign:
181+
rhs = "? (unknown predicate)"
182+
else:
183+
crhs = (
184+
" (C:"
185+
+ (str(self.cpredicate) if self.is_cpredicate_ok else "?")
186+
+ ")")
187+
rhs = str(self.xpredicate) + crhs
188+
return str(self.vrd) + " := " + rhs
189+
190+
def ternary_assignment_ann(self) -> str:
191+
rhs = str(self.tern_assign_true) + " : " + str(self.tern_assign_false)
192+
if self.is_nondet_ternary_assign:
193+
rhs = " ? " + rhs
194+
else:
195+
rhs = str(self.xpredicate) + " ? " + rhs
196+
cpred = (
197+
" (C:"
198+
+ (str(self.cpredicate) if self.is_cpredicate_ok else "?")
199+
+ ")")
200+
return str(self.vrd) + " := " + rhs + cpred
201+
105202
@property
106203
def annotation(self) -> str:
107204
if self.xdata.instruction_is_subsumed():
108205
return "subsumed by " + self.xdata.subsumed_by()
206+
if self.is_ternary_assign or self.is_nondet_ternary_assign:
207+
return self.ternary_assignment_ann()
208+
if self.is_predicate_assign or self.is_nondet_predicate_assign:
209+
return self.predicate_assignment_ann()
109210
if self.xdata.instruction_subsumes():
110211
return "subsumes " + ", ".join(self.xdata.subsumes())
111212
cx = " (C: " + (str(self.cresult) if self.is_cresult_ok else "None") + ")"
@@ -209,6 +310,141 @@ def ast_prov_subsumed(
209310

210311
return ([], [ll_assign])
211312

313+
def ast_prov_predicate_assign(
314+
self,
315+
astree: ASTInterface,
316+
iaddr: str,
317+
bytestring: str,
318+
xdata: InstrXData
319+
) -> Tuple[List[AST.ASTInstruction], List[AST.ASTInstruction]]:
320+
321+
annotations: List[str] = [iaddr, "MOV (predicate assign)"]
322+
323+
# low-level assignment
324+
325+
(ll_lhs, _, _) = self.opargs[0].ast_lvalue(astree)
326+
(ll_rhs, _, _) = self.opargs[1].ast_rvalue(astree)
327+
328+
ll_assign = astree.mk_assign(
329+
ll_lhs,
330+
ll_rhs,
331+
iaddr=iaddr,
332+
bytestring=bytestring,
333+
annotations=annotations)
334+
335+
# high-level assignment
336+
337+
xd = ARMMoveXData(xdata)
338+
339+
if xd.is_nondet_predicate_assign:
340+
chklogger.logger.warning(
341+
"Predicate assignment without associated predicate at "
342+
+ "address %s", iaddr)
343+
return ([], [ll_assign])
344+
345+
rhs = xd.cpredicate if xd.is_cpredicate_ok else xd.xpredicate
346+
lhs = xd.vrd
347+
rdefs = xdata.reachingdefs
348+
defuses = xdata.defuses
349+
defuseshigh = xdata.defuseshigh
350+
351+
hl_lhs = XU.xvariable_to_ast_lval(lhs, xdata, iaddr, astree, rhs=rhs)
352+
hl_rhs = XU.xxpr_to_ast_def_expr(rhs, xdata, iaddr, astree)
353+
354+
hl_assign = astree.mk_assign(
355+
hl_lhs,
356+
hl_rhs,
357+
iaddr=iaddr,
358+
bytestring=bytestring,
359+
annotations=annotations)
360+
361+
astree.add_instr_mapping(hl_assign, ll_assign)
362+
astree.add_instr_address(hl_assign, [iaddr])
363+
astree.add_expr_mapping(hl_rhs, ll_rhs)
364+
astree.add_lval_mapping(hl_lhs, ll_lhs)
365+
astree.add_expr_reachingdefs(hl_rhs, rdefs[1:])
366+
astree.add_expr_reachingdefs(ll_rhs, [rdefs[0]])
367+
astree.add_lval_defuses(hl_lhs, defuses[0])
368+
astree.add_lval_defuses_high(hl_lhs, defuseshigh[0])
369+
370+
if astree.has_register_variable_intro(iaddr):
371+
rvintro = astree.get_register_variable_intro(iaddr)
372+
if rvintro.has_cast():
373+
astree.add_expose_instruction(hl_assign.instrid)
374+
375+
return ([hl_assign], [ll_assign])
376+
377+
378+
def ast_prov_ternary_assign(
379+
self,
380+
astree: ASTInterface,
381+
iaddr: str,
382+
bytestring: str,
383+
xdata: InstrXData
384+
) -> Tuple[List[AST.ASTInstruction], List[AST.ASTInstruction]]:
385+
386+
annotations: List[str] = [iaddr, "MOV (ternary assign)"]
387+
388+
# low-level assignment
389+
390+
(ll_lhs, _, _) = self.opargs[0].ast_lvalue(astree)
391+
(ll_rhs, _, _) = self.opargs[1].ast_rvalue(astree)
392+
393+
ll_assign = astree.mk_assign(
394+
ll_lhs,
395+
ll_rhs,
396+
iaddr=iaddr,
397+
bytestring=bytestring,
398+
annotations=annotations)
399+
400+
# high-level assignment
401+
402+
xd = ARMMoveXData(xdata)
403+
404+
if xd.is_nondet_ternary_assign:
405+
chklogger.logger.warning(
406+
"Ternary assignment without associated predicate at address %s",
407+
iaddr)
408+
return ([], [ll_assign])
409+
410+
rhsp = xd.cpredicate if xd.is_cpredicate_ok else xd.xpredicate
411+
rhs1 = xd.tern_assign_true
412+
rhs2 = xd.tern_assign_false
413+
lhs = xd.vrd
414+
rdefs = xdata.reachingdefs
415+
defuses = xdata.defuses
416+
defuseshigh = xdata.defuseshigh
417+
418+
hl_lhs = XU.xvariable_to_ast_lval(lhs, xdata, iaddr, astree)
419+
hl_rhsp = XU.xxpr_to_ast_def_expr(rhsp, xdata, iaddr, astree)
420+
hl_rhs1 = XU.xxpr_to_ast_def_expr(rhs1, xdata, iaddr, astree)
421+
hl_rhs2 = XU.xxpr_to_ast_def_expr(rhs2, xdata, iaddr, astree)
422+
hl_rhs = astree.mk_question(hl_rhsp, hl_rhs1, hl_rhs2)
423+
424+
hl_assign = astree.mk_assign(
425+
hl_lhs,
426+
hl_rhs,
427+
iaddr=iaddr,
428+
bytestring=bytestring,
429+
annotations=annotations)
430+
431+
astree.add_instr_mapping(hl_assign, ll_assign)
432+
astree.add_instr_address(hl_assign, [iaddr])
433+
astree.add_expr_mapping(hl_rhs, ll_rhs)
434+
astree.add_lval_mapping(hl_lhs, ll_lhs)
435+
astree.add_expr_reachingdefs(hl_rhs, rdefs[1:])
436+
astree.add_expr_reachingdefs(ll_rhs, [rdefs[0]])
437+
astree.add_lval_defuses(hl_lhs, defuses[0])
438+
astree.add_lval_defuses_high(hl_lhs, defuseshigh[0])
439+
440+
if astree.has_register_variable_intro(iaddr):
441+
rvintro = astree.get_register_variable_intro(iaddr)
442+
if rvintro.has_cast():
443+
astree.add_expose_instruction(hl_assign.instrid)
444+
445+
return ([hl_assign], [ll_assign])
446+
447+
212448
def ast_prov(
213449
self,
214450
astree: ASTInterface,
@@ -232,10 +468,22 @@ def ast_prov(
232468
if xdata.instruction_is_subsumed():
233469
return self.ast_prov_subsumed(astree, iaddr, bytestring, xdata)
234470

471+
xd = ARMMoveXData(xdata)
472+
235473
if xdata.instruction_subsumes():
236-
chklogger.logger.warning(
237-
"MOV instruction at %s is part of an aggregate that is not yet supported",
238-
iaddr)
474+
if xd.is_predicate_assign or xd.is_nondet_predicate_assign:
475+
return self.ast_prov_predicate_assign(
476+
astree, iaddr, bytestring, xdata)
477+
478+
elif xd.is_ternary_assign or xd.is_nondet_ternary_assign:
479+
return self.ast_prov_ternary_assign(
480+
astree, iaddr, bytestring, xdata)
481+
482+
else:
483+
chklogger.logger.warning(
484+
"MOV instruction at %s is part of an aggregate that is "
485+
+ "not yet supported",
486+
iaddr)
239487
return ([], [])
240488

241489
# low-level assignment

0 commit comments

Comments
 (0)