Skip to content

Commit 48e244c

Browse files
committed
AST: support for more expressive memory variable representation
1 parent 39c9c2d commit 48e244c

File tree

4 files changed

+197
-9
lines changed

4 files changed

+197
-9
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-20240805"
1+
chbversion: str = "0.3.0-20240829"

chb/arm/opcodes/ARMLoadRegister.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,8 +207,8 @@ def ast_prov(
207207
annotations=annotations)
208208
ll_assigns: List[AST.ASTInstruction] = [ll_assign, ll_addr_assign]
209209

210-
basereg = xdata.vars[1]
211-
newaddr = xdata.xprs[4]
210+
basereg = xdata.vars[2]
211+
newaddr = xdata.xprs[5]
212212
hl_addr_lhs = XU.xvariable_to_ast_lval(basereg, xdata, iaddr, astree)
213213
hl_addr_rhs = XU.xxpr_to_ast_def_expr(newaddr, xdata, iaddr, astree)
214214

@@ -220,6 +220,9 @@ def ast_prov(
220220
annotations=annotations)
221221
hl_assigns: List[AST.ASTInstruction] = [hl_assign, hl_addr_assign]
222222

223+
# Note: work-around for deficiency in def-use propagation
224+
astree.add_expose_instruction(hl_addr_assign.instrid)
225+
223226
astree.add_instr_mapping(hl_addr_assign, ll_addr_assign)
224227
astree.add_instr_address(hl_addr_assign, [iaddr])
225228
astree.add_expr_mapping(hl_addr_rhs, ll_addr_rhs)

chb/invariants/VMemoryBase.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,10 @@ def is_basevar(self) -> bool:
8585
def is_basearray(self) -> bool:
8686
return False
8787

88+
@property
89+
def is_basestruct(self) -> bool:
90+
return False
91+
8892
@property
8993
def is_global(self) -> bool:
9094
return False
@@ -249,6 +253,46 @@ def __str__(self) -> str:
249253
return str(self.basearray)
250254

251255

256+
@varregistry.register_tag("s", VMemoryBase)
257+
class VMemoryBaseBaseStruct(VMemoryBase):
258+
"""Base struct address.
259+
260+
args[0]: index of variable in xprdictionary
261+
args[1]: index of struct type in bcdictionary
262+
"""
263+
264+
def __init__(
265+
self,
266+
vd: "FnVarDictionary",
267+
ixval: IndexedTableValue) -> None:
268+
VMemoryBase.__init__(self, vd, ixval)
269+
270+
@property
271+
def is_basestruct(self) -> bool:
272+
return True
273+
274+
@property
275+
def basestruct(self) -> "XVariable":
276+
return self.xd.variable(self.args[0])
277+
278+
@property
279+
def basetyp(self) -> "BCTyp":
280+
return self.bcd.typ(self.args[1])
281+
282+
def to_json_result(self) -> JSONResult:
283+
ptrvar = self.basestruct.to_json_result()
284+
if ptrvar.is_ok:
285+
content: Dict[str, Any] = {}
286+
content["ptrvar"] = ptrvar.content
287+
return JSONResult("memorybase", content, "ok")
288+
else:
289+
return JSONResult(
290+
"memorybase", {}, "fail", "memorybase: " + str(ptrvar.reason))
291+
292+
def __str__(self) -> str:
293+
return str(self.basestruct)
294+
295+
252296
@varregistry.register_tag("g", VMemoryBase)
253297
class VMemoryBaseGlobal(VMemoryBase):
254298

chb/invariants/XXprUtil.py

