Skip to content

Commit fba5a45

Browse files
committed
ARM:AST: updates for conversion to C expressions
1 parent 0168ba8 commit fba5a45

File tree

6 files changed

+164
-13
lines changed

6 files changed

+164
-13
lines changed

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-20250318"
1+
chbversion: str = "0.3.0-20250325"

chb/app/InstrXData.py

Lines changed: 96 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,11 @@ def __init__(
7373
self.expanded = False
7474
self._vars: List[XVariable] = []
7575
self._vars_r: List[Optional[XVariable]] = []
76+
self._cvars_r: List[Optional[XVariable]] = []
7677
self._types: List["BCTyp"] = []
7778
self._xprs: List[XXpr] = []
7879
self._xprs_r: List[Optional[XXpr]] = []
80+
self._cxprs_r: List[Optional[XXpr]] = []
7981
self._intervals: List[XInterval] = []
8082
self._strs: List[str] = []
8183
self._ints: List[int] = []
@@ -128,6 +130,12 @@ def vars_r(self) -> List[Optional[XVariable]]:
128130
self._expand()
129131
return self._vars_r
130132

133+
@property
134+
def cvars_r(self) -> List[Optional[XVariable]]:
135+
if not self.expanded:
136+
self._expand()
137+
return self._cvars_r
138+
131139
@property
132140
def types(self) -> List["BCTyp"]:
133141
if not self.expanded:
@@ -156,6 +164,17 @@ def get_var_x(self, index: int) -> Optional[XVariable]:
156164
+ str(len(self.vars))
157165
+ ")")
158166

167+
def get_cvar_r(self, index: int) -> Optional[XVariable]:
168+
if index < len(self.cvars_r):
169+
return self.cvars_r[index]
170+
else:
171+
raise UF.CHBError(
172+
"xdata: cvar-index out-of-bound: "
173+
+ str(index)
174+
+ " (length is "
175+
+ str(len(self.cvars_r))
176+
+ ")")
177+
159178
@property
160179
def xprs(self) -> List[XXpr]:
161180
if not self.expanded:
@@ -168,6 +187,12 @@ def xprs_r(self) -> List[Optional[XXpr]]:
168187
self._expand()
169188
return self._xprs_r
170189

190+
@property
191+
def cxprs_r(self) -> List[Optional[XXpr]]:
192+
if not self.expanded:
193+
self._expand()
194+
return self._cxprs_r
195+
171196
@property
172197
def intervals(self) -> List[XInterval]:
173198
if not self.expanded:
@@ -232,22 +257,60 @@ def is_ok(self) -> bool:
232257

233258
key = self.tags[0]
234259
if key.startswith("ar:"):
235-
return all(self.vars_r) and all(self.xprs_r)
260+
return all(self.vars_r) and all(self.xprs_r) and all(self.cxprs_r)
236261
else:
237262
return True
238263

264+
def has_var_r(self, index: int) -> bool:
265+
return index >= 0 and index < len(self.vars_r)
266+
267+
def is_var_ok(self, index: int) -> bool:
268+
if self.has_var_r(index):
269+
v = self.vars_r[index]
270+
return v is not None
271+
return False
272+
273+
def has_cvar_r(self, index: int) -> bool:
274+
return index >= 0 and index < len(self.cvars_r)
275+
276+
def is_cvar_ok(self, index: int) -> bool:
277+
if self.has_cvar_r(index):
278+
v = self.cvars_r[index]
279+
return v is not None
280+
return False
281+
282+
def has_xpr_r(self, index: int) -> bool:
283+
return index >= 0 and index < len(self.xprs_r)
284+
285+
def is_xpr_ok(self, index: int) -> bool:
286+
if self.has_xpr_r(index):
287+
x = self.xprs_r[index]
288+
return x is not None
289+
return False
290+
291+
def has_cxpr_r(self, index: int) -> bool:
292+
return index >= 0 and index < len(self.cxprs_r)
293+
294+
def is_cxpr_ok(self, index: int) -> bool:
295+
if self.has_cxpr_r(index):
296+
cx = self.cxprs_r[index]
297+
return cx is not None
298+
return False
299+
239300
@property
240-
def error_values(self) -> Tuple[List[int], List[int]]:
301+
def error_values(self) -> Tuple[List[int], List[int], List[int]]:
241302

