44# ------------------------------------------------------------------------------
55# The MIT License (MIT)
66#
7- # Copyright (c) 2021-2023 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
2525# SOFTWARE.
2626# ------------------------------------------------------------------------------
2727
28- from typing import List , TYPE_CHECKING
28+ from typing import cast , List , Tuple , TYPE_CHECKING
2929
3030from chb .app .InstrXData import InstrXData
3131
3232from chb .arm .ARMDictionaryRecord import armregistry
33- from chb .arm .ARMOpcode import ARMOpcode , simplify_result
33+ from chb .arm .ARMOpcode import ARMOpcode , ARMOpcodeXData , simplify_result
3434from chb .arm .ARMOperand import ARMOperand
3535
36- import chb .util .fileutil as UF
36+ import chb .ast .ASTNode as AST
37+ from chb .astinterface .ASTInterface import ASTInterface
38+
39+ import chb .invariants .XXprUtil as XU
3740
41+ import chb .util .fileutil as UF
3842from chb .util .IndexedTable import IndexedTableValue
43+ from chb .util .loggingutil import chklogger
44+
3945
4046if TYPE_CHECKING :
4147 from chb .arm .ARMDictionary import ARMDictionary
48+ from chb .invariants .VAssemblyVariable import VMemoryVariable
49+ from chb .invariants .XVariable import XVariable
50+ from chb .invariants .XXpr import XXpr
51+
52+
53+ class ARMStoreMultipleIncrementBeforeXData (ARMOpcodeXData ):
54+
55+ def __init__ (self , xdata : InstrXData ) -> None :
56+ ARMOpcodeXData .__init__ (self , xdata )
57+
58+ @property
59+ def regcount (self ) -> int :
60+ return len (self .xdata .vars_r ) - 1
61+
62+ @property
63+ def baselhs (self ) -> "XVariable" :
64+ return self .var (0 , "baselhs" )
65+
66+ @property
67+ def is_baselhs_known (self ) -> bool :
68+ return self .xdata .vars_r [0 ] is not None
69+
70+ @property
71+ def memlhss (self ) -> List ["XVariable" ]:
72+ return [self .var (i , "memlhs-" + str (i ))
73+ for i in range (1 , self .regcount + 1 )]
74+
75+ @property
76+ def rhss (self ) -> List ["XXpr" ]:
77+ return [self .xpr (i , "rhs-" + str (i ))
78+ for i in range (3 , self .regcount + 3 )]
79+
80+ @property
81+ def annotation (self ) -> str :
82+ wbu = self .writeback_update ()
83+ if self .is_ok :
84+ assigns : List [str ] = []
85+ for (memlhs , rhs ) in zip (self .memlhss , self .rhss ):
86+ assigns .append (str (memlhs ) + " := " + str (rhs ))
87+ return ": " .join (assigns ) + wbu
88+ else :
89+ return "Error value"
90+
4291
4392
4493@armregistry .register_tag ("STMIB" , ARMOpcode )
@@ -65,13 +114,94 @@ def __init__(
65114 def operands (self ) -> List [ARMOperand ]:
66115 return [self .armd .arm_operand (self .args [i ]) for i in [1 , 2 ]]
67116
117+ @property
118+ def opargs (self ) -> List [ARMOperand ]:
119+ return [self .armd .arm_operand (self .args [i ]) for i in [1 , 2 , 3 ]]
120+
68121 def is_store_instruction (self , xdata : InstrXData ) -> bool :
69122 return True
70123
71124 def annotation (self , xdata : InstrXData ) -> str :
72- """xdata format: a:vxx .
73-
74- xprs[0..n]: rhs expressions
75- """
125+ xd = ARMStoreMultipleIncrementBeforeXData (xdata )
126+ return xd .annotation
76127
77- return '; "' .join (" := ? := " + str (x ) for x in xdata .xprs )
128+ def ast_prov (
129+ self ,
130+ astree : ASTInterface ,
131+ iaddr : str ,
132+ bytestring : str ,
133+ xdata : InstrXData ) -> Tuple [
134+ List [AST .ASTInstruction ], List [AST .ASTInstruction ]]:
135+
136+ xd = ARMStoreMultipleIncrementBeforeXData (xdata )
137+ if not xd .is_ok :
138+ chklogger .logger .error (
139+ "STMIB: Error value encountered at address %s" , iaddr )
140+ return ([], [])
141+
142+ annotations : List [str ] = [iaddr , "STMIB" ]
143+
144+ ll_instrs : List [AST .ASTInstruction ] = []
145+ hl_instrs : List [AST .ASTInstruction ] = []
146+
147+ (baselval , _ , _ ) = self .opargs [0 ].ast_lvalue (astree )
148+ (baserval , _ , _ ) = self .opargs [0 ].ast_rvalue (astree )
149+
150+ memlhss = xd .memlhss
151+ regrhss = xd .rhss
152+ regrdefs = xdata .reachingdefs [1 :]
153+ memuses = xdata .defuses [1 :]
154+ memuseshigh = xdata .defuseshigh [1 :]
155+
156+ regsop = self .opargs [1 ]
157+ registers = regsop .registers
158+ base_offset = 4
159+ for (i , r ) in enumerate (registers ):
160+
161+ # low-level assignments
162+
163+ base_offset_c = astree .mk_integer_constant (base_offset )
164+ addr = astree .mk_binary_op ("plus" , baserval , base_offset_c )
165+ ll_lhs = astree .mk_memref_lval (addr )
166+ ll_rhs = astree .mk_register_variable_expr (r )
167+ ll_assign = astree .mk_assign (
168+ ll_lhs ,
169+ ll_rhs ,
170+ iaddr = iaddr ,
171+ bytestring = bytestring ,
172+ annotations = annotations )
173+ ll_instrs .append (ll_assign )
174+
175+ # high-level assignments
176+
177+ memlhs = memlhss [i ]
178+ regrhs = regrhss [i ]
179+
180+ hl_lhs = XU .xvariable_to_ast_lval (memlhs , xdata , iaddr , astree )
181+ hl_rhs = XU .xxpr_to_ast_def_expr (regrhs , xdata , iaddr , astree )
182+ hl_assign = astree .mk_assign (
183+ hl_lhs ,
184+ hl_rhs ,
185+ iaddr = iaddr ,
186+ bytestring = bytestring ,
187+ annotations = annotations )
188+ hl_instrs .append (hl_assign )
189+
190+ astree .add_instr_mapping (hl_assign , ll_assign )
191+ astree .add_instr_address (hl_assign , [iaddr ])
192+ astree .add_expr_mapping (hl_rhs , ll_rhs )
193+ astree .add_lval_mapping (hl_lhs , ll_lhs )
194+ astree .add_expr_reachingdefs (ll_rhs , [regrdefs [i ]])
195+ astree .add_lval_defuses (hl_lhs , memuses [i ])
196+ astree .add_lval_defuses_high (hl_lhs , memuseshigh [i ])
197+
198+ base_offset += 4
199+
200+ if (
201+ (memlhs .is_memory_variable
202+ and cast ("VMemoryVariable" , memlhs .denotation ).base .is_basevar )):
203+ astree .add_expose_instruction (hl_assign .instrid )
204+
205+ # TODO: add writeback update
206+
207+ return (hl_instrs , ll_instrs )
0 commit comments