Lines changed: 147 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@
4949
from chb.invariants.VConstantValueVariable import (
5050
VInitialRegisterValue, VInitialMemoryValue, VFunctionReturnValue,
5151
SymbolicValue, MemoryAddress)
52-
from chb.invariants.VMemoryBase import VMemoryBaseBaseArray
52+
from chb.invariants.VMemoryBase import (
53+
VMemoryBase, VMemoryBaseBaseArray, VMemoryBaseBaseStruct)
5354
from chb.invariants.VMemoryOffset import (
5455
VMemoryOffset,
5556
VMemoryOffsetConstantOffset,
@@ -59,6 +60,16 @@
5960
from chb.mips.MIPSRegister import MIPSRegister
6061

6162

63+
def prdebug(
64+
s: str, iaddr: Optional[str] = None, iaddrs: List[str] = []) -> None:
65+
if iaddr is None:
66+
print("DEBUG: " + s)
67+
elif iaddr in iaddrs:
68+
print("DEBUG: " + iaddr + ": " + s)
69+
else:
70+
None
71+
72+
6273
def is_struct_field_address(xpr: X.XXpr, astree: ASTInterface) -> bool:
6374
"""Return true if the expression is the address of a known struct."""
6475

@@ -254,6 +265,37 @@ def vreturn_deref_value_to_ast_lval_expression(
254265
return astree.mk_temp_lval_expression()
255266

256267

268+
def memory_variable_to_lval_expression(
269+
base: "VMemoryBase",
270+
offset: "VMemoryOffset",
271+
xdata: "InstrXData",
272+
iaddr: str,
273+
astree: ASTInterface,
274+
size: int = 4) -> AST.ASTExpr:
275+
276+
name = str(base)
277+
278+
if not astree.globalsymboltable.has_symbol(name):
279+
chklogger.logger.error(
280+
"AST conversion of memory variable %s not in global symbol "
281+
+ "table not yet supported at address %s",
282+
name, iaddr)
283+
return astree.mk_temp_lval_expression()
284+
285+
vinfo = astree.globalsymboltable.get_symbol(name)
286+
if offset.is_field_offset:
287+
offset = cast("VMemoryOffsetFieldOffset", offset)
288+
astoffset = field_offset_to_ast_offset(offset, xdata, iaddr, astree)
289+
return astree.mk_vinfo_lval_expression(vinfo, astoffset)
290+
291+
chklogger.logger.error(
292+
"AST conversion of memory variable %s with other offset not yet "
293+
+ "supported at address %s",
294+
name, iaddr)
295+
296+
return astree.mk_temp_lval_expression()
297+
298+
257299
def global_variable_to_lval_expression(
258300
offset: "VMemoryOffset",
259301
xdata: "InstrXData",
@@ -565,6 +607,11 @@ def xvariable_to_ast_def_lval_expression(
565607
return global_variable_to_lval_expression(
566608
memvar.offset, xdata, iaddr, astree)
567609

610+
if xvar.is_memory_variable:
611+
memvar = cast("VMemoryVariable", xvar.denotation)
612+
return memory_variable_to_lval_expression(
613+
memvar.base, memvar.offset, xdata, iaddr, astree)
614+
568615
if xvar.is_local_stack_variable:
569616
stackvar = cast("VMemoryVariable", xvar.denotation)
570617
offset = stackvar.offset.offsetvalue()
@@ -826,6 +873,7 @@ def default() -> AST.ASTExpr:
826873

827874
if hl_addr.is_ast_lval_expr:
828875
hl_addr_type = hl_addr.ctype(astree.ctyper)
876+
829877
if hl_addr_type is None:
830878
return default()
831879

@@ -845,6 +893,11 @@ def default() -> AST.ASTExpr:
845893
else:
846894
return default()
847895

896+
if hl_addr.is_ast_addressof:
897+
hl_addr = cast(AST.ASTAddressOf, hl_addr)
898+
hl_lval = hl_addr.lval
899+
return astree.mk_lval_expr(hl_lval)
900+
848901
if hl_addr.is_ast_binary_op:
849902
hl_addr = cast(AST.ASTBinaryOp, hl_addr)
850903

@@ -980,7 +1033,6 @@ def stack_variable_to_ast_lval(
9801033

9811034

9821035
def array_offset_to_ast_offset(
983-
elementtyp: AST.ASTTyp,
9841036
offset: "VMemoryOffsetArrayIndexOffset",
9851037
xdata: "InstrXData",
9861038
iaddr: str,
@@ -1001,7 +1053,36 @@ def to_ast_offset(suboffset: "VMemoryOffset") -> AST.ASTOffset:
10011053
else:
10021054
return nooffset
10031055

1004-
return astree.mk_expr_index_offset(indexxpr, offset=to_ast_offset(offset.offset))
1056+
return astree.mk_expr_index_offset(
1057+
indexxpr, offset=to_ast_offset(offset.offset))
1058+
1059+
1060+
def field_offset_to_ast_offset(
1061+
offset: "VMemoryOffsetFieldOffset",
1062+
xdata: "InstrXData",
1063+
iaddr: str,
1064+
astree: ASTInterface) -> AST.ASTOffset:
1065+
1066+
if offset.has_no_offset():
1067+
return astree.mk_field_offset(offset.fieldname, offset.ckey)
1068+
1069+
if offset.offset.is_field_offset:
1070+
fieldoffset = cast("VMemoryOffsetFieldOffset", offset.offset)
1071+
suboffset = field_offset_to_ast_offset(
1072+
fieldoffset, xdata, iaddr, astree)
1073+
elif offset.offset.is_array_index_offset:
1074+
arrayindexoffset = cast("VMemoryOffsetArrayIndexOffset", offset.offset)
1075+
suboffset = array_offset_to_ast_offset(
1076+
arrayindexoffset, xdata, iaddr, astree)
1077+
elif offset.offset.is_constant_value_offset:
1078+
suboffset = astree.mk_scalar_index_offset(offset.offset.offsetvalue())
1079+
else:
1080+
suboffset = nooffset
1081+
1082+
return astree.mk_field_offset(
1083+
offset.fieldname, offset.ckey, offset=suboffset)
1084+
1085+
10051086

10061087
def array_variable_to_ast_lval(
10071088
base: "MemoryAddress",
@@ -1035,7 +1116,6 @@ def array_variable_to_ast_lval(
10351116
return astree.mk_temp_lval()
10361117

10371118
astoffset = array_offset_to_ast_offset(
1038-
elementtyp,
10391119
cast("VMemoryOffsetArrayIndexOffset", offset),
10401120
xdata,
10411121
iaddr,
@@ -1050,6 +1130,46 @@ def array_variable_to_ast_lval(
10501130
return astree.mk_temp_lval()
10511131

10521132

1133+
def struct_variable_to_ast_lval(
1134+
base: "MemoryAddress",
1135+
structtyp: AST.ASTTypComp,
1136+
offset: "VMemoryOffset",
1137+
xdata: "InstrXData",
1138+
iaddr: str,
1139+
astree: ASTInterface) -> AST.ASTLval:
1140+
1141+
name = base.name
1142+
if name is None:
1143+
chklogger.logger.error(
1144+
"AST conversion of struct variable at %s encountered nameless "
1145+
+ "base %s",
1146+
str(iaddr), str(base))
1147+
return astree.mk_temp_lval()
1148+
1149+
if not astree.globalsymboltable.has_symbol(name):
1150+
chklogger.logger.error(
1151+
"AST conversion of memory address value %s not in global symbol "
1152+
+ " table not yet supported at address %s",
1153+
str(name), iaddr)
1154+
return astree.mk_temp_lval()
1155+
1156+
vinfo = astree.globalsymboltable.get_symbol(name)
1157+
if not offset.is_field_offset:
1158+
chklogger.logger.error(
1159+
"AST conversion of struct variable expected to find field offset "
1160+
+ "but found %s at address %s",
1161+
str(offset), iaddr)
1162+
return astree.mk_temp_lval()
1163+
1164+
astoffset = field_offset_to_ast_offset(
1165+
cast("VMemoryOffsetFieldOffset", offset),
1166+
xdata,
1167+
iaddr,
1168+
astree)
1169+
1170+
return astree.mk_vinfo_lval(vinfo, offset=astoffset)
1171+
1172+
10531173
def global_variable_to_ast_lval(
10541174
offset: "VMemoryOffset",
10551175
xdata: "InstrXData",
@@ -1190,8 +1310,8 @@ def xvariable_to_ast_lval(
11901310

11911311
elif (
11921312
xv.is_memory_variable
1193-
and cast ("VMemoryVariable",
1194-
xv.denotation).base.is_basearray):
1313+
and cast("VMemoryVariable",
1314+
xv.denotation).base.is_basearray):
11951315
xvmem = cast("VMemoryVariable", xv.denotation)
11961316
base = cast("VMemoryBaseBaseArray", xvmem.base).basearray
11971317
if not base.is_memory_address_value:
@@ -1209,6 +1329,27 @@ def xvariable_to_ast_lval(
12091329
iaddr,
12101330
astree)
12111331

1332+
elif (
1333+
xv.is_memory_variable
1334+
and cast("VMemoryVariable",
1335+
xv.denotation).base.is_basestruct):
1336+
xvmem = cast ("VMemoryVariable", xv.denotation)
1337+
base = cast("VMemoryBaseBaseStruct", xvmem.base).basestruct
1338+
if not base.is_memory_address_value:
1339+
chklogger.logger.error(
1340+
"AST conversion of lval %s encountered invalie BaseStruct at %s",
1341+
str(xv), iaddr)
1342+
return astree.mk_temp_lval()
1343+
basevar = cast("MemoryAddress", base.denotation.auxvar)
1344+
basetyp = cast("VMemoryBaseBaseStruct", xvmem.base).basetyp.convert(astree.typconverter)
1345+
return struct_variable_to_ast_lval(
1346+
basevar,
1347+
cast(AST.ASTTypComp, basetyp),
1348+
xvmem.offset,
1349+
xdata,
1350+
iaddr,
1351+
astree)
1352+
12121353
else:
12131354
chklogger.logger.error(
12141355
"AST conversion of lval %s at address %s not yet supported",

0 commit comments

Comments
 (0)