242303
key = self.tags[0]
243304
if key.startswith("ar:"):
244305
vars_e: List[int] = [
245306
i for i in range(0, len(self.vars_r)) if self.vars_r[i] is None]
246307
xprs_e: List[int] = [
247308
i for i in range(0, len(self.xprs_r)) if self.xprs_r[i] is None]
248-
return (vars_e, xprs_e)
309+
cxprs_e: List[int] = [
310+
i for i in range(0, len(self.cxprs_r)) if self.cxprs_r[i] is None]
311+
return (vars_e, xprs_e, cxprs_e)
249312
else:
250-
return ([], [])
313+
return ([], [], [])
251314

252315

253316
def _expand(self) -> None:
@@ -290,6 +353,12 @@ def _expand(self) -> None:
290353
else:
291354
self._vars.append(xd.variable(arg))
292355

356+
elif c == "w":
357+
if arg == -2:
358+
self._cvars_r.append(None)
359+
else:
360+
self._cvars_r.append(xd.variable(arg))
361+
293362
elif c == "x":
294363
if use_result:
295364
if arg == -2:
@@ -299,6 +368,11 @@ def _expand(self) -> None:
299368
else:
300369
self._xprs.append(xd.xpr(arg))
301370

371+
elif c == "c":
372+
if arg == -2:
373+
self._cxprs_r.append(None)
374+
else:
375+
self._cxprs_r.append(xd.xpr(arg))
302376
elif c == "a":
303377
self._xprs.append(xd.xpr(arg))
304378
elif c == "s":
@@ -338,6 +412,7 @@ def is_function_argument(self) -> bool:
338412

339413
@property
340414
def function_argument_callsite(self) -> AsmAddress:
415+
# Currently only used in x86
341416
if self.is_function_argument:
342417
return self.bdictionary.address(self.args[2])
343418
else:
@@ -474,6 +549,15 @@ def get_base_update_xpr(self) -> XXpr:
474549
def has_return_xpr(self) -> bool:
475550
return any(s.startswith("return:") for s in self.tags)
476551

552+
def has_return_cxpr(self) -> bool:
553+
if any(s.startswith("return:") for s in self.tags):
554+
rvtag = next(t for t in self.tags if t.startswith("return:"))
555+
rvix = int(rvtag[7:])
556+
rval = self.args[rvix + 2]
557+
return rval >= 0
558+
else:
559+
return False
560+
477561
def get_return_xpr(self) -> XXpr:
478562
rvtag = next(t for t in self.tags if t.startswith("return:"))
479563
rvix = int(rvtag[7:])
@@ -490,6 +574,14 @@ def get_return_xxpr(self) -> XXpr:
490574
raise UF.CHBError("Unexpected error in rewritten return value")
491575
return self.xprdictionary.xpr(rval)
492576

577+
def get_return_cxpr(self) -> XXpr:
578+
rvtag = next(t for t in self.tags if t.startswith("return:"))
579+
rvix = int(rvtag[7:])
580+
rval = self.args[rvix + 2]
581+
if rval == -2:
582+
raise UF.CHBError("Unexpected error in C return value")
583+
return self.xprdictionary.xpr(rval)
584+
493585
@property
494586
def is_aggregate_jumptable(self) -> bool:
495587
return "agg-jt" in self.tags

chb/arm/ARMOpcode.py

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ def is_ok(self) -> bool:
119119
return self.xdata.is_ok
120120

121121
def var(self, index: int, name: str) -> "XVariable":
122-
if index >= len(self.xdata.vars_r):
122+
if not self.has_var(index):
123123
raise UF.CHBError(
124124
self.__class__.__name__ + ":"
125125
+ name + " index out of bounds: " + str(index))
@@ -129,8 +129,31 @@ def var(self, index: int, name: str) -> "XVariable":
129129
self.__class__.__name__ + ":" + name + " has an error value")
130130
return v
131131

132+
def has_var(self, index: int) -> bool:
133+
return self.xdata.has_var_r(index)
134+
135+
def is_var_ok(self, index: int) -> bool:
136+
return self.xdata.is_var_ok(index)
137+
138+
def cvar(self, index: int, name: str) -> "XVariable":
139+
if not self.has_cvar(index):
140+
raise UF.CHBError(
141+
self.__class__.__name__ + ":"
142+
+ name + " index out of bounds: " + str(index))
143+
cv = self.xdata.cvars_r[index]
144+
if cv is None:
145+
raise UF.CHBError(
146+
self.__class__.__name__ + ":" + name + " has an error value")
147+
return cv
148+
149+
def has_cvar(self, index: int) -> bool:
150+
return self.xdata.has_cxpr_r(index)
151+
152+
def is_cvar_ok(self, index: int) -> bool:
153+
return self.xdata.is_cvar_ok(index)
154+
132155
def xpr(self, index: int, name: str) -> "XXpr":
133-
if index >= len(self.xdata.xprs_r):
156+
if not self.has_xpr(index):
134157
raise UF.CHBError(
135158
self.__class__.__name__ + ":"
136159
+ name + " index out of bounds: " + str(index))
@@ -140,6 +163,29 @@ def xpr(self, index: int, name: str) -> "XXpr":
140163
self.__class__.__name__ + ":" + name + " has an error value")
141164
return x
142165

