Skip to content

Commit 27be06e

Browse files
committed
allow for conditional return instructions
1 parent 4687988 commit 27be06e

File tree

6 files changed

+141
-6
lines changed

6 files changed

+141
-6
lines changed

chb/app/BasicBlock.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,10 @@ def last_instruction(self) -> Instruction:
9595
def has_return(self) -> bool:
9696
return self.last_instruction.is_return_instruction
9797

98+
@property
99+
def has_conditional_return(self) -> bool:
100+
return self.last_instruction.is_conditional_return_instruction
101+
98102
@property
99103
@abstractmethod
100104
def instructions(self) -> Mapping[str, Instruction]:

chb/app/CHVersion.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
chbversion: str = "0.3.0-20250608"
1+
chbversion: str = "0.3.0-20250624"

chb/app/Cfg.py

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -682,10 +682,32 @@ def ast(self,
682682
for n in self.rpo_sorted_nodes:
683683
astblock = astfn.astblock(n)
684684
blocknode = astblock.ast(astree)
685-
if astblock.has_return:
685+
686+
if astblock.has_conditional_return:
687+
succ = self.successors(n)[0]
686688
instr = astblock.last_instruction
687689
rv = instr.return_value()
688690
astexpr: Optional[AST.ASTExpr] = None
691+
if rv is not None and not astree.returns_void():
692+
astexpr = XU.xxpr_to_ast_def_expr(
693+
rv, instr.xdata, instr.iaddr, astree)
694+
rtnstmt = astree.mk_return_stmt(
695+
astexpr, instr.iaddr, instr.bytestring)
696+
rvcondition = instr.ast_condition(astree)
697+
if rvcondition is not None:
698+
elsebr = astree.mk_instr_sequence([])
699+
brstmt = cast(AST.ASTBranch, astree.mk_branch(
700+
rvcondition, rtnstmt, elsebr, succ))
701+
blockstmts[n] = [blocknode, brstmt]
702+
else:
703+
blockstmts[n] = [blocknode, rtnstmt]
704+
else:
705+
blockstmts[n] = [blocknode]
706+
707+
elif astblock.has_return:
708+
instr = astblock.last_instruction
709+
rv = instr.return_value()
710+
astexpr = None
689711
if rv is not None and not astree.returns_void():
690712
astexpr = XU.xxpr_to_ast_def_expr(
691713
rv, instr.xdata, instr.iaddr, astree)

chb/app/InstrXData.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,26 @@ def get_instruction_condition(self) -> XXpr:
526526
else:
527527
raise UF.CHBError("No instruction condition index found")
528528

529+
def get_instruction_c_condition(self) -> XXpr:
530+
for t in self.tags:
531+
if t.startswith("icc:"):
532+
index = int(t[4:])
533+
argval = self.args[index]
534+
if argval == -2:
535+
raise UF.CHBError(
536+
"Error value in instruction c condition")
537+
return self.xprdictionary.xpr(argval)
538+
else:
539+
raise UF.CHBError("No instruction c_condition index found")
540+
541+
def has_valid_instruction_c_condition(self) -> bool:
542+
for t in self.tags:
543+
if t.startswith("icc:"):
544+
index = int(t[4:])
545+
argval = self.args[index]
546+
return argval >= 0
547+
return False
548+
529549
def has_condition_block_condition(self) -> bool:
530550
return "TF" in self.tags
531551

@@ -576,6 +596,17 @@ def has_return_cxpr(self) -> bool:
576596
else:
577597
return False
578598

599+
@property
600+
def is_return_xpr_ok(self) -> bool:
601+
if not self.has_return_xpr():
602+
return False
603+
rvtag = next(t for t in self.tags if t.startswith("return:"))
604+
rvix = int(rvtag[7:])
605+
rval = self.args[rvix]
606+
if rval == -2:
607+
return False
608+
return True
609+
579610
def get_return_xpr(self) -> XXpr:
580611
rvtag = next(t for t in self.tags if t.startswith("return:"))
581612
rvix = int(rvtag[7:])
@@ -584,6 +615,17 @@ def get_return_xpr(self) -> XXpr:
584615
raise UF.CHBError("Unexpected error in return value")
585616
return self.xprdictionary.xpr(rval)
586617

618+
@property
619+
def is_return_xxpr_ok(self) -> bool:
620+
if not self.has_return_xpr():
621+
return False
622+
rvtag = next(t for t in self.tags if t.startswith("return:"))
623+
rvix = int(rvtag[7:])
624+
rval = self.args[rvix + 1]
625+
if rval == -2:
626+
return False
627+
return True
628+
587629
def get_return_xxpr(self) -> XXpr:
588630
rvtag = next(t for t in self.tags if t.startswith("return:"))
589631
rvix = int(rvtag[7:])

chb/app/Instruction.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,10 @@ def is_store_instruction(self) -> bool:
206206
def is_return_instruction(self) -> bool:
207207
...
208208

209+
@property
210+
def is_conditional_return_instruction(self) -> bool:
211+
return False
212+
209213
@property
210214
def is_nop_instruction(self) -> bool:
211215
return False

chb/arm/opcodes/ARMBranchExchange.py

Lines changed: 67 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
from chb.astinterface.ASTInterface import ASTInterface
3939

4040
from chb.invariants.XXpr import XXpr
41-
41+
import chb.invariants.XXprUtil as XU
4242

4343
import chb.util.fileutil as UF
4444
from chb.util.loggingutil import chklogger
@@ -69,6 +69,14 @@ def xxtgt(self) -> "XXpr":
6969
def has_return_xpr(self) -> bool:
7070
return self.xdata.has_return_xpr()
7171

72+
@property
73+
def is_return_xpr_ok(self) -> bool:
74+
return self.xdata.is_return_xpr_ok
75+
76+
@property
77+
def is_return_xxpr_ok(self) -> bool:
78+
return self.xdata.is_return_xxpr_ok
79+
7280
def returnval(self) -> "XXpr":
7381
return self.xdata.get_return_xpr()
7482

@@ -81,6 +89,18 @@ def has_creturnval(self) -> bool:
8189
def creturnval(self) -> "XXpr":
8290
return self.xdata.get_return_cxpr()
8391

92+
def has_instruction_condition(self) -> bool:
93+
return self.xdata.has_instruction_condition()
94+
95+
def get_instruction_condition(self) -> "XXpr":
96+
return self.xdata.get_instruction_condition()
97+
98+
def has_valid_instruction_c_condition(self) -> bool:
99+
return self.xdata.has_valid_instruction_c_condition()
100+
101+
def get_instruction_c_condition(self) -> "XXpr":
102+
return self.xdata.get_instruction_c_condition()
103+
84104
@property
85105
def annotation(self) -> str:
86106
if self.xdata.is_bx_call:
@@ -89,8 +109,10 @@ def annotation(self) -> str:
89109
cx = (" (C: "
90110
+ (str(self.creturnval()) if self.has_creturnval() else "None")
91111
+ ")")
92-
if self.is_ok:
112+
if self.is_return_xxpr_ok:
93113
return "return " + str(self.rreturnval()) + cx
114+
elif self.is_return_xpr_ok:
115+
return "return " + str(self.returnval()) + cx
94116
else:
95117
return "Error value"
96118
else:
@@ -126,11 +148,20 @@ def is_return_instruction(self, xdata: InstrXData) -> bool:
126148
else:
127149
return False
128150

151+
def is_conditional_return_instruction(self, xdata: InstrXData) -> bool:
152+
if self.is_return_instruction(xdata):
153+
return xdata.has_instruction_condition()
154+
return False
155+
129156
def return_value(self, xdata: InstrXData) -> Optional[XXpr]:
130157
xd = ARMBranchExchangeXData(xdata)
131-
if xd.has_creturnval():
132-
if xd.is_ok:
158+
if xd.has_return_xpr():
159+
if xd.has_creturnval():
133160
return xd.creturnval()
161+
elif xd.is_return_xxpr_ok:
162+
return xd.rreturnval()
163+
elif xd.is_return_xpr_ok:
164+
return xd.returnval()
134165
else:
135166
chklogger.logger.warning(
136167
"Return value is an error value")
@@ -174,6 +205,38 @@ def assembly_ast(
174205
"""Need check for branch on LR, which should emit a return statement."""
175206
return []
176207

208+
def ast_condition_prov(
209+
self,
210+
astree: ASTInterface,
211+
iaddr: str,
212+
bytestring: str,
213+
xdata: InstrXData,
214+
reverse: bool
215+
) -> Tuple[Optional[AST.ASTExpr], Optional[AST.ASTExpr]]:
216+
217+
ll_astcond = self.ast_cc_expr(astree)
218+
219+
if xdata.has_instruction_condition():
220+
xd = ARMBranchExchangeXData(xdata)
221+
if xd.has_valid_instruction_c_condition():
222+
pcond = xd.get_instruction_c_condition()
223+
else:
224+
pcond = xd.get_instruction_condition()
225+
hl_astcond = XU.xxpr_to_ast_def_expr(pcond, xdata, iaddr, astree)
226+
227+
astree.add_expr_mapping(hl_astcond, ll_astcond)
228+
astree.add_expr_reachingdefs(hl_astcond, xdata.reachingdefs)
229+
astree.add_flag_expr_reachingdefs(ll_astcond, xdata.flag_reachingdefs)
230+
astree.add_condition_address(ll_astcond, [iaddr])
231+
232+
return (hl_astcond, ll_astcond)
233+
234+
else:
235+
chklogger.logger.error(
236+
"No condition found at address %s", iaddr)
237+
hl_astcond = astree.mk_temp_lval_expression()
238+
return (hl_astcond, ll_astcond)
239+
177240
def ast_prov(
178241
self,
179242
astree: ASTInterface,

0 commit comments

Comments
 (0)