Skip to content

Commit 0687126

Browse files
committed
INV: add support for typecast values
1 parent 3975e55 commit 0687126

File tree

8 files changed

+181
-14
lines changed

8 files changed

+181
-14
lines changed

chb/arm/opcodes/ARMLoadRegister.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,13 +230,26 @@ def ast_prov(
230230
defuses = xdata.defuses
231231
defuseshigh = xdata.defuseshigh
232232

233+
def has_cast() -> bool:
234+
return (
235+
astree.has_register_variable_intro(iaddr)
236+
and astree.get_register_variable_intro(iaddr).has_cast())
237+
238+
if has_cast():
239+
lhstype = hl_lhs.ctype(astree.ctyper)
240+
if lhstype is not None:
241+
hl_rhs = astree.mk_cast_expr(lhstype, hl_rhs)
242+
233243
hl_assign = astree.mk_assign(
234244
hl_lhs,
235245
hl_rhs,
236246
iaddr=iaddr,
237247
bytestring=bytestring,
238248
annotations=annotations)
239249

250+
if has_cast():
251+
astree.add_expose_instruction(hl_assign.instrid)
252+
240253
astree.add_instr_mapping(hl_assign, ll_assign)
241254
astree.add_instr_address(hl_assign, [iaddr])
242255
astree.add_expr_mapping(hl_rhs, ll_rhs)
@@ -316,6 +329,10 @@ def ast_prov(
316329
astree.add_lval_defuses(ll_addr_lhs, defuses[1])
317330
astree.add_lval_defuses_high(ll_addr_lhs, defuseshigh[1])
318331
else:
332+
if astree.has_register_variable_intro(iaddr):
333+
rvintro = astree.get_register_variable_intro(iaddr)
334+
if rvintro.has_cast():
335+
astree.add_expose_instruction(hl_assign.instrid)
319336
ll_assigns = [ll_assign]
320337
hl_assigns = [hl_assign]
321338

chb/arm/opcodes/ARMLoadRegisterHalfword.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ def ast_prov(
199199

200200
elif xd.is_xrmem_unknown and xd.is_address_known:
201201
xaddr = xd.xaddr
202+
lhs = xd.vrt
202203
hl_lhs = XU.xvariable_to_ast_lval(lhs, xdata, iaddr, astree)
203204
hl_rhs = XU.xmemory_dereference_lval_expr(
204205
xaddr, xdata, iaddr, astree, size=2)

chb/astinterface/ASTICodeTransformer.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,9 @@ def transform_instruction_sequence_stmt(
8080
for instr in stmt.instructions:
8181
if instr.is_ast_assign:
8282
instr = cast(AST.ASTAssign, instr)
83-
if self.astinterface.has_ssa_value(str(instr.lhs)):
83+
if (
84+
self.astinterface.has_ssa_value(str(instr.lhs))
85+
and not self.provenance.has_expose_instruction(instr.instrid)):
8486
chklogger.logger.info(
8587
"Remove [%s]: has ssa value", str(instr))
8688
continue

chb/astinterface/ASTInterface.py

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
# ------------------------------------------------------------------------------
55
# The MIT License (MIT)
66
#
7-
# Copyright (c) 2021-2024 Aarno Labs LLC
7+
# Copyright (c) 2021-2025 Aarno Labs LLC
88
#
99
# Permission is hereby granted, free of charge, to any person obtaining a copy
1010
# of this software and associated documentation files (the "Software"), to deal
@@ -62,6 +62,8 @@
6262
from chb.astinterface.ASTIProvenance import ASTIProvenance
6363
import chb.astinterface.ASTIUtil as AU
6464

65+
from chb.userdata.UserHints import FunctionAnnotation, RegisterVarIntro
66+
6567
import chb.util.fileutil as UF
6668
from chb.util.loggingutil import chklogger
6769

@@ -98,6 +100,7 @@ def __init__(
98100
appsignature: Optional["AppFunctionSignature"] = None,
99101
rdeflocs: Dict[str, List[List[str]]] = {},
100102
varintros: Dict[str, str] = {},
103+
functionannotation: Optional[FunctionAnnotation] = None,
101104
stackvarintros: Dict[int, str] = {},
102105
patchevents: Dict[str, "PatchEvent"] = {},
103106
verbose: bool = False) -> None:
@@ -106,6 +109,7 @@ def __init__(
106109
self._astprototype = astprototype
107110
self._appsignature = appsignature
108111
self._rdeflocs = rdeflocs
112+
self._functionannotation = functionannotation
109113
self._varintros = varintros
110114
self._stackvarintros = stackvarintros
111115
self._patchevents = patchevents
@@ -152,10 +156,19 @@ def appsignature(self) -> Optional["AppFunctionSignature"]:
152156
def rdeflocs(self) -> Dict[str, List[List[str]]]:
153157
return self._rdeflocs
154158

159+
@property
160+
def function_annotation(self) -> Optional[FunctionAnnotation]:
161+
return self._functionannotation
162+
163+
def has_function_annotation(self) -> bool:
164+
return self.function_annotation is not None
165+
166+
# deprecated
155167
@property
156168
def varintros(self) -> Dict[str, str]:
157169
return self._varintros
158170

171+
# deprecated
159172
@property
160173
def stackvarintros(self) -> Dict[int, str]:
161174
return self._stackvarintros
@@ -265,15 +278,29 @@ def add_local_vardefinition(
265278
self._localvardefinitions.setdefault(iaddr, {})
266279
self._localvardefinitions[iaddr][var] = expr
267280

281+
# deprecated
268282
def has_variable_intro(self, iaddr: str) -> bool:
269283
return iaddr in self.varintros
270284

285+
# deprecated
271286
def get_variable_intro(self, iaddr: str) -> str:
272287
if self.has_variable_intro(iaddr):
273288
return self.varintros[iaddr]
274289
else:
275290
raise UF.CHBError("No variable intro found for " + iaddr)
276291

292+
def has_register_variable_intro(self, iaddr: str) -> bool:
293+
fnannotation = self.function_annotation
294+
if fnannotation is not None:
295+
return fnannotation.has_register_variable_introduction(iaddr)
296+
return False
297+
298+
def get_register_variable_intro(self, iaddr: str) -> RegisterVarIntro:
299+
fnannotation = self.function_annotation
300+
if fnannotation is not None:
301+
return fnannotation.get_register_variable_introduction(iaddr)
302+
raise UF.CHBError("No function annotation found")
303+
277304
def has_stack_variable_intro(self, offset: int) -> bool:
278305
return offset in self.stackvarintros
279306

@@ -1014,8 +1041,8 @@ def mk_ssa_register_varinfo(
10141041
return vinfo
10151042

10161043
# create a new ssa variable
1017-
if iaddr in self.varintros:
1018-
vname = self.varintros[iaddr]
1044+
if self.has_register_variable_intro(iaddr):
1045+
vname = self.get_register_variable_intro(iaddr).name
10191046
elif prefix is not None:
10201047
self._ssa_prefix_counters.setdefault(prefix, 0)
10211048
ssaid = self._ssa_prefix_counters[prefix]

chb/cmdline/astcmds.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -215,8 +215,8 @@ def buildast(args: argparse.Namespace) -> NoReturn:
215215
symbolicaddrs: Dict[str, str] = userhints.symbolic_addresses()
216216
revsymbolicaddrs = {v: k for (k, v) in symbolicaddrs.items()}
217217
revfunctionnames = userhints.rev_function_names()
218-
varintros = userhints.variable_introductions()
219-
stackvarintros = userhints.stack_variable_introductions()
218+
varintros = userhints.variable_introductions() # to be removed
219+
stackvarintros = userhints.stack_variable_introductions() # to be removed
220220

221221
# library_targets = library_call_targets(app, functions)
222222

@@ -324,6 +324,7 @@ def buildast(args: argparse.Namespace) -> NoReturn:
324324
fstackvarintros = {
325325
-off: name
326326
for (off, name) in stackvarintros.get(faddr, {}).items()}
327+
functionannotation = userhints.function_annotation(faddr)
327328

328329
astinterface = ASTInterface(
329330
astree,
@@ -333,6 +334,7 @@ def buildast(args: argparse.Namespace) -> NoReturn:
333334
astprototype=astprototype,
334335
appsignature=appsignature,
335336
varintros=varintros,
337+
functionannotation=functionannotation,
336338
stackvarintros=fstackvarintros,
337339
patchevents=patchevents,
338340
verbose=verbose)
@@ -341,7 +343,7 @@ def buildast(args: argparse.Namespace) -> NoReturn:
341343
# xdata records for all instructions in the function. Locations that
342344
# have a common user are merged. Types are provided by lhs_types.
343345
astinterface.introduce_ssa_variables(
344-
f.rdef_locations(), f.lhs_types(), f.lhs_names)
346+
f.rdef_locations(), f.register_lhs_types, f.lhs_names)
345347

346348
# Introduce stack variables for all stack buffers with types
347349
astinterface.introduce_stack_variables(

chb/invariants/VConstantValueVariable.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@
3939
* ctxt_iaddress_t
4040
* ctxt_iaddress_t
4141
| FunctionReturnValue of ctxt_iaddress_t "fr" 2 0
42+
| TypeCastValue of "tc" 3 2
43+
ctxt_iaddress_t
44+
* string
45+
* btype_t
46+
* register_t
4247
| SyscallErrorReturnValue of ctxt_iaddress_t "ev" 2 0
4348
| AugmentedValue of "av" 4 2
4449
variable_t
@@ -131,6 +136,10 @@ def is_global_value(self) -> bool:
131136
def is_function_return_value(self) -> bool:
132137
return False
133138

139+
@property
140+
def is_typecast_value(self) -> bool:
141+
return False
142+
134143
@property
135144
def is_symbolic_value(self) -> bool:
136145
return False
@@ -549,6 +558,46 @@ def __str__(self) -> str:
549558
return "rtn_" + self.callsite
550559

551560

561+
@varregistry.register_tag("tc", VConstantValueVariable)
562+
class VTypeCastValue(VConstantValueVariable):
563+
"""Type cast of a register value.
564+
565+
tags[1]: address of cast
566+
tags[2]: name of variable
567+
args[0]: index of cast target type in bcdictionary
568+
args[1]: index of register in bdictionary
569+
"""
570+
571+
def __init__(
572+
self,
573+
vd: "FnVarDictionary",
574+
ixval: IndexedTableValue) -> None:
575+
VConstantValueVariable.__init__(self, vd, ixval)
576+
577+
@property
578+
def is_typecast_value(self) -> bool:
579+
return True
580+
581+
@property
582+
def iaddr(self) -> str:
583+
return self.tags[1]
584+
585+
@property
586+
def name(self) -> str:
587+
return self.tags[2]
588+
589+
@property
590+
def tgttype(self) -> "BCTyp":
591+
return self.bcd.typ(self.args[0])
592+
593+
@property
594+
def register(self) -> Register:
595+
return self.bd.register(self.args[1])
596+
597+
def __str__(self) -> str:
598+
return self.name
599+
600+
552601
@varregistry.register_tag("fp", VConstantValueVariable)
553602
class FunctionPointer(VConstantValueVariable):
554603
"""Function pointer.

chb/invariants/XVariable.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
#
77
# Copyright (c) 2016-2020 Kestrel Technology LLC
88
# Copyright (c) 2020-2021 Henny Sipma
9-
# Copyright (c) 2021-2024 Aarno Labs LLC
9+
# Copyright (c) 2021-2025 Aarno Labs LLC
1010
#
1111
# Permission is hereby granted, free of charge, to any person obtaining a copy
1212
# of this software and associated documentation files (the "Software"), to deal
@@ -116,6 +116,13 @@ def is_function_return_value(self) -> bool:
116116
and self.denotation.is_auxiliary_variable
117117
and self.denotation.auxvar.is_function_return_value)
118118

119+
@property
120+
def is_typecast_value(self) -> bool:
121+
return (
122+
self.has_denotation()
123+
and self.denotation.is_auxiliary_variable
124+
and self.denotation.auxvar.is_typecast_value)
125+
119126
@property
120127
def is_memory_address_value(self) -> bool:
121128
return (

chb/invariants/XXprUtil.py

Lines changed: 68 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
VMemoryVariable, VAuxiliaryVariable, VRegisterVariable)
5656
from chb.invariants.VConstantValueVariable import (
5757
VInitialRegisterValue, VInitialMemoryValue, VFunctionReturnValue,
58-
SymbolicValue, MemoryAddress)
58+
VTypeCastValue, SymbolicValue, MemoryAddress)
5959
from chb.invariants.VMemoryBase import (
6060
VMemoryBase,
6161
VMemoryBaseBaseVar,
@@ -889,6 +889,14 @@ def xvariable_to_ast_def_lval_expression(
889889
vinfo = astree.globalsymboltable.get_symbol(name)
890890
return astree.mk_vinfo_lval_expression(vinfo, anonymous=anonymous)
891891

892+
if xvar.is_typecast_value:
893+
tcvar = cast("VTypeCastValue", xvar.denotation)
894+
chklogger.logger.error(
895+
"AST def conversion of typecast value %s to lval at address %s "
896+
+ "not yet supported",
897+
str(tcvar), iaddr)
898+
return astree.mk_temp_lval_expression()
899+
892900
chklogger.logger.error(
893901
"AST def conversion of variable %s to lval-expression at address "
894902
+ "%s not yet supported",
@@ -1553,12 +1561,17 @@ def global_variable_to_ast_lval(
15531561
if fieldoffset.offset.is_no_offset:
15541562
subfieldastoffset: AST.ASTOffset = nooffset
15551563
elif fieldoffset.offset.is_field_offset:
1556-
subfieldoffset = cast(
1564+
subfieldfldoffset = cast(
15571565
"VMemoryOffsetFieldOffset", fieldoffset.offset)
1558-
subfieldname = subfieldoffset.fieldname
1559-
subfieldkey = subfieldoffset.ckey
1566+
subfieldname = subfieldfldoffset.fieldname
1567+
subfieldkey = subfieldfldoffset.ckey
15601568
subfieldastoffset = astree.mk_field_offset(
15611569
subfieldname, subfieldkey)
1570+
elif fieldoffset.offset.is_array_index_offset:
1571+
subfieldarrayoffset = cast(
1572+
"VMemoryOffsetArrayIndexOffset", fieldoffset.offset)
1573+
subfieldastoffset = array_offset_to_ast_offset(
1574+
subfieldarrayoffset, xdata, iaddr, astree, anonymous=anonymous)
15621575
else:
15631576
chklogger.logger.error(
15641577
"Index sub offset of global offset %s not yet handled at %s",
@@ -1741,10 +1754,26 @@ def vargument_deref_value_to_ast_lval(
17411754
astree: ASTInterface,
17421755
anonymous: bool = False) -> AST.ASTLval:
17431756

1757+
if offset.is_no_offset:
1758+
asmvar = cast("VAuxiliaryVariable", basevar.denotation)
1759+
vinitvar = cast("VInitialRegisterValue", asmvar.auxvar)
1760+
xinitarg = vinitregister_value_to_ast_lval_expression(
1761+
vinitvar, xdata, iaddr, astree, anonymous=anonymous)
1762+
argtype = xinitarg.ctype(astree.ctyper)
1763+
if argtype is None:
1764+
chklogger.logger.error(
1765+
"Untyped dereferenced argument value %s not yet supported at "
1766+
+ "address %s",
1767+
str(xinitarg), iaddr)
1768+
return astree.mk_temp_lval()
1769+
else:
1770+
return astree.mk_memref_lval(xinitarg, anonymous=anonymous)
1771+
17441772
if not offset.is_constant_value_offset:
17451773
chklogger.logger.error(
1746-
"Non-constant offset: %s not yet supported at address %s",
1747-
str(offset), iaddr)
1774+
"Non-constant offset: %s with variable %s not yet supported at "
1775+
+ "address %s",
1776+
str(offset), str(basevar), iaddr)
17481777
return astree.mk_temp_lval()
17491778

17501779
coff = offset.offsetvalue()
@@ -1844,6 +1873,39 @@ def vargument_deref_value_to_ast_lval(
18441873
str(basevar), str(offset), iaddr)
18451874
return astree.mk_temp_lval()
18461875

1876+
if basevar.is_typecast_value:
1877+
asmvar = cast("VAuxiliaryVariable", basevar.denotation)
1878+
vtcv = cast("VTypeCastValue", asmvar.auxvar)
1879+
bctype = vtcv.tgttype
1880+
vtype = bctype.convert(astree.typconverter)
1881+
if vtype is not None and vtype.is_pointer:
1882+
tgttype = cast(AST.ASTTypPtr, vtype).tgttyp
1883+
castaddr = vtcv.iaddr
1884+
if len(astree.ssa_intros[castaddr]) == 1:
1885+
vinfo = list(astree.ssa_intros[castaddr].values())[0]
1886+
vexpr = astree.mk_vinfo_lval_expression(
1887+
vinfo, anonymous=anonymous)
1888+
if tgttype.is_compound:
1889+
1890+
return field_pointer_to_ast_memref_lval(
1891+
vexpr,
1892+
tgttype,
1893+
coff,
1894+
iaddr,
1895+
astree,
1896+
anonymous=anonymous)
1897+
1898+
chklogger.logger.error(
1899+
"AST conversion of typecast value %s with type %s not yet handled "
1900+
+ " at address %s",
1901+
str(basevar), str(tgttype), iaddr)
1902+
return astree.mk_temp_lval()
1903+
1904+
chklogger.logger.error(
1905+
"AST conversion of typecast value %s with type %s not yet handled at %s",
1906+
str(basevar), str(vtype), iaddr)
1907+
return astree.mk_temp_lval()
1908+
18471909
chklogger.logger.error(
18481910
"AST conversion of argument deref lvalue: %s with offset %s not yet "
18491911
+ "handled at %s (variable denotation type: %s)",

0 commit comments

Comments
 (0)