166+
def has_xpr(self, index: int) -> bool:
167+
return self.xdata.has_xpr_r(index)
168+
169+
def is_xpr_ok(self, index: int) -> bool:
170+
return self.xdata.is_xpr_ok(index)
171+
172+
def cxpr(self, index: int, name: str) -> "XXpr":
173+
if index >= len(self.xdata.cxprs_r):
174+
raise UF.CHBError(
175+
self.__class__.__name__ + ":"
176+
+ name + " cxpr index out of bounds: " + str(index))
177+
cx = self.xdata.cxprs_r[index]
178+
if cx is None:
179+
raise UF.CHBError(
180+
self.__class__.__name__ + ":" + name + " has an error value")
181+
return cx
182+
183+
def has_cxpr(self, index: int) -> bool:
184+
return self.xdata.has_cxpr_r(index)
185+
186+
def is_cxpr_ok(self, index: int) -> bool:
187+
return self.xdata.is_cxpr_ok(index)
188+
143189
def add_instruction_condition(self, s: str) -> str:
144190
if self.xdata.has_unknown_instruction_condition():
145191
return "if ? then " + s

chb/ast/ASTNode.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2772,6 +2772,9 @@ def is_union(self) -> bool:
27722772
def is_compinfo(self) -> bool:
27732773
return True
27742774

2775+
def has_fields(self) -> bool:
2776+
return len(self.fieldinfos) > 0
2777+
27752778
def has_field_offsets(self) -> bool:
27762779
return all(finfo.has_byteoffset() for finfo in self.fieldinfos)
27772780

chb/cmdline/commandutil.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -647,7 +647,7 @@ def results_stats(args: argparse.Namespace) -> NoReturn:
647647
if sortby == "instrs":
648648
sortkey = lambda f: f.instruction_count
649649
elif sortby == "basicblocks":
650-
sortkey = lambda f: f.block_count
650+
sortkey = lambda f: (f.block_count, f.instruction_count, int(f.faddr, 16))
651651
elif sortby == "loopdepth":
652652
sortkey = lambda f: f.loop_depth
653653
elif sortby == "time":

chb/invariants/XXprUtil.py

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,21 @@ def field_pointer_to_ast_memref_expr(
358358

359359
subfoffset: AST.ASTOffset = nooffset
360360
compinfo = astree.compinfo(compkey)
361+
362+
if not compinfo.has_fields():
363+
if not anonymous:
364+
chklogger.logger.error(
365+
"Struct definition is missing for %s at address %s (no fields found)",
366+
compinfo.compname, iaddr)
367+
return astree.mk_temp_lval_expression()
368+
369+
if not compinfo.has_field_offsets():
370+
if not anonymous:
371+
chklogger.logger.error(
372+
"Struct definition for %s does not have field offsets at address %s",
373+
compinfo.compname, iaddr)
374+
return astree.mk_temp_lval_expression()
375+
361376
(field, restoffset) = compinfo.field_at_offset(offset)
362377
if restoffset > 0:
363378
if field.fieldtype.is_compound:
@@ -750,11 +765,6 @@ def vinitmemory_value_to_ast_lval_expression(
750765
return vglobal_variable_value_to_ast_lval_expression(
751766
avar.offset, xdata, iaddr, astree, size=size, anonymous=anonymous)
752767

753-
if vconstvar.is_argument_deref_value:
754-
avar = vconstvar.variable.denotation
755-
return vargument_deref_value_to_ast_lval_expression(
756-
avar.basevar, avar.offset, xdata, iaddr, astree, anonymous=anonymous)
757-
758768
if vconstvar.is_function_return_deref_value:
759769
avar = vconstvar.variable.denotation
760770
return vreturn_deref_value_to_ast_lval_expression(

0 commit comments

Comments
 (0)