diff --git a/chb/app/AppResultFunctionMetrics.py b/chb/app/AppResultFunctionMetrics.py index 68a0b957..a83ad60f 100644 --- a/chb/app/AppResultFunctionMetrics.py +++ b/chb/app/AppResultFunctionMetrics.py @@ -6,7 +6,7 @@ # # Copyright (c) 2016-2020 Kestrel Technology LLC # Copyright (c) 2020 Henny Sipma -# Copyright (c) 2021 Aarno Labs LLC +# Copyright (c) 2021-2025 Aarno Labs LLC # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -28,7 +28,7 @@ # ------------------------------------------------------------------------------ import xml.etree.ElementTree as ET -from typing import Dict, Optional, TYPE_CHECKING +from typing import Dict, List, Optional, TYPE_CHECKING import chb.util.fileutil as UF @@ -236,10 +236,13 @@ def as_dictionary(self) -> Dict[str, str]: def metrics_to_string( self, shownocallees: bool = False, - space: str = " ") -> str: + space: str = " ", + tags: List[str] = [], + taglen: int = 0) -> str: callcount = '' name = '' unrc = '' + ftags = "".ljust(taglen) if shownocallees and (not self.has_name()): if self.call_count == 0: callcount = ' (no callees)' @@ -247,6 +250,9 @@ def metrics_to_string( name = ' (' + self.name + ')' if self.unresolved_call_count > 0: unrc = str(self.unresolved_call_count) + if len(tags) > 0: + ftags = (" [" + ",".join(tags) + "]").ljust(taglen) + return (str(self.faddr).ljust(10) + space + '{:6.1f}'.format(self.espp) + space + '{:6.1f}'.format(self.readsp) + space @@ -254,4 +260,4 @@ def metrics_to_string( + unrc.rjust(6) + space + str(self.block_count).rjust(6) + space + str(self.instruction_count).rjust(6) + space - + '{:8.3f}'.format(self.time) + name + callcount) + + '{:8.3f}'.format(self.time) + ftags + name + callcount) diff --git a/chb/app/AppResultMetrics.py b/chb/app/AppResultMetrics.py index eb2ce2b9..eb43d355 100644 --- a/chb/app/AppResultMetrics.py +++ b/chb/app/AppResultMetrics.py @@ -6,7 +6,7 @@ # # Copyright (c) 2016-2020 Kestrel Technology LLC # Copyright (c) 2020 Henny Sipma -# Copyright (c) 2021-2024 Aarno Labs LLC +# Copyright (c) 2021-2025 Aarno Labs LLC # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/chb/app/CHVersion.py b/chb/app/CHVersion.py index 1ab6486a..644f53e5 100644 --- a/chb/app/CHVersion.py +++ b/chb/app/CHVersion.py @@ -1 +1 @@ -chbversion: str = "0.3.0-20250318" +chbversion: str = "0.3.0-20250401" diff --git a/chb/app/Cfg.py b/chb/app/Cfg.py index 07bfa145..827ce949 100644 --- a/chb/app/Cfg.py +++ b/chb/app/Cfg.py @@ -685,12 +685,14 @@ def ast(self, if astblock.has_return: instr = astblock.last_instruction rv = instr.return_value() + astexpr: Optional[AST.ASTExpr] = None if rv is not None and not astree.returns_void(): - astexpr: Optional[AST.ASTExpr] = XU.xxpr_to_ast_def_expr( + astexpr = XU.xxpr_to_ast_def_expr( rv, instr.xdata, instr.iaddr, astree) - else: - astexpr = None - # astexpr = astexprs[0] if len(astexprs) == 1 else None + if rv.is_string_reference: + cstr = rv.constant.string_reference() + straddr = hex(rv.constant.value) + astexpr = astree.mk_string_constant(astexpr, cstr, straddr) rtnstmt = astree.mk_return_stmt(astexpr, instr.iaddr, instr.bytestring) blockstmts[n] = [blocknode, rtnstmt] else: diff --git a/chb/app/InstrXData.py b/chb/app/InstrXData.py index 06bee162..768da68d 100644 --- a/chb/app/InstrXData.py +++ b/chb/app/InstrXData.py @@ -71,12 +71,13 @@ def __init__( IndexedTableValue.__init__(self, ixval.index, ixval.tags, ixval.args) self._fnd = fnd self.expanded = False - self._ssavals: List[XVariable] = [] self._vars: List[XVariable] = [] self._vars_r: List[Optional[XVariable]] = [] + self._cvars_r: List[Optional[XVariable]] = [] self._types: List["BCTyp"] = [] self._xprs: List[XXpr] = [] self._xprs_r: List[Optional[XXpr]] = [] + self._cxprs_r: List[Optional[XXpr]] = [] self._intervals: List[XInterval] = [] self._strs: List[str] = [] self._ints: List[int] = [] @@ -130,33 +131,16 @@ def vars_r(self) -> List[Optional[XVariable]]: return self._vars_r @property - def types(self) -> List["BCTyp"]: + def cvars_r(self) -> List[Optional[XVariable]]: if not self.expanded: self._expand() - return self._types + return self._cvars_r @property - def ssavals(self) -> List[XVariable]: + def types(self) -> List["BCTyp"]: if not self.expanded: self._expand() - return self._ssavals - - def has_ssaval(self, register: str) -> bool: - for v in self._ssavals: - if v.is_ssa_register_value: - ssaval = v.ssa_register_value() - if str(ssaval.register) == register: - return True - return False - - def get_ssaval(self, register: str) -> "SSARegisterValue": - for v in self._ssavals: - if v.is_ssa_register_value: - ssaval = v.ssa_register_value() - if str(ssaval.register) == register: - return ssaval - raise UF.CHBError( - "No ssa value found for register " + register) + return self._types def get_var(self, index: int) -> XVariable: if index < len(self.vars): @@ -180,6 +164,17 @@ def get_var_x(self, index: int) -> Optional[XVariable]: + str(len(self.vars)) + ")") + def get_cvar_r(self, index: int) -> Optional[XVariable]: + if index < len(self.cvars_r): + return self.cvars_r[index] + else: + raise UF.CHBError( + "xdata: cvar-index out-of-bound: " + + str(index) + + " (length is " + + str(len(self.cvars_r)) + + ")") + @property def xprs(self) -> List[XXpr]: if not self.expanded: @@ -192,6 +187,12 @@ def xprs_r(self) -> List[Optional[XXpr]]: self._expand() return self._xprs_r + @property + def cxprs_r(self) -> List[Optional[XXpr]]: + if not self.expanded: + self._expand() + return self._cxprs_r + @property def intervals(self) -> List[XInterval]: if not self.expanded: @@ -256,12 +257,48 @@ def is_ok(self) -> bool: key = self.tags[0] if key.startswith("ar:"): - return all(self.vars_r) and all(self.xprs_r) + return all(self.vars_r) and all(self.xprs_r) and all(self.cxprs_r) else: return True + def has_var_r(self, index: int) -> bool: + return index >= 0 and index < len(self.vars_r) + + def is_var_ok(self, index: int) -> bool: + if self.has_var_r(index): + v = self.vars_r[index] + return v is not None + return False + + def has_cvar_r(self, index: int) -> bool: + return index >= 0 and index < len(self.cvars_r) + + def is_cvar_ok(self, index: int) -> bool: + if self.has_cvar_r(index): + v = self.cvars_r[index] + return v is not None + return False + + def has_xpr_r(self, index: int) -> bool: + return index >= 0 and index < len(self.xprs_r) + + def is_xpr_ok(self, index: int) -> bool: + if self.has_xpr_r(index): + x = self.xprs_r[index] + return x is not None + return False + + def has_cxpr_r(self, index: int) -> bool: + return index >= 0 and index < len(self.cxprs_r) + + def is_cxpr_ok(self, index: int) -> bool: + if self.has_cxpr_r(index): + cx = self.cxprs_r[index] + return cx is not None + return False + @property - def error_values(self) -> Tuple[List[int], List[int]]: + def error_values(self) -> Tuple[List[int], List[int], List[int]]: key = self.tags[0] if key.startswith("ar:"): @@ -269,9 +306,11 @@ def error_values(self) -> Tuple[List[int], List[int]]: i for i in range(0, len(self.vars_r)) if self.vars_r[i] is None] xprs_e: List[int] = [ i for i in range(0, len(self.xprs_r)) if self.xprs_r[i] is None] - return (vars_e, xprs_e) + cxprs_e: List[int] = [ + i for i in range(0, len(self.cxprs_r)) if self.cxprs_r[i] is None] + return (vars_e, xprs_e, cxprs_e) else: - return ([], []) + return ([], [], []) def _expand(self) -> None: @@ -314,6 +353,12 @@ def _expand(self) -> None: else: self._vars.append(xd.variable(arg)) + elif c == "w": + if arg == -2: + self._cvars_r.append(None) + else: + self._cvars_r.append(xd.variable(arg)) + elif c == "x": if use_result: if arg == -2: @@ -323,6 +368,11 @@ def _expand(self) -> None: else: self._xprs.append(xd.xpr(arg)) + elif c == "c": + if arg == -2: + self._cxprs_r.append(None) + else: + self._cxprs_r.append(xd.xpr(arg)) elif c == "a": self._xprs.append(xd.xpr(arg)) elif c == "s": @@ -353,8 +403,6 @@ def _expand(self) -> None: flagrdef = varinvd.var_invariant_fact(arg) if arg >= 0 else None flagrdef = cast(Optional[FlagReachingDefFact], flagrdef) self._flagreachingdefs.append(flagrdef) - elif c == "c": - self._ssavals.append(xd.variable(arg)) else: raise UF.CHBError("Key letter not recognized: " + c) @@ -364,6 +412,7 @@ def is_function_argument(self) -> bool: @property def function_argument_callsite(self) -> AsmAddress: + # Currently only used in x86 if self.is_function_argument: return self.bdictionary.address(self.args[2]) else: @@ -434,6 +483,9 @@ def has_branch_conditions(self) -> bool: def has_condition_setter(self) -> bool: return len(self.tags) == 4 and self.tags[1] == "TF" + def has_missing_branch_conditions(self) -> bool: + return len(self.tags) > 1 and self.tags[1] == "TF:no-x" + def get_condition_setter(self) -> str: if len(self.tags) > 2: return self.tags[2] @@ -497,9 +549,29 @@ def get_base_update_xpr(self) -> XXpr: "Unexpected error value in base-update expression") return self.xprdictionary.xpr(xbuval) + def get_base_update_cxpr(self) -> XXpr: + cbutag = next(t for t in self.tags if t.startswith("cbu:")) + cix = int(cbutag[4:]) + cbuval = self.args[cix] + if cbuval == -2: + chklogger.logger.info( + "Base update c expression unavailable, fall back to expression") + return self.get_base_update_xpr() + else: + return self.xprdictionary.xpr(cbuval) + def has_return_xpr(self) -> bool: return any(s.startswith("return:") for s in self.tags) + def has_return_cxpr(self) -> bool: + if any(s.startswith("return:") for s in self.tags): + rvtag = next(t for t in self.tags if t.startswith("return:")) + rvix = int(rvtag[7:]) + rval = self.args[rvix + 2] + return rval >= 0 + else: + return False + def get_return_xpr(self) -> XXpr: rvtag = next(t for t in self.tags if t.startswith("return:")) rvix = int(rvtag[7:]) @@ -516,6 +588,14 @@ def get_return_xxpr(self) -> XXpr: raise UF.CHBError("Unexpected error in rewritten return value") return self.xprdictionary.xpr(rval) + def get_return_cxpr(self) -> XXpr: + rvtag = next(t for t in self.tags if t.startswith("return:")) + rvix = int(rvtag[7:]) + rval = self.args[rvix + 2] + if rval == -2: + raise UF.CHBError("Unexpected error in C return value") + return self.xprdictionary.xpr(rval) + @property def is_aggregate_jumptable(self) -> bool: return "agg-jt" in self.tags @@ -577,9 +657,4 @@ def __str__(self) -> str: lines.append("defuses[" + str(i) + "] = " + str(d)) for (i, du) in enumerate(self.defuseshigh): lines.append("defuseshigh[" + str(i) + "] = " + str(du)) - for (i, s) in enumerate(self.ssavals): - line = "ssa[" + str(i) + "] = " + str(s) - if s.is_ssa_register_value: - line += " -> register " + str(s.ssa_register_value().register) - lines.append(line) return "\n".join(lines) diff --git a/chb/arm/ARMCallOpcode.py b/chb/arm/ARMCallOpcode.py index a74340f6..04d9e7e2 100644 --- a/chb/arm/ARMCallOpcode.py +++ b/chb/arm/ARMCallOpcode.py @@ -68,7 +68,9 @@ class ARMCallOpcodeXData(ARMOpcodeXData): """ xdata format: a:x[2n]xr[n]dh, call (n arguments) ------------------------------------------------- - xprs[0..2n-1]: (arg location expr, arg value expr) * n + xprs_r[0..n-1]: arg values + xprs_r[n..2n-1]: register arg values + cxprs_r[0..n-1]: arg value (C representation) xprs[2n]: call target expression rdefs[0..n-1]: arg location reaching definitions uses[0]: lhs @@ -110,11 +112,58 @@ def arguments(self) -> List["XXpr"]: arguments.append(x) return arguments + @property + def c_arguments(self) -> List[Optional["XXpr"]]: + argcount = self.argument_count + c_args: List[Optional["XXpr"]] = [] + for i in range(argcount): + x = self._xdata.cxprs_r[i] + c_args.append(x) + return c_args + + @property + def cx_arguments(self) -> List["XXpr"]: + argcount = self.argument_count + result: List["XXpr"] = [] + for i in range(argcount): + x = self.c_arguments[i] + if x is None: + x = self.arguments[i] + result.append(x) + return result + @property def argumentxvars(self) -> List["XXpr"]: argcount = self.argument_count - return [x for x in self._xdata.xprs_r[argcount:2 * argcount] - if x is not None] + argvars: List["XXpr"] = [] + for i in range(argcount): + x = self._xdata.xprs_r[i + argcount] + if x is None: + raise UF.CHBError( + "Unexpected None-value call argument at index " + + str(i)) + argvars.append(x) + return argvars + + def argument(self, index: int) -> Tuple[Optional["XXpr"], Optional[str]]: + """Returns argument for (1-based) index.""" + + if index > self.argument_count: + msg = ( + "argument index " + str(index) + " exceeds argument count " + + str(self.argument_count)) + return (None, msg) + if index <= 0: + msg = ( + "argument index " + str(index) + " is invalid. A positive " + + "value is expected") + return (None, msg) + c_arg = self.c_arguments[index-1] + if c_arg is None: + x_arg = self.arguments[index-1] + return (x_arg, "fall-back to x-expression") + else: + return (c_arg, None) @property def calltarget(self) -> "CallTarget": @@ -124,7 +173,8 @@ def calltarget(self) -> "CallTarget": def annotation(self) -> str: tgt = str(self.calltarget) args = ", ".join(str(x) for x in self.arguments) - call = "call " + str(tgt) + "(" + args + ")" + cargs = " (C: (" + ", ".join(str(x) for x in self.c_arguments) + "))" + call = "call " + str(tgt) + "(" + args + ")" + cargs return self.add_instruction_condition(call) @@ -310,7 +360,7 @@ def ast_call_prov( if len(astargtypes) < argcount: astargtypes += ([None] * (argcount - len(astargtypes))) - xargs = xd.arguments + xargs = xd.cx_arguments xvarargs = xd.argumentxvars if len(rdefs) >= argcount: llrdefs = rdefs[:argcount] @@ -318,7 +368,7 @@ def ast_call_prov( # xv represents the location of the argument, which can be # either a register, or a stack location, where the stack # location is represented by an expression of the form - # (sp + n), with n is the offset from the current stackpointer + # (sp + n), where n is the offset from the current stackpointer # in bytes (note: not the stackpointer at function entry). # rdef represents the reaching definition for the argument # location. diff --git a/chb/arm/ARMOpcode.py b/chb/arm/ARMOpcode.py index de93cd1e..5e3b98ff 100644 --- a/chb/arm/ARMOpcode.py +++ b/chb/arm/ARMOpcode.py @@ -119,7 +119,7 @@ def is_ok(self) -> bool: return self.xdata.is_ok def var(self, index: int, name: str) -> "XVariable": - if index >= len(self.xdata.vars_r): + if not self.has_var(index): raise UF.CHBError( self.__class__.__name__ + ":" + name + " index out of bounds: " + str(index)) @@ -129,8 +129,31 @@ def var(self, index: int, name: str) -> "XVariable": self.__class__.__name__ + ":" + name + " has an error value") return v + def has_var(self, index: int) -> bool: + return self.xdata.has_var_r(index) + + def is_var_ok(self, index: int) -> bool: + return self.xdata.is_var_ok(index) + + def cvar(self, index: int, name: str) -> "XVariable": + if not self.has_cvar(index): + raise UF.CHBError( + self.__class__.__name__ + ":" + + name + " index out of bounds: " + str(index)) + cv = self.xdata.cvars_r[index] + if cv is None: + raise UF.CHBError( + self.__class__.__name__ + ":" + name + " has an error value") + return cv + + def has_cvar(self, index: int) -> bool: + return self.xdata.has_cxpr_r(index) + + def is_cvar_ok(self, index: int) -> bool: + return self.xdata.is_cvar_ok(index) + def xpr(self, index: int, name: str) -> "XXpr": - if index >= len(self.xdata.xprs_r): + if not self.has_xpr(index): raise UF.CHBError( self.__class__.__name__ + ":" + name + " index out of bounds: " + str(index)) @@ -140,6 +163,29 @@ def xpr(self, index: int, name: str) -> "XXpr": self.__class__.__name__ + ":" + name + " has an error value") return x + def has_xpr(self, index: int) -> bool: + return self.xdata.has_xpr_r(index) + + def is_xpr_ok(self, index: int) -> bool: + return self.xdata.is_xpr_ok(index) + + def cxpr(self, index: int, name: str) -> "XXpr": + if index >= len(self.xdata.cxprs_r): + raise UF.CHBError( + self.__class__.__name__ + ":" + + name + " cxpr index out of bounds: " + str(index)) + cx = self.xdata.cxprs_r[index] + if cx is None: + raise UF.CHBError( + self.__class__.__name__ + ":" + name + " has an error value") + return cx + + def has_cxpr(self, index: int) -> bool: + return self.xdata.has_cxpr_r(index) + + def is_cxpr_ok(self, index: int) -> bool: + return self.xdata.is_cxpr_ok(index) + def add_instruction_condition(self, s: str) -> str: if self.xdata.has_unknown_instruction_condition(): return "if ? then " + s @@ -167,11 +213,18 @@ def get_base_update_xpr(self) -> "XXpr": raise UF.CHBError( self.__class__.__name__ + " does not have writeback") + def get_base_update_cxpr(self) -> "XXpr": + if self.is_writeback: + return self.xdata.get_base_update_cxpr() + else: + raise UF.CHBError( + self.__class__.__name__ + " does not have writeback") + def writeback_update(self) -> str: if self.xdata.has_base_update(): vbu = self.get_base_update_var() - xbu = self.get_base_update_xpr() - return "; " + str(vbu) + " := " + str(xbu) + xbu = self.get_base_update_cxpr() + return "; wbu: " + str(vbu) + " := " + str(xbu) else: return "" diff --git a/chb/arm/opcodes/ARMAdd.py b/chb/arm/opcodes/ARMAdd.py index ede2a66d..396faffc 100644 --- a/chb/arm/opcodes/ARMAdd.py +++ b/chb/arm/opcodes/ARMAdd.py @@ -53,22 +53,34 @@ class ARMAddXData(ARMOpcodeXData): """Add ==> result - xdata format: a:vxxxxxxrrdh - ------------------------- - vars[0]: vrd (Rd) - xprs[0]: xrn (Rn) - xprs[1]: xrm (Rm) - xprs[2]: result: xrn + xrm - xprs[3]: rresult: xrn + xrm (rewritten) - xprs[4]: xxrn (xrn rewritten) - xprs[5]: xxrm (xrm rewritten) - xprs[6]: tcond (optional) - xprs[7]: fcond (optional) + Data format (regular) + - variables: + 0: vrd + + - expressions: + 0: xrn + 1: xrm + 2: result + 3: rresult (result, rewritten) + 4: xxrn (xrn, rewritten) + 5: xxrm (xrm, rewritten) + + - c expressions: + 0: cresult + rdefs[0]: xrn rdefs[1]: xrm rdefs[2:..]: reaching definitions for simplified result expression uses[0]: vrd useshigh[0]: vrd + + Data format (as part of jump table) + - expressions: + 0: xrn + 1: xxrn (xrn, rewritten) + + rdefs[0]: xrn + rdefs[1:]: reaching definitions for xxrn """ def __init__(self, xdata: InstrXData) -> None: @@ -91,27 +103,58 @@ def jt_xxrn(self) -> "XXpr": """Part of jumptable.""" return self.xpr(1, "xxrn") + @property + def is_jt_xxrn_ok(self) -> bool: + return self.is_xpr_ok(1) + @property def result(self) -> "XXpr": return self.xpr(2, "result") + @property + def is_result_ok(self) -> bool: + return self.is_xpr_ok(2) + @property def rresult(self) -> "XXpr": return self.xpr(3, "rresult") + @property + def is_rresult_ok(self) -> bool: + return self.is_xpr_ok(3) + + @property + def cresult(self) -> "XXpr": + return self.cxpr(0, "cresult") + + @property + def is_cresult_ok(self) -> bool: + return self.is_cxpr_ok(0) + @property def result_simplified(self) -> str: - return simplify_result( - self.xdata.args[3], self.xdata.args[4], self.result, self.rresult) + if self.is_result_ok and self.is_rresult_ok: + return simplify_result( + self.xdata.args[3], self.xdata.args[4], self.result, self.rresult) + else: + return str(self.xrn) + " + " + str(self.xrm) @property def xxrn(self) -> "XXpr": return self.xpr(4, "xxrn") + @property + def is_xxrn_ok(self) -> bool: + return self.is_xpr_ok(4) + @property def xxrm(self) -> "XXpr": return self.xpr(5, "xxrm") + @property + def is_xxrm_ok(self) -> bool: + return self.is_xpr_ok(5) + @property def rn_rdef(self) -> Optional["ReachingDefFact"]: return self._xdata.reachingdefs[0] @@ -123,7 +166,10 @@ def rm_rdef(self) -> Optional["ReachingDefFact"]: @property def annotation(self) -> str: if self.xdata.is_aggregate_jumptable: - return "jump-table: " + str(self.jt_xxrn) + if self.is_jt_xxrn_ok: + return "jump-table: " + str(self.jt_xxrn) + else: + return "jump-table: " + str(self.xrn) assignment = str(self.vrd) + " := " + self.result_simplified return self.add_instruction_condition(assignment) @@ -175,10 +221,7 @@ def mnemonic_extension(self) -> str: def annotation(self, xdata: InstrXData) -> str: xd = ARMAddXData(xdata) - if xd.is_ok: - return xd.annotation - else: - return "Error Value" + return xd.annotation # -------------------------------------------------------------------------- # AddWithCarry() @@ -243,169 +286,75 @@ def has_cast() -> bool: and astree.get_register_variable_intro(iaddr).has_cast()) xd = ARMAddXData(xdata) - if not xdata.is_ok: - chklogger.logger.error("Error value encountered at %s", iaddr) - return ([], []) + + if xd.is_cresult_ok and xd.is_rresult_ok: + rhs = xd.cresult + xrhs = xd.rresult + + elif xd.is_rresult_ok: + rhs = xd.rresult + xrhs = xd.rresult + + elif xd.is_result_ok: + rhs = xd.result + xrhs = xd.result + + else: + chklogger.logger.error( + "ADD: Encountered error value for rhs at address %s", iaddr) + return ([], [ll_assign]) lhs = xd.vrd rhs1 = xd.xrn rhs2 = xd.xrm - rhs3 = xd.rresult - rrhs1 = xd.xxrn - rrhs2 = xd.xxrm + rrhs1 = xd.xxrn if xd.is_xxrn_ok else xd.xrn + rrhs2 = xd.xxrm if xd.is_xxrm_ok else xd.xrm defuses = xdata.defuses defuseshigh = xdata.defuseshigh hl_lhs = XU.xvariable_to_ast_lval(lhs, xdata, iaddr, astree) - def hl_rhs_default () -> AST.ASTExpr: - return XU.xxpr_to_ast_def_expr(rhs3, xdata, iaddr, astree) - if str(lhs) == "PC": chklogger.logger.info( "Add (ADD) instruction at address %s sets PC", iaddr) hl_lhs_type = hl_lhs.ctype(astree.ctyper) - def pointer_arithmetic_expr() -> AST.ASTExpr: - hl_rhs1 = XU.xxpr_to_ast_def_expr(rrhs1, xdata, iaddr, astree) - hl_rhs2 = XU.xxpr_to_ast_def_expr(rrhs2, xdata, iaddr, astree) - hl_rhs1_type = hl_rhs1.ctype(astree.ctyper) - hl_rhs2_type = hl_rhs2.ctype(astree.ctyper) - - if hl_rhs1_type is None and hl_rhs2_type is None: - chklogger.logger.info( - "Unable to lift pointer arithmetic without type for " - + "%s at address %s", - str(rhs3), iaddr) - return hl_rhs_default() - - if hl_rhs2_type is not None and hl_rhs2_type.is_pointer: - rhs2tgttyp = cast(AST.ASTTypPtr, hl_rhs2_type).tgttyp - tgttypsize = astree.type_size_in_bytes(rhs2tgttyp) - if tgttypsize is None: - chklogger.logger.warning( - "Unable to lift pointer arithmetic without size for " - + "%s at address %s; set type size to 1", - str(hl_rhs2_type), iaddr) - tgttypsize = 1 - - if tgttypsize == 1: - return XU.xxpr_to_ast_def_expr(rhs3, xdata, iaddr, astree) - - if hl_rhs1.is_integer_constant: - addend = cast(AST.ASTIntegerConstant, hl_rhs1).cvalue - addend = addend // tgttypsize - astaddend: AST.ASTExpr = astree.mk_integer_constant(addend) - annotations.append("scaled by " + str(tgttypsize)) - return astree.mk_binary_op("plus", hl_rhs2, astaddend) - - scale = astree.mk_integer_constant(tgttypsize) - scaled = astree.mk_binary_op("div", hl_rhs1, scale) - return astree.mk_binary_op("plus", hl_rhs2, scaled) - - if hl_rhs1_type is not None and hl_rhs1_type.is_pointer: - rhs1tgttyp = cast(AST.ASTTypPtr, hl_rhs1_type).tgttyp - tgttypsize = astree.type_size_in_bytes(rhs1tgttyp) - if tgttypsize is None: - chklogger.logger.info( - "Unable to lift pointer arithmetic without size for " - + "%s at address %s", - str(hl_rhs1_type), iaddr) - return hl_rhs_default() - - if hl_rhs1.is_ast_startof: - arraylval = cast(AST.ASTStartOf, hl_rhs1).lval - arrayvinfo = cast(AST.ASTVariable, arraylval.lhost).varinfo - if tgttypsize == 1: - scaled = hl_rhs2 - else: - scale = astree.mk_integer_constant(tgttypsize) - scaled = astree.mk_binary_op("div", hl_rhs2, scale) - - offset = astree.mk_expr_index_offset(scaled) - offsetlval = astree.mk_vinfo_lval(arrayvinfo, offset) - return astree.mk_address_of(offsetlval) - - if tgttypsize == 1: - return XU.xxpr_to_ast_def_expr(rhs3, xdata, iaddr, astree) - - if hl_rhs2.is_integer_constant: - addend = cast(AST.ASTIntegerConstant, hl_rhs2).cvalue - addend = addend // tgttypsize - astaddend = astree.mk_integer_constant(addend) - annotations.append("scaled by " + str(tgttypsize)) - return astree.mk_binary_op("plus", hl_rhs1, astaddend) - - scale = astree.mk_integer_constant(tgttypsize) - scaled = astree.mk_binary_op("div", hl_rhs2, scale) - return astree.mk_binary_op("plus", hl_rhs1, scaled) - - if hl_rhs2_type is None: - chklogger.logger.info( - "Unable to lift pointer arithmetic without type for " - + "%s at address %s", - str(rhs2), iaddr) - return hl_rhs_default() - - chklogger.logger.info( - "Second operand pointer variable not yet supported for %s at " - + "address %s; rrhs1: %s; hl_rhs1: %s; hl_rhs2: %s; hl_rhs1_type: %s;" - + " hl_rhs2_type: %s", - str(rhs3), - iaddr, - str(rrhs1), - str(hl_rhs1), - str(hl_rhs2), - str(hl_rhs1_type), - str(hl_rhs2_type)) - return hl_rhs_default() - # resulting expression is a stack address if ( (str(rrhs1) == "SP" or rrhs1.is_stack_address) - and rhs3.is_stack_address): + and xrhs.is_stack_address): annotations.append("stack address") - rhs3 = cast("XprCompound", rhs3) - stackoffset = rhs3.stack_address_offset() + xrhs = cast("XprCompound", xrhs) + stackoffset = xrhs.stack_address_offset() rhslval = astree.mk_stack_variable_lval(stackoffset) hl_rhs: AST.ASTExpr = astree.mk_address_of(rhslval) # resulting expression is a pc-relative address elif str(rrhs1) == "PC" or str(rhs2) == "PC": annotations.append("PC-relative") - if rhs3.is_int_constant: - rhsexpr = XU.xxpr_to_ast_def_expr(rhs3, xdata, iaddr, astree) - rhsval = cast("XprConstant", rhs3).intvalue - if rhs3.is_string_reference: + if xrhs.is_int_constant: + rhsexpr = XU.xxpr_to_ast_def_expr(xrhs, xdata, iaddr, astree) + rhsval = cast("XprConstant", xrhs).intvalue + if xrhs.is_string_reference: saddr = hex(rhsval) - cstr = rhs3.constant.string_reference() + cstr = xrhs.constant.string_reference() hl_rhs = astree.mk_string_constant( rhsexpr, cstr, saddr) else: hl_rhs = astree.mk_global_address_constant( rhsval, rhsexpr) else: - hl_rhs = XU.xxpr_to_ast_def_expr(rhs3, xdata, iaddr, astree) + hl_rhs = XU.xxpr_to_ast_def_expr(rhs, xdata, iaddr, astree) - elif rhs3.is_addressof_var: - hl_rhs = XU.xxpr_to_ast_def_expr(rhs3, xdata, iaddr, astree) - if rhs3.is_constant_expression: + elif rhs.is_addressof_var: + hl_rhs = XU.xxpr_to_ast_def_expr(rhs, xdata, iaddr, astree) + if rhs.is_constant_expression: astree.set_ssa_value(str(hl_lhs), hl_rhs) - elif (hl_lhs_type is not None and hl_lhs_type.is_pointer and not has_cast()): - hl_rhs = pointer_arithmetic_expr() - if str(hl_rhs).startswith("astmem_tmp"): - chklogger.logger.error( - "Unable to compute pointer arithmetic expression for %s " - "at address %s", - str(rhs3), iaddr) - else: - if rhs3.is_constant_expression: - astree.set_ssa_value(str(hl_lhs), hl_rhs) else: - hl_rhs = hl_rhs_default () + hl_rhs = XU.xxpr_to_ast_def_expr(rhs, xdata, iaddr, astree) hl_assign = astree.mk_assign( hl_lhs, diff --git a/chb/arm/opcodes/ARMAdr.py b/chb/arm/opcodes/ARMAdr.py index 311d151f..489087d6 100644 --- a/chb/arm/opcodes/ARMAdr.py +++ b/chb/arm/opcodes/ARMAdr.py @@ -61,9 +61,18 @@ def vrd(self) -> "XVariable": def ximm(self) -> "XXpr": return self.xpr(0, "ximm") + @property + def caddr(self) -> "XXpr": + return self.cxpr(0, "caddr") + + @property + def is_caddr_ok(self) -> bool: + return self.is_cxpr_ok(0) + @property def annotation(self) -> str: - assignment = str(self.vrd) + " := " + str(self.ximm) + cx = " (C: " + (str(self.caddr) if self.is_caddr_ok else "None") + ")" + assignment = str(self.vrd) + " := " + str(self.ximm) + cx return self.add_instruction_condition(assignment) @@ -100,10 +109,7 @@ def opargs(self) -> List[ARMOperand]: def annotation(self, xdata: InstrXData) -> str: xd = ARMAdrXData(xdata) - if xd.is_ok: - return xd.annotation - else: - return "Error value" + return xd.annotation def ast_prov( self, @@ -130,13 +136,9 @@ def ast_prov( # high-level assignment xd = ARMAdrXData(xdata) - if not xd.is_ok: - chklogger.logger.error( - "Encountered error value at address %s", iaddr) - return ([], []) lhs = xd.vrd - rhs = xd.ximm + rhs = xd.caddr if xd.is_caddr_ok else xd.ximm defuses = xdata.defuses defuseshigh = xdata.defuseshigh diff --git a/chb/arm/opcodes/ARMArithmeticShiftRight.py b/chb/arm/opcodes/ARMArithmeticShiftRight.py index 70e5fbcb..1d606f55 100644 --- a/chb/arm/opcodes/ARMArithmeticShiftRight.py +++ b/chb/arm/opcodes/ARMArithmeticShiftRight.py @@ -49,6 +49,19 @@ class ARMArithmeticShiftRightXData(ARMOpcodeXData): + """Data format: + - variables: + 0: vrd + + - expressions: + 0: xrn + 1: xrm + 2: result + 3: rresult (result rewritten) + + - c expressions: + 0: cresult + """ def __init__(self, xdata: InstrXData) -> None: ARMOpcodeXData.__init__(self, xdata) @@ -69,18 +82,43 @@ def xrm(self) -> "XXpr": def result(self) -> "XXpr": return self.xpr(2, "result") + @property + def is_result_ok(self) -> bool: + return self.is_xpr_ok(2) + @property def rresult(self) -> "XXpr": return self.xpr(3, "rresult") + @property + def is_rresult_ok(self) -> bool: + return self.is_xpr_ok(3) + + @property + def cresult(self) -> "XXpr": + return self.cxpr(0, "cresult") + + @property + def is_cresult_ok(self) -> bool: + return self.is_cxpr_ok(0) + @property def result_simplified(self) -> str: - return simplify_result( - self.xdata.args[3], self.xdata.args[4], self.result, self.rresult) + if self.is_result_ok and self.is_rresult_ok: + return simplify_result( + self.xdata.args[3], self.xdata.args[4], self.result, self.rresult) + elif self.is_result_ok: + return str(self.result) + else: + return str(self.xrn) + " s>> " + str(self.xrm) @property def annotation(self) -> str: - assignment = str(self.vrd) + " := " + self.result_simplified + cresult = ( + " (C: " + + (str(self.cresult) if self.is_cresult_ok else "None") + + ")") + assignment = str(self.vrd) + " := " + self.result_simplified + cresult return self.add_instruction_condition(assignment) @@ -98,13 +136,8 @@ class ARMArithmeticShiftRight(ARMOpcode): args[3]: index of rm in armdictionary args[4]: is-wide (thumb) - xdata format: a:vxxxxrrdh - ------------------------- - vars[0]: lhs - xprs[0]: xrn - xprs[1]: xrm - xprs[2]: xrn >> xrm - xprs[3]: xrn >> xrm (simplified) + xdata format + ------------ rdefs[0]: xrm rdefs[1]: xrn rdefs[2..]: xrn >> xrm (simplified) @@ -136,10 +169,7 @@ def mnemonic_extension(self) -> str: def annotation(self, xdata: InstrXData) -> str: xd = ARMArithmeticShiftRightXData(xdata) - if xd.is_ok: - return xd.annotation - else: - return "Error value" + return xd.annotation def ast_prov( self, @@ -168,21 +198,30 @@ def ast_prov( # high-level assignment xd = ARMArithmeticShiftRightXData(xdata) - if not xd.is_ok: + + if xd.is_cresult_ok and xd.is_rresult_ok: + rhs = xd.cresult + + elif xd.is_rresult_ok: + rhs = xd.rresult + + elif xd.is_result_ok: + rhs = xd.result + + else: chklogger.logger.error( - "Encountered error value at address %s", iaddr) - return ([], []) + "ASR: Encountered error value for rhs at address %s", iaddr) + return ([], [ll_assign]) lhs = xd.vrd rhs1 = xd.xrn rhs2 = xd.xrm - rhs3 = xd.rresult rdefs = xdata.reachingdefs defuses = xdata.defuses defuseshigh = xdata.defuseshigh hl_lhs = XU.xvariable_to_ast_lval(lhs, xdata, iaddr, astree) - hl_rhs = XU.xxpr_to_ast_def_expr(rhs3, xdata, iaddr, astree) + hl_rhs = XU.xxpr_to_ast_def_expr(rhs, xdata, iaddr, astree) hl_assign = astree.mk_assign( hl_lhs, diff --git a/chb/arm/opcodes/ARMBitwiseAnd.py b/chb/arm/opcodes/ARMBitwiseAnd.py index 16b94378..7f07506c 100644 --- a/chb/arm/opcodes/ARMBitwiseAnd.py +++ b/chb/arm/opcodes/ARMBitwiseAnd.py @@ -50,6 +50,19 @@ class ARMBitwiseAndXData(ARMOpcodeXData): + """Data format: + - variables: + 0: vrd + + - expressions: + 0: xrn + 1: xrm + 2: result + 3: rresult (result rewritten) + + - c expressions: + 0: cresult + """ def __init__(self, xdata: InstrXData) -> None: ARMOpcodeXData.__init__(self, xdata) @@ -70,18 +83,41 @@ def xrm(self) -> "XXpr": def result(self) -> "XXpr": return self.xpr(2, "result") + @property + def is_result_ok(self) -> bool: + return self.is_xpr_ok(2) + @property def rresult(self) -> "XXpr": return self.xpr(3, "rresult") + @property + def is_rresult_ok(self) -> bool: + return self.is_xpr_ok(3) + + @property + def cresult(self) -> "XXpr": + return self.cxpr(0, "cresult") + + @property + def is_cresult_ok(self) -> bool: + return self.is_cxpr_ok(0) + @property def result_simplified(self) -> str: - return simplify_result( - self.xdata.args[3], self.xdata.args[4], self.result, self.rresult) + if self.is_result_ok and self.is_rresult_ok: + return simplify_result( + self.xdata.args[3], self.xdata.args[4], self.result, self.rresult) + else: + return str(self.xrn) + " & " + str(self.xrm) @property def annotation(self) -> str: - assignment = str(self.vrd) + " := " + self.result_simplified + cresult = ( + " (C: " + + (str(self.cresult) if self.is_cresult_ok else "None") + + ")") + assignment = str(self.vrd) + " := " + self.result_simplified + cresult return self.add_instruction_condition(assignment) @@ -99,13 +135,8 @@ class ARMBitwiseAnd(ARMOpcode): args[3]: index of rm in armdictionary args[4]: is-wide (thumb) - xdata format: a:vxxxxrrdh - ------------------------- - vars[0]: lhs - xprs[0]: xrn - xprs[1]: xrm - xprs[2]: xrn & xrm - xprs[3]: xrn & xrm (simplified) + xdata format: + ------------- rdefs[0]: xrm rdefs[1]: xrn rdefs[2..]: xrn & xrm (simplified) @@ -136,10 +167,7 @@ def mnemonic_extension(self) -> str: def annotation(self, xdata: InstrXData) -> str: xd = ARMBitwiseAndXData(xdata) - if xd.is_ok: - return xd.annotation - else: - return "Error value" + return xd.annotation def ast_prov( self, @@ -173,13 +201,22 @@ def ast_prov( # high-level assignment xd = ARMBitwiseAndXData(xdata) - if not xd.is_ok: + + if xd.is_cresult_ok and xd.is_rresult_ok: + rhs = xd.cresult + + elif xd.is_rresult_ok: + rhs = xd.rresult + + elif xd.is_result_ok: + rhs = xd.result + + else: chklogger.logger.error( - "Encountered error value at address %s", iaddr) - return ([], []) + "AND: Encountered error value for rhs at address %s", iaddr) + return ([], [ll_assign]) lhs = xd.vrd - rhs = xd.rresult defuses = xdata.defuses defuseshigh = xdata.defuseshigh diff --git a/chb/arm/opcodes/ARMBitwiseBitClear.py b/chb/arm/opcodes/ARMBitwiseBitClear.py index 027fd80a..c542b2b5 100644 --- a/chb/arm/opcodes/ARMBitwiseBitClear.py +++ b/chb/arm/opcodes/ARMBitwiseBitClear.py @@ -49,6 +49,19 @@ class ARMBitwiseBitClearXData(ARMOpcodeXData): + """Data format: + - variables: + 0: vrd + + - expressions: + 0: xrn + 1: xrm + 2: result + 3: rresult (result rewritten) + + - c expressions: + 0: cresult + """ def __init__(self, xdata: InstrXData) -> None: ARMOpcodeXData.__init__(self, xdata) @@ -57,26 +70,55 @@ def __init__(self, xdata: InstrXData) -> None: def vrd(self) -> "XVariable": return self.var(0, "vrd") + @property + def xrn(self) -> "XXpr": + return self.xpr(0, "xrn") + @property def xrm(self) -> "XXpr": - return self.xpr(0, "xrm") + return self.xpr(1, "xrm") @property def result(self) -> "XXpr": - return self.xpr(1, "result") + return self.xpr(2, "result") + + @property + def is_result_ok(self) -> bool: + return self.is_xpr_ok(2) @property def rresult(self) -> "XXpr": - return self.xpr(2, "rresult") + return self.xpr(3, "rresult") + + @property + def is_rresult_ok(self) -> bool: + return self.is_xpr_ok(3) + + @property + def cresult(self) -> "XXpr": + return self.cxpr(0, "cresult") + + @property + def is_cresult_ok(self) -> bool: + return self.is_cxpr_ok(0) @property def result_simplified(self) -> str: - return simplify_result( - self.xdata.args[3], self.xdata.args[4], self.result, self.rresult) + if self.is_result_ok and self.is_rresult_ok: + return simplify_result( + self.xdata.args[3], self.xdata.args[4], self.result, self.rresult) + elif self.is_result_ok: + return str(self.result) + else: + return str(self.xrn) + " & ~" + str(self.xrm) @property def annotation(self) -> str: - assignment = str(self.vrd) + " := " + self.result_simplified + cresult = ( + " (C: " + + (str(self.cresult) if self.is_cresult_ok else "None") + + ")") + assignment = str(self.vrd) + " := " + self.result_simplified + cresult return self.add_instruction_condition(assignment) @@ -93,13 +135,8 @@ class ARMBitwiseBitClear(ARMOpcode): args[3]: index of op3 in armdictionary args[4]: is-wide (thumb) - xdata format: a:vxxxxrr..dh - --------------------------- - vars[0]: lhs - xprs[0]: rhs1 - xprs[1]: rhs2 - xprs[2]: rhs1 & (not (rhs2)) - xprs[3]: rhs1 & (not (rhs2)) simplified + xdata format + ------------ rdefs[0]: rhs1 rdefs[1]: rhs2 rdefs[2:.]: result @@ -121,10 +158,7 @@ def opargs(self) -> List[ARMOperand]: def annotation(self, xdata: InstrXData) -> str: xd = ARMBitwiseBitClearXData(xdata) - if xd.is_ok: - return xd.annotation - else: - return "Error value" + return xd.annotation def ast_prov( self, @@ -159,13 +193,22 @@ def ast_prov( # high-level assignment xd = ARMBitwiseBitClearXData(xdata) - if not xd.is_ok: + + if xd.is_cresult_ok: + rhs = xd.cresult + + elif xd.is_rresult_ok: + rhs = xd.rresult + + elif xd.is_result_ok: + rhs = xd.result + + else: chklogger.logger.error( - "Encountered error value at address %s", iaddr) - return ([], []) + "BIC: Encountered error value for rhs at address %s", iaddr) + return ([], [ll_assign]) lhs = xd.vrd - rhs = xd.rresult defuses = xdata.defuses defuseshigh = xdata.defuseshigh diff --git a/chb/arm/opcodes/ARMBitwiseExclusiveOr.py b/chb/arm/opcodes/ARMBitwiseExclusiveOr.py index ef0a399e..c62d86e8 100644 --- a/chb/arm/opcodes/ARMBitwiseExclusiveOr.py +++ b/chb/arm/opcodes/ARMBitwiseExclusiveOr.py @@ -49,6 +49,19 @@ class ARMBitwiseExclusiveOrXData(ARMOpcodeXData): + """Data format: + - variables: + 0: vrd + + - expressions: + 0: xrn + 1: xrm + 2: result + 3: rresult (result, simplified) + + - c expressions: + 0: cresult + """ def __init__(self, xdata: InstrXData) -> None: ARMOpcodeXData.__init__(self, xdata) @@ -73,14 +86,31 @@ def result(self) -> "XXpr": def rresult(self) -> "XXpr": return self.xpr(3, "rresult") + @property + def is_rresult_ok(self) -> bool: + return self.is_xpr_ok(3) + + @property + def cresult(self) -> "XXpr": + return self.cxpr(0, "cresult") + + @property + def is_cresult_ok(self) -> bool: + return self.is_cxpr_ok(0) + @property def result_simplified(self) -> str: - return simplify_result( - self.xdata.args[3], self.xdata.args[4], self.result, self.rresult) + if self.is_rresult_ok: + return simplify_result( + self.xdata.args[3], self.xdata.args[4], self.result, self.rresult) + else: + return str(self.result) @property def annotation(self) -> str: - assignment = str(self.vrd) + " := " + self.result_simplified + cr = str(self.cresult) if self.is_cresult_ok else "" + cr = " (C: " + cr + ")" + assignment = str(self.vrd) + " := " + self.result_simplified + cr return self.add_instruction_condition(assignment) @@ -98,13 +128,8 @@ class ARMBitwiseExclusiveOr(ARMOpcode): args[3]: index of op3 in armdictionary args[4]: is-wide (thumb) - xdata format: a:vxxxxrr..dh - --------------------------- - vars[0]: lhs - xprs[0]: rhs1 - xprs[1]: rhs2 - xprs[2]: (rhs1 xor rhs2) - xprs[3]: (rhs1 xor rhs2) + xdata format: + ------------- rdefs[0]: rhs1 rdefs[1]: rhs2 rdefs[2:.]: result @@ -131,10 +156,7 @@ def opargs(self) -> List[ARMOperand]: def annotation(self, xdata: InstrXData) -> str: xd = ARMBitwiseExclusiveOrXData(xdata) - if xd.is_ok: - return xd.annotation - else: - return "Error value" + return xd.annotation def ast_prov( self, @@ -166,13 +188,15 @@ def ast_prov( # high-level assignment xd = ARMBitwiseExclusiveOrXData(xdata) - if not xd.is_ok: - chklogger.logger.error( - "Encountered error value at address %s", iaddr) - return ([], []) + + if xd.is_cresult_ok: + rhs = xd.cresult + elif xd.is_rresult_ok: + rhs = xd.rresult + else: + rhs = xd.result lhs = xd.vrd - rhs = xd.rresult defuses = xdata.defuses defuseshigh = xdata.defuseshigh diff --git a/chb/arm/opcodes/ARMBitwiseOr.py b/chb/arm/opcodes/ARMBitwiseOr.py index d493a08e..d95a1a84 100644 --- a/chb/arm/opcodes/ARMBitwiseOr.py +++ b/chb/arm/opcodes/ARMBitwiseOr.py @@ -49,6 +49,19 @@ class ARMBitwiseOrXData(ARMOpcodeXData): + """Data format: + - variables: + 0: vrd + + - expressions: + 0: xrn + 1: xrm + 2: result + 3: rresult (result rewritten) + + - c expressions: + 0: cresult + """ def __init__(self, xdata: InstrXData) -> None: ARMOpcodeXData.__init__(self, xdata) @@ -69,18 +82,41 @@ def xrm(self) -> "XXpr": def result(self) -> "XXpr": return self.xpr(2, "result") + @property + def is_result_ok(self) -> bool: + return self.is_xpr_ok(2) + @property def rresult(self) -> "XXpr": return self.xpr(3, "rresult") + @property + def is_rresult_ok(self) -> bool: + return self.is_xpr_ok(3) + + @property + def cresult(self) -> "XXpr": + return self.cxpr(0, "cresult") + + @property + def is_cresult_ok(self) -> bool: + return self.is_cxpr_ok(0) + @property def result_simplified(self) -> str: - return simplify_result( - self.xdata.args[3], self.xdata.args[4], self.result, self.rresult) + if self.is_result_ok and self.is_rresult_ok: + return simplify_result( + self.xdata.args[3], self.xdata.args[4], self.result, self.rresult) + else: + return str(self.xrn) + " | " + str(self.xrm) @property def annotation(self) -> str: - assignment = str(self.vrd) + " := " + self.result_simplified + cresult = ( + " (C: " + + (str(self.cresult) if self.is_cresult_ok else "None") + + ")") + assignment = str(self.vrd) + " := " + self.result_simplified + cresult return self.add_instruction_condition(assignment) @@ -98,13 +134,8 @@ class ARMBitwiseOr(ARMOpcode): args[3]: index of op3 in armdictionary args[4]: is-wide (thumb) - xdata format: a:vxxxxrrdh - ------------------------- - vars[0]: lhs - xprs[0]: xrn - xprs[1]: xrm - xprs[2]: xrn & xrm - xprs[3]: xrn & xrm (simplified) + xdata format: + ------------- rdefs[0]: xrm rdefs[1]: xrn rdefs[2..]: xrn & xrm (simplified) @@ -136,10 +167,7 @@ def opargs(self) -> List[ARMOperand]: def annotation(self, xdata: InstrXData) -> str: xd = ARMBitwiseOrXData(xdata) - if xd.is_ok: - return xd.annotation - else: - return "Error value" + return xd.annotation def ast_prov( self, @@ -173,18 +201,27 @@ def ast_prov( # high-level assignment xd = ARMBitwiseOrXData(xdata) - if not xd.is_ok: + + if xd.is_cresult_ok: + rhs = xd.cresult + + elif xd.is_rresult_ok: + rhs = xd.rresult + + elif xd.is_result_ok: + rhs = xd.result + + else: chklogger.logger.error( - "Encountered error value at address %s", iaddr) - return ([], []) + "ORR: Encountered error value for rhs at address %s", iaddr) + return ([], [ll_assign]) lhs = xd.vrd - rhs3 = xd.rresult defuses = xdata.defuses defuseshigh = xdata.defuseshigh hl_lhs = XU.xvariable_to_ast_lval(lhs, xdata, iaddr, astree) - hl_rhs = XU.xxpr_to_ast_def_expr(rhs3, xdata, iaddr, astree) + hl_rhs = XU.xxpr_to_ast_def_expr(rhs, xdata, iaddr, astree) hl_assign = astree.mk_assign( hl_lhs, diff --git a/chb/arm/opcodes/ARMBranch.py b/chb/arm/opcodes/ARMBranch.py index e49fba46..27fe8821 100644 --- a/chb/arm/opcodes/ARMBranch.py +++ b/chb/arm/opcodes/ARMBranch.py @@ -61,13 +61,39 @@ class ARMBranchXData(ARMOpcodeXData): + """Data format (conditional) + - expressions + 0: txpr (true expression) + 1: fxpr (false expression) + 2: tcond (txpr, rewritten) + 3: fcond (fxpr, rewritten) + 4: xtgt (if absolute target address) + + - c expressions + 0: ctcond + 1: cfcond + + Data format (unconditional, or missing branch conditions) + - expressions + 0: xtgt + 1: xxtgt (rewritten) + """ def __init__(self, xdata: InstrXData) -> None: ARMOpcodeXData.__init__(self, xdata) + @property + def is_conditional(self) -> bool: + return ( + self._xdata.has_branch_conditions() + or self._xdata.has_missing_branch_conditions()) + @property def is_unconditional(self) -> bool: - return len(self._xdata.xprs_r) == 2 + return not self.is_conditional + + def has_branch_conditions(self) -> bool: + return self._xdata.has_branch_conditions() @property def txpr(self) -> "XXpr": @@ -81,38 +107,66 @@ def fxpr(self) -> "XXpr": def tcond(self) -> "XXpr": return self.xpr(2, "tcond") + @property + def is_tcond_ok(self) -> bool: + return self.is_xpr_ok(2) + @property def fcond(self) -> "XXpr": return self.xpr(3, "fcond") + @property + def is_fcond_ok(self) -> bool: + return self.is_xpr_ok(3) + + @property + def ctcond(self) -> "XXpr": + return self.cxpr(0, "ctcond") + + @property + def is_ctcond_ok(self) -> bool: + return self.is_cxpr_ok(0) + + @property + def cfcond(self) -> "XXpr": + return self.cxpr(1, "cfcond") + + @property + def is_cfcond_ok(self) -> bool: + return self.is_cxpr_ok(1) + @property def xtgt(self) -> "XXpr": - index = 1 if self.is_unconditional else 4 - return self.xpr(index, "xtgt") + if self.is_unconditional or (not self.has_branch_conditions()): + return self.xpr(1, "xtgt") + else: + return self.xpr(4, "xtgt") @property - def is_xtgt_known(self) -> bool: - index = 1 if self.is_unconditional else 4 - return self.xdata.xprs_r[index] is not None + def is_xtgt_ok(self) -> bool: + if self.is_unconditional or (not self.has_branch_conditions()): + return self.is_xpr_ok(1) + else: + return self.is_xpr_ok(4) @property def annotation(self) -> str: - if self.is_ok: - if self._xdata.has_branch_conditions(): - return "if " + str(self.tcond) + " then goto " + str(self.xtgt) - elif self.is_unconditional: - return "goto " + str(self.xtgt) + if self.is_conditional: + if self.has_branch_conditions(): + if self.is_ctcond_ok: + cond = str(self.ctcond) + elif self.is_tcond_ok: + cond = str(self.tcond) + else: + cond = str(self.txpr) + return "if " + cond + " then goto " + str(self.xtgt) else: - return "?" - elif self.is_xtgt_known: - if self._xdata.has_branch_conditions(): - return "if " + str(self.txpr) + " then goto " + str(self.xtgt) - elif self.is_unconditional: - return "goto " + str(self.xtgt) - else: - return "?" + return ( + "if ? then goto " + + str(self.xtgt) + + " (no branch conditions found") else: - return "Error value" + return "goto " + str(self.xtgt) @armregistry.register_tag("B", ARMOpcode) @@ -125,20 +179,7 @@ class ARMBranch(ARMCallOpcode): tags[1]: args[0]: index of target operand in armdictionary args[1]: is-wide (thumb) - - xdata format: a:xxxxxr.. - ------------------------ - xprs[0]: true condition - xprs[1]: false condition - xprs[2]: true condition (simplified) - xprs[3]: false condition (simplified) - xprs[4]: target address (absolute) - - or, if no conditions - - xdata format: a:x - xprs[0]: target address (absolute) - """ + """ def __init__(self, d: "ARMDictionary", ixval: IndexedTableValue) -> None: ARMCallOpcode.__init__(self, d, ixval) @@ -157,12 +198,6 @@ def mnemonic_extension(self) -> str: def opargs(self) -> List[ARMOperand]: return [self.armd.arm_operand(self.args[0])] - def ft_conditions_basic(self, xdata: InstrXData) -> Sequence[XXpr]: - if xdata.has_branch_conditions(): - return [xdata.xprs[1], xdata.xprs[0]] - else: - return [] - def ft_conditions(self, xdata: InstrXData) -> Sequence[XXpr]: xd = ARMBranchXData(xdata) if xdata.has_branch_conditions(): @@ -289,11 +324,28 @@ def default(condition: XXpr) -> AST.ASTExpr: ll_astcond = self.ast_cc_expr(astree) - if len(ftconds_basic) == 2: - if reverse: - condition = ftconds_basic[0] + if xd.is_conditional: + if xd.has_branch_conditions(): + if reverse: + if xd.is_cfcond_ok: + condition = xd.cfcond + elif xd.is_fcond_ok: + condition = xd.fcond + else: + condition = xd.fxpr + else: + if xd.is_ctcond_ok: + condition = xd.ctcond + elif xd.is_tcond_ok: + condition = xd.tcond + else: + condition = xd.txpr else: - condition = ftconds_basic[1] + chklogger.logger.error( + "Bcc: conditional branch without branch conditions " + + "at address %s", iaddr) + hl_astcond = astree.mk_temp_lval_expression() + return (hl_astcond, ll_astcond) csetter = xdata.tags[2] hl_astcond = XU.xxpr_to_ast_def_expr( diff --git a/chb/arm/opcodes/ARMBranchExchange.py b/chb/arm/opcodes/ARMBranchExchange.py index 5149ede4..d45ab975 100644 --- a/chb/arm/opcodes/ARMBranchExchange.py +++ b/chb/arm/opcodes/ARMBranchExchange.py @@ -75,12 +75,24 @@ def returnval(self) -> "XXpr": def rreturnval(self) -> "XXpr": return self.xdata.get_return_xxpr() + def has_creturnval(self) -> bool: + return self.xdata.has_return_cxpr() + + def creturnval(self) -> "XXpr": + return self.xdata.get_return_cxpr() + @property def annotation(self) -> str: if self.xdata.is_bx_call: return "bx-call" if self.has_return_xpr(): - return "return " + str(self.rreturnval()) + cx = (" (C: " + + (str(self.creturnval()) if self.has_creturnval() else "None") + + ")") + if self.is_ok: + return "return " + str(self.rreturnval()) + cx + else: + return "Error value" else: return "Not supported yet" @@ -116,17 +128,21 @@ def is_return_instruction(self, xdata: InstrXData) -> bool: def return_value(self, xdata: InstrXData) -> Optional[XXpr]: xd = ARMBranchExchangeXData(xdata) - if xd.has_return_xpr(): - return xd.rreturnval() + if xd.has_creturnval(): + if xd.is_ok: + return xd.creturnval() + else: + chklogger.logger.warning( + "Return value is an error value") + return None else: return None def is_call(self, xdata: InstrXData) -> bool: - return len(xdata.tags) >= 2 and xdata.tags[1] == "call" + return xdata.has_call_target() def is_call_instruction(self, xdata: InstrXData) -> bool: - # return xdata.has_call_target() - return False + return xdata.has_call_target() def call_target(self, xdata: InstrXData) -> "CallTarget": if self.is_call_instruction(xdata): @@ -145,26 +161,9 @@ def argument_count(self, xdata: InstrXData) -> int: else: raise UF.CHBError("Instruction is not a call: " + str(self)) - def arguments(self, xdata: InstrXData) -> Sequence[XXpr]: - return xdata.xprs[:self.argument_count(xdata)] - def annotation(self, xdata: InstrXData) -> str: - """xdata format: a:x . - - xprs[0]: target operand - """ - if self.is_call_instruction(xdata): - tgt = xdata.call_target(self.ixd) - args = ", ".join(str(x) for x in self.arguments(xdata)) - return "call " + str(tgt) + "(" + args + ")" - xd = ARMBranchExchangeXData(xdata) - if xd.has_return_xpr and xd.is_ok: - return xd.annotation - elif xd.is_ok: - return "goto " + str(xd.xxtgt) - else: - return "Error value" + return xd.annotation def assembly_ast( self, diff --git a/chb/arm/opcodes/ARMCompare.py b/chb/arm/opcodes/ARMCompare.py index 291cb8e1..7f02d536 100644 --- a/chb/arm/opcodes/ARMCompare.py +++ b/chb/arm/opcodes/ARMCompare.py @@ -49,12 +49,17 @@ class ARMCompareXData(ARMOpcodeXData): - """ - xdata format: a:xxxrr - --------------------- - xprs[0]: xrn - xprs[1]: xrm - xprs[2]: xrn - xrm (simplified) + """Data format: + --------------- + - expressions: + 0: xrn + 1: xrm: + 2: xresult (xrn - xrm) + 3: result (xresult rewritten) + + - c expressions: + 0: cresult + rdefs[0]: rn rdefs[1]: rm rdefs[2..]: xrn - xrm (simplified) @@ -71,15 +76,32 @@ def xrn(self) -> "XXpr": def xrm(self) -> "XXpr": return self.xpr(1, "xrm") + @property + def xresult(self) -> "XXpr": + return self.xpr(2, "xresult") + @property def result(self) -> "XXpr": - return self.xpr(2, "result") + return self.xpr(3, "result") + + @property + def is_result_ok(self) -> bool: + return self.is_xpr_ok(3) + + @property + def cresult(self) -> "XXpr": + return self.cxpr(0, "cresult") + + @property + def is_cresult_ok(self) -> bool: + return self.is_cxpr_ok(0) @property def annotation(self) -> str: + cx = " (C: " + (str(self.cresult) if self.is_cresult_ok else "None") + ")" ann = "compare " + str(self.xrn) + " and " + str(self.xrm) if self.is_ok: - ann += " (" + str(self.result) + ")" + ann += " (" + str(self.result) + ")" + cx return self.add_instruction_condition(ann) @@ -149,15 +171,15 @@ def ast_prov( rdefs = xdata.reachingdefs xd = ARMCompareXData(xdata) - if xd.is_ok: + + if xd.is_cresult_ok: + rhs = xd.cresult + elif xd.is_result_ok: rhs = xd.result - hl_rhs = XU.xxpr_to_ast_def_expr(rhs, xdata, iaddr, astree) else: - rhs1 = xd.xrn - rhs2 = xd.xrm - hl_rhs1 = XU.xxpr_to_ast_def_expr(rhs1, xdata, iaddr, astree) - hl_rhs2 = XU.xxpr_to_ast_def_expr(rhs2, xdata, iaddr, astree) - hl_rhs = astree.mk_binary_op("minus", hl_rhs1, hl_rhs2) + rhs = xd.xresult + + hl_rhs = XU.xxpr_to_ast_def_expr(rhs, xdata, iaddr, astree) hl_assign = astree.mk_assign( astree.ignoredlhs, diff --git a/chb/arm/opcodes/ARMLoadMultipleIncrementAfter.py b/chb/arm/opcodes/ARMLoadMultipleIncrementAfter.py index 2ccaaca7..5300c7f5 100644 --- a/chb/arm/opcodes/ARMLoadMultipleIncrementAfter.py +++ b/chb/arm/opcodes/ARMLoadMultipleIncrementAfter.py @@ -25,7 +25,7 @@ # SOFTWARE. # ------------------------------------------------------------------------------ -from typing import List, Tuple, TYPE_CHECKING +from typing import Iterable, List, Tuple, TYPE_CHECKING from chb.app.InstrXData import InstrXData @@ -49,6 +49,20 @@ class ARMLoadMultipleIncrementAfterXData(ARMOpcodeXData): + """Data format: + - variables: + 0: baselhs + 1..n: lhsvars + + - expressions: + 0: baserhs + 1..n: memrhss + n+1..2n: rmemrhss (memrhss, rewritten) + 2n+1..3n: xaddrs + + - c expressions: + 0..n-1: cmemrhss + """ def __init__(self, xdata: InstrXData) -> None: ARMOpcodeXData.__init__(self, xdata) @@ -57,6 +71,23 @@ def __init__(self, xdata: InstrXData) -> None: def regcount(self) -> int: return len(self.xdata.vars_r) - 1 + def has_index(self, index: int) -> bool: + """returns true if index is between 1 and regcount (inclusive).""" + + return index > 0 and index <= self.regcount + + @property + def memrhs_range(self) -> Iterable[int]: + return range(1, self.regcount + 1) + + @property + def rmemrhs_range(self) -> Iterable[int]: + return range(self.regcount + 1, (2 * self.regcount) + 1) + + @property + def xaddr_range(self) -> Iterable[int]: + return range((2 * self.regcount) + 1, (3 * self.regcount) + 1) + @property def baselhs(self) -> "XVariable": return self.var(0, "baselhs") @@ -65,23 +96,106 @@ def baselhs(self) -> "XVariable": def lhsvars(self) -> List["XVariable"]: return [self.var(i, "lhsvar") for i in range(1, self.regcount + 1)] + def lhsvar(self, index: int) -> "XVariable": + """returns the lhsvar at (1-based) position index""" + + if self.has_index(index): + return self.lhsvars[index] + else: + raise UF.CHBError("LDM: index out of bounds: " + str(index)) + @property def baserhs(self) -> "XXpr": return self.xpr(0, "baserhs") @property - def rhsexprs(self) -> List["XXpr"]: - return [self.xpr(i, "rhsexpr") for i in range(1, self.regcount + 1)] + def memrhss(self) -> List["XXpr"]: + return [self.xpr(i, "memrhs") for i in self.memrhs_range] + + @property + def are_memrhss_ok(self) -> bool: + return all(self.is_xpr_ok(i) for i in self.memrhs_range) + + def memrhs(self, index) -> "XXpr": + """returns the rhs expression at (1-based) position index""" + + if self.has_index(index): + if self.are_memrhss_ok: + return self.memrhss[index - 1] + else: + raise UF.CHBError("LDM: memrhss have error values") + else: + raise UF.CHBError("LDM: index out of bounds for memrhs") + + @property + def rmemrhss(self) -> List["XXpr"]: + return [self.xpr(i, "rmemrhs") for i in self.rmemrhs_range] + + @property + def are_rmemrhss_ok(self) -> bool: + return all(self.is_xpr_ok(i) for i in self.rmemrhs_range) + + def rmemrhs(self, index) -> "XXpr": + """returns the rewritten rhs expr at (1-based) position index""" + + if self.has_index(index): + if self.are_rmemrhss_ok: + return self.rmemrhss[index - 1] + else: + raise UF.CHBError("LDM: rmemrhss have error values") + else: + raise UF.CHBError("LDM: index out of bounds for rmemrhs") @property def xaddrs(self) -> List["XXpr"]: - return [self.xpr(i, "xaddr") - for i in range(self.regcount + 1, (2 * self.regcount) + 3)] + return [self.xpr(i, "xaddr") for i in self.xaddr_range] + + @property + def are_xaddrs_ok(self) -> bool: + return all(self.is_xpr_ok(i) for i in self.xaddr_range) + + def xaddr(self, index) -> "XXpr": + """returns the rhs addr at (1-based) position index""" + + if self.has_index(index): + if self.are_xaddrs_ok: + return self.xaddrs[index - 1] + else: + raise UF.CHBError("LDM: xaddrs have error values") + else: + raise UF.CHBError("LDM: index out of bounds for xaddr") + + @property + def cmemrhss(self) -> List["XXpr"]: + return [self.cxpr(i, "cmemrhs") for i in range(0, self.regcount)] + + @property + def are_cmemrhss_ok(self) -> bool: + return all(self.is_cxpr_ok(i) for i in range(0, self.regcount)) + + def cmemrhs(self, index) -> "XXpr": + """returns the rhs addr at (1-based) position index""" + + if self.has_index(index): + if self.are_cmemrhss_ok: + return self.cmemrhss[index - 1] + else: + raise UF.CHBError("LDM: cmemrhss have error values") + else: + raise UF.CHBError("LDM: index out of bounds cmemrhs") @property def annotation(self) -> str: - pairs = zip(self.lhsvars, self.rhsexprs) - assigns = "; ".join(str(v) + " := " + str(x) for (x, v) in pairs) + if self.are_rmemrhss_ok: + pairs = list(zip(self.lhsvars, self.rmemrhss)) + elif self.are_memrhss_ok: + pairs = list(zip(self.lhsvars, self.memrhss)) + else: + pairs = [] + if len(pairs) > 0: + assigns = "; ".join(str(v) + " := " + str(x) for (x, v) in pairs) + else: + assigns = "unknown rhs memory" wbu = self.writeback_update() return self.add_instruction_condition(assigns + wbu) @@ -98,14 +212,8 @@ class ARMLoadMultipleIncrementAfter(ARMOpcode): args[2]: index of registers in arm dictionary args[3]: index of base memory address - xdata format: vv[n]xxxx[n]rr[n]dd[n]hh[n] - ---------------------------------------- - vars[0]: base lhs - vars[1..n]: register lhss - xprs[0]: base rhs - xprs[1]: updated base (may be unchanged in case of no writeback) - xprs[2]: updated base (simplified) - xprs[3..n+2]: values of memory locations read + xdata format: + ------------- rdefs[0]: reaching definition base register rdefs[1..n]: reaching definition memory locations uses[0]: base lhs @@ -143,10 +251,7 @@ def is_load_instruction(self, xdata: InstrXData) -> bool: def annotation(self, xdata: InstrXData) -> str: xd = ARMLoadMultipleIncrementAfterXData(xdata) - if xd.is_ok: - return xd.annotation - else: - return "Error value" + return xd.annotation # ------------------------------------------------------------------------- # address = R[n]; @@ -168,15 +273,22 @@ def ast_prov( List[AST.ASTInstruction], List[AST.ASTInstruction]]: xd = ARMLoadMultipleIncrementAfterXData(xdata) - if not xd.is_ok: + + if xd.are_cmemrhss_ok: + rhsexprs = xd.cmemrhss + elif xd.are_rmemrhss_ok: + rhsexprs = xd.rmemrhss + elif xd.are_memrhss_ok: + rhsexprs = xd.memrhss + + else: chklogger.logger.error( - "Error value encountered at address %s", iaddr) + "LDM: Error value encountered at address %s", iaddr) return ([], []) baselhs = xd.baselhs lhsvars = xd.lhsvars baserhs = xd.baserhs - rhsexprs = xd.rhsexprs baserdef = xdata.reachingdefs[0] memrdefs = xdata.reachingdefs[1:] diff --git a/chb/arm/opcodes/ARMLoadRegister.py b/chb/arm/opcodes/ARMLoadRegister.py index 5f91a5d3..187160d4 100644 --- a/chb/arm/opcodes/ARMLoadRegister.py +++ b/chb/arm/opcodes/ARMLoadRegister.py @@ -53,6 +53,21 @@ class ARMLoadRegisterXData(ARMOpcodeXData): + """Data format: + - variables: + 0: vrt (lhs) + + - expressions: + 0: xrn + 1: xrm + 2: xmem (rhs) + 3: xrmem (rhs, rewritten) + 4: xaddr (address of rhs) + + - c expressions: + 0: cxrmem (rhs) + 1: cxaddr (address of rhs) + """ def __init__(self, xdata: InstrXData) -> None: ARMOpcodeXData.__init__(self, xdata) @@ -61,10 +76,6 @@ def __init__(self, xdata: InstrXData) -> None: def vrt(self) -> "XVariable": return self.var(0, "vrt") - @property - def vmem(self) -> "XVariable": - return self.var(1, "vmem") - @property def xrn(self) -> "XXpr": return self.xpr(0, "xrn") @@ -77,29 +88,68 @@ def xrm(self) -> "XXpr": def xmem(self) -> "XXpr": return self.xpr(2, "xmem") + @property + def is_xmem_ok(self) -> bool: + return self.is_xpr_ok(2) + @property def xrmem(self) -> "XXpr": return self.xpr(3, "xrmem") + @property + def is_xrmem_ok(self) -> bool: + return self.is_xpr_ok(3) + + @property + def cxrmem(self) -> "XXpr": + return self.cxpr(0, "cxrmem") + + @property + def is_cxrmem_ok(self) -> bool: + return self.is_cxpr_ok(0) + @property def xaddr(self) -> "XXpr": return self.xpr(4, "xaddr") @property - def is_xrmem_unknown(self) -> bool: - return self.xdata.xprs_r[3] is None + def is_xaddr_ok(self) -> bool: + return self.is_xpr_ok(4) + + @property + def xxaddr(self) -> "XXpr": + return self.xpr(5, "xxaddr") + + @property + def is_xxaddr_ok(self) -> bool: + return self.is_xpr_ok(5) @property - def is_address_known(self) -> bool: - return self.xdata.xprs_r[4] is not None + def cxaddr(self) -> "XXpr": + return self.cxpr(1, "cxaddr") + + @property + def is_cxaddr_ok(self) -> bool: + return self.is_cxpr_ok(1) @property def annotation(self) -> str: wbu = self.writeback_update() - if self.is_ok: - assignment = str(self.vrt) + " := " + str(self.xrmem) - elif self.is_xrmem_unknown and self.is_address_known: - assignment = str(self.vrt) + " := *(" + str(self.xaddr) + ")" + if self.is_cxrmem_ok: + crhs = str(self.cxrmem) + elif self.is_cxaddr_ok: + crhs = "*(" + str(self.cxaddr) + ")" + else: + crhs = "None" + cx = " (C: " + crhs + ")" + addr = str(self.xxaddr if self.is_xxaddr_ok else self.xaddr) + caddr = str(self.cxaddr if self.is_cxaddr_ok else "None") + caddr = " (addr: " + addr + "; C: " + caddr + ")" + if self.is_ok or self.is_xrmem_ok: + assignment = str(self.vrt) + " := " + str(self.xrmem) + cx + caddr + elif self.is_xaddr_ok: + assignment = ( + str(self.vrt) + " := *(" + str(self.xaddr) + ")" + cx + caddr) else: assignment = "Error value" return self.add_instruction_condition(assignment) + wbu @@ -120,28 +170,12 @@ class ARMLoadRegister(ARMOpcode): xdata format: ------------- - vars[0]: lhs - vars[1]: memory location expressed as a variable - xprs[0]: value in rn - xprs[1]: value in rm - xprs[2]: value in memory location - xprs[3]: value in memory location (simplified) - xprs[4]: address of memory location rdefs[0]: reaching definitions rn rdefs[1]: reaching definitions rm rdefs[2]: reaching definitions memory location rdefs[3..]: reaching definitions for memory value uses[0]: use of lhs useshigh[0]: use of lhs at high level - - optional: - vars[2]: lhs base register (if base update), add "bu" to tags - - xprs[.]: instruction condition (if has condition) - xprs[.]: new address for base register - - uses[1]: use of updated base register - useshigh[1]: use of updated base register """ def __init__(self, d: "ARMDictionary", ixval: IndexedTableValue) -> None: @@ -162,13 +196,20 @@ def opargs(self) -> List[ARMOperand]: return [self.armd.arm_operand(self.args[i]) for i in [0, 1, 2, 3]] def lhs(self, xdata: InstrXData) -> List[XVariable]: - return [xdata.vars[0]] + xd = ARMLoadRegisterXData(xdata) + return [xd.vrt] def is_load_instruction(self, xdata: InstrXData) -> bool: return True def rhs(self, xdata: InstrXData) -> List[XXpr]: - return [xdata.xprs[1]] + xd = ARMLoadRegisterXData(xdata) + if xd.is_xrmem_ok: + return [xd.xrmem] + elif xd.is_xmem_ok: + return [xd.xmem] + else: + return [] def annotation(self, xdata: InstrXData) -> str: """lhs, rhs, with optional instr condition and base update.""" @@ -185,9 +226,7 @@ def ast_prov( xd = ARMLoadRegisterXData(xdata) - memaddr = xd.xaddr - - annotations: List[str] = [iaddr, "LDR", "addr: " + str(memaddr)] + annotations: List[str] = [iaddr, "LDR"] # low-level assignment @@ -213,24 +252,34 @@ def has_cast() -> bool: lhs = xd.vrt if xd.is_ok: - rhs = xd.xrmem - rhsval = None if has_cast() else xd.xrmem - xaddr = xd.xaddr - hl_lhs = XU.xvariable_to_ast_lval(lhs, xdata, iaddr, astree, rhs=rhsval) - hl_rhs = XU.xxpr_to_ast_def_expr( - rhs, xdata, iaddr, astree, memaddr=xaddr) + rhs = xd.cxrmem + rhsval = None if has_cast() else xd.cxrmem + hl_lhs = XU.xvariable_to_ast_lval( + lhs, xdata, iaddr, astree, rhs=rhsval) + hl_rhs = XU.xxpr_to_ast_def_expr(rhs, xdata, iaddr, astree) + + elif xd.is_cxaddr_ok: + cxaddr = xd.cxaddr + hl_lhs = XU.xvariable_to_ast_lval(lhs, xdata, iaddr, astree) + hl_rhs = XU.xmemory_dereference_lval_expr( + cxaddr, xdata, iaddr, astree) - elif xd.is_xrmem_unknown and xd.is_address_known: + elif xd.is_xaddr_ok: xaddr = xd.xaddr hl_lhs = XU.xvariable_to_ast_lval(lhs, xdata, iaddr, astree) hl_rhs = XU.xmemory_dereference_lval_expr( xaddr, xdata, iaddr, astree) + chklogger.logger.warning( + "LDR: Unable to use a C expression for rhs. Fall back to " + + "native byte-based address: %s to form rhs %s at address %s", + str(xaddr), str(hl_rhs), iaddr) + else: chklogger.logger.error( "LDR: both memory value and address values are error values " + "at address %s: ", iaddr) - return ([], []) + return ([], (ll_pre + [ll_assign] + ll_post)) rdefs = xdata.reachingdefs defuses = xdata.defuses @@ -273,43 +322,9 @@ def has_cast() -> bool: ll_assigns: List[AST.ASTInstruction] = [ll_assign, ll_addr_assign] basereg = xd.get_base_update_var() - newaddr = xd.get_base_update_xpr() + newaddr = xd.get_base_update_cxpr() hl_addr_lhs = XU.xvariable_to_ast_lval(basereg, xdata, iaddr, astree) - - hl_addr_lhs_type = hl_addr_lhs.ctype(astree.ctyper) - if hl_addr_lhs_type is not None and len(xdata.ints) > 0: - if hl_addr_lhs_type.is_pointer: - addrtype = cast(AST.ASTTypPtr, hl_addr_lhs_type) - tgttyp = addrtype.tgttyp - tgttypsize = astree.type_size_in_bytes(tgttyp) - if tgttypsize is not None: - incr = xdata.ints[0] - ptrincr = incr // tgttypsize - hl_addr_rhs = astree.mk_binary_op( - "plus", - astree.mk_lval_expression(hl_addr_lhs), - astree.mk_integer_constant(ptrincr)) - else: - hl_addr_rhs = XU.xxpr_to_ast_def_expr( - newaddr, xdata, iaddr, astree) - chklogger.logger.warning( - "LDR address adjustment not scaled due to missing " - + "size of pointer target type %s at address %s", - str(tgttyp), iaddr) - else: - hl_addr_rhs = XU.xxpr_to_ast_def_expr( - newaddr, xdata, iaddr, astree) - chklogger.logger.warning( - "LDR address adjustment not scaled due to unexpected " - + "address type: %s at address %s", - str(hl_addr_lhs_type), iaddr) - else: - hl_addr_rhs = XU.xxpr_to_ast_def_expr( - newaddr, xdata, iaddr, astree) - chklogger.logger.warning( - "LDR address adjustment not scaled due to lack of type " - + "information at address %s", - iaddr) + hl_addr_rhs = XU.xxpr_to_ast_def_expr(newaddr, xdata, iaddr, astree) hl_addr_assign = astree.mk_assign( hl_addr_lhs, @@ -319,9 +334,6 @@ def has_cast() -> bool: annotations=annotations) hl_assigns: List[AST.ASTInstruction] = [hl_assign, hl_addr_assign] - # Note: work-around for deficiency in def-use propagation - astree.add_expose_instruction(hl_addr_assign.instrid) - astree.add_instr_mapping(hl_addr_assign, ll_addr_assign) astree.add_instr_address(hl_addr_assign, [iaddr]) astree.add_expr_mapping(hl_addr_rhs, ll_addr_rhs) diff --git a/chb/arm/opcodes/ARMLoadRegisterHalfword.py b/chb/arm/opcodes/ARMLoadRegisterHalfword.py index 71a0fbc1..e56e699e 100644 --- a/chb/arm/opcodes/ARMLoadRegisterHalfword.py +++ b/chb/arm/opcodes/ARMLoadRegisterHalfword.py @@ -52,6 +52,21 @@ class ARMLoadRegisterHalfwordXData(ARMOpcodeXData): + """Data format: + - variables: + 0: vrt (lhs) + + - expressions: + 0: xrn + 1: xrm + 2: xmem (rhs) + 3: xrmem (rhs, rewritten) + 4: xaddr (address of rhs) + + - c expressions: + 0: cxrmem (rhs) + 1: cxaddr (address of rhs) + """ def __init__(self, xdata: InstrXData) -> None: ARMOpcodeXData.__init__(self, xdata) @@ -61,36 +76,79 @@ def vrt(self) -> "XVariable": return self.var(0, "vrt") @property - def vmem(self) -> "XVariable": - return self.var(1, "vmem") + def xrn(self) -> "XXpr": + return self.xpr(0, "xrn") + + @property + def xrm(self) -> "XXpr": + return self.xpr(1, "xrm") @property def xmem(self) -> "XXpr": return self.xpr(2, "xmem") + @property + def is_xmem_ok(self) -> bool: + return self.is_xpr_ok(2) + @property def xrmem(self) -> "XXpr": return self.xpr(3, "xrmem") + @property + def is_xrmem_ok(self) -> bool: + return self.is_xpr_ok(3) + + @property + def cxrmem(self) -> "XXpr": + return self.cxpr(0, "cxrmem") + + @property + def is_cxrmem_ok(self) -> bool: + return self.is_cxpr_ok(0) + @property def xaddr(self) -> "XXpr": return self.xpr(4, "xaddr") @property - def is_xrmem_unknown(self) -> bool: - return self.xdata.xprs_r[3] is None + def is_xaddr_ok(self) -> bool: + return self.is_xpr_ok(4) + + @property + def xxaddr(self) -> "XXpr": + return self.xpr(5, "xxaddr") + + @property + def is_xxaddr_ok(self) -> bool: + return self.is_xpr_ok(5) + + @property + def cxaddr(self) -> "XXpr": + return self.cxpr(1, "cxaddr") @property - def is_address_known(self) -> bool: - return self.xdata.xprs_r[4] is not None + def is_cxaddr_ok(self) -> bool: + return self.is_cxpr_ok(1) @property def annotation(self) -> str: wbu = self.writeback_update() - if self.is_ok: - assignment = str(self.vrt) + " := " + str(self.xrmem) - elif self.is_xrmem_unknown and self.is_address_known: - assignment = str(self.vrt) + " := *(" + str(self.xaddr) + ")" + if self.is_cxrmem_ok: + crhs = str(self.cxrmem) + elif self.is_cxaddr_ok: + crhs = "*(" + str(self.cxaddr) + ")" + else: + crhs = "None" + cx = " (C: " + crhs + ")" + addr = str(self.xxaddr if self.is_xxaddr_ok else self.xaddr) + caddr = str(self.cxaddr if self.is_cxaddr_ok else "None") + caddr = " (addr: " + addr + "; C: " + caddr + ")" + if self.is_ok or self.is_xrmem_ok: + assignment = str(self.vrt) + " := " + str(self.xrmem) + cx + caddr + elif self.is_xaddr_ok: + assignment = ( + str(self.vrt) + " := *(" + str(self.xaddr) + ")" + cx + caddr) else: assignment = "Error value" return self.add_instruction_condition(assignment) + wbu @@ -109,27 +167,14 @@ class ARMLoadRegisterHalfword(ARMOpcode): args[3]: index of memory location in armdictionary args[4]: is-wide (thumb) - xdata format: a:vxxxxrrrdh - -------------------------- - vars[0]: lhs - vars[1]: memory location expressed as a variable - xprs[0]: value in rn - xprs[1]: value in rm - xprs[2]: value in memory location - xprs[3]: value in memory location (simplified) - xprs[4]: address of memory location + xdata format: + ------------- rdefs[0]: reaching definitions rn rdefs[1]: reaching definitions rm rdefs[2]: reaching definitions memory location rdefs[3..]: reaching definitions for memory value uses[0]: use of lhs useshigh[0]: use of lhs at high level - - optional: - vars[1]: lhs base register (if base update) - - xprs[.]: instruction condition (if has condition) - xprs[.]: new address for base register """ def __init__(self, d: "ARMDictionary", ixval: IndexedTableValue) -> None: @@ -149,13 +194,20 @@ def opargs(self) -> List[ARMOperand]: return [self.armd.arm_operand(self.args[i]) for i in [0, 1, 2, 3]] def lhs(self, xdata: InstrXData) -> List[XVariable]: - return [xdata.vars[0]] + xd = ARMLoadRegisterHalfwordXData(xdata) + return [xd.vrt] def is_load_instruction(self, xdata: InstrXData) -> bool: return True def rhs(self, xdata: InstrXData) -> List[XXpr]: - return [xdata.xprs[1]] + xd = ARMLoadRegisterHalfwordXData(xdata) + if xd.is_xrmem_ok: + return [xd.xrmem] + elif xd.is_xmem_ok: + return [xd.xmem] + else: + return [] def annotation(self, xdata: InstrXData) -> str: return ARMLoadRegisterHalfwordXData(xdata).annotation @@ -189,31 +241,53 @@ def ast_prov( # high-level assignment + def has_cast() -> bool: + return ( + astree.has_register_variable_intro(iaddr) + and astree.get_register_variable_intro(iaddr).has_cast()) + + lhs = xd.vrt + if xd.is_ok: - lhs = xd.vrt - rhs = xd.xrmem - xaddr = xd.xaddr - hl_lhs = XU.xvariable_to_ast_lval(lhs, xdata, iaddr, astree, rhs=rhs) - hl_rhs = XU.xxpr_to_ast_def_expr( - rhs, xdata, iaddr, astree, memaddr=xaddr, size=2) + rhs = xd.cxrmem + rhsval = None if has_cast() else xd.cxrmem + hl_lhs = XU.xvariable_to_ast_lval( + lhs, xdata, iaddr, astree, rhs=rhsval) + hl_rhs = XU.xxpr_to_ast_def_expr(rhs, xdata, iaddr, astree) + + elif xd.is_cxaddr_ok: + cxaddr = xd.cxaddr + hl_lhs = XU.xvariable_to_ast_lval(lhs, xdata, iaddr, astree) + hl_rhs = XU.xmemory_dereference_lval_expr( + cxaddr, xdata, iaddr, astree) - elif xd.is_xrmem_unknown and xd.is_address_known: + elif xd.is_xaddr_ok: xaddr = xd.xaddr - lhs = xd.vrt hl_lhs = XU.xvariable_to_ast_lval(lhs, xdata, iaddr, astree) hl_rhs = XU.xmemory_dereference_lval_expr( - xaddr, xdata, iaddr, astree, size=2) + xaddr, xdata, iaddr, astree) + + chklogger.logger.warning( + "LDRH: Unable to use a C expression for rhs. Fall back to " + + "native byte-based address: %s to form rhs %s at address %s", + str(xaddr), str(hl_rhs), iaddr) else: chklogger.logger.error( "LDRH: both memory value and address values are error values " + "at address %s: ", iaddr) - return ([], []) + return ([], (ll_pre + [ll_assign] + ll_post)) + rdefs = xdata.reachingdefs defuses = xdata.defuses defuseshigh = xdata.defuseshigh + if has_cast(): + lhstype = hl_lhs.ctype(astree.ctyper) + if lhstype is not None: + hl_rhs = astree.mk_cast_expr(lhstype, hl_rhs) + hl_assign = astree.mk_assign( hl_lhs, hl_rhs, @@ -221,6 +295,9 @@ def ast_prov( bytestring=bytestring, annotations=annotations) + if has_cast(): + astree.add_expose_instruction(hl_assign.instrid) + astree.add_instr_mapping(hl_assign, ll_assign) astree.add_instr_address(hl_assign, [iaddr]) astree.add_expr_mapping(hl_rhs, ll_rhs) @@ -245,7 +322,7 @@ def ast_prov( ll_assigns: List[AST.ASTInstruction] = [ll_assign, ll_addr_assign] basereg = xd.get_base_update_var() - newaddr = xd.get_base_update_xpr() + newaddr = xd.get_base_update_cxpr() hl_addr_lhs = XU.xvariable_to_ast_lval(basereg, xdata, iaddr, astree) hl_addr_rhs = XU.xxpr_to_ast_def_expr(newaddr, xdata, iaddr, astree) diff --git a/chb/arm/opcodes/ARMMove.py b/chb/arm/opcodes/ARMMove.py index e5edf14a..5423288f 100644 --- a/chb/arm/opcodes/ARMMove.py +++ b/chb/arm/opcodes/ARMMove.py @@ -51,6 +51,17 @@ class ARMMoveXData(ARMOpcodeXData): + """Data format: + - variables: + 0: vrd + + - expressions: + 0: xrm + 1: result + + - c expressions: + 0: cresult + """ def __init__(self, xdata: InstrXData) -> None: ARMOpcodeXData.__init__(self, xdata) @@ -67,9 +78,23 @@ def xrm(self) -> "XXpr": def result(self) -> "XXpr": return self.xpr(1, "result") + @property + def is_result_ok(self) -> bool: + return self.is_xpr_ok(1) + + @property + def cresult(self) -> "XXpr": + return self.cxpr(0, "cresult") + + @property + def is_cresult_ok(self) -> bool: + return self.is_cxpr_ok(0) + @property def annotation(self) -> str: - assignment = str(self.vrd) + " := " + str(self.result) + cx = " (C: " + (str(self.cresult) if self.is_cresult_ok else "None") + ")" + rhs = str(self.result) if self.is_result_ok else str(self.xrm) + assignment = str(self.vrd) + " := " + rhs + cx return self.add_instruction_condition(assignment) @@ -87,11 +112,8 @@ class ARMMove(ARMOpcode): args[3]: is-wide (thumb) args[4]: wide - xdata format: a:vxxrdh - ---------------------- - vars[0]: lhs - xprs[0]: rhs - xprs[1]: rhs (simplified) + xdata format + ------------ rdefs[0]: rhs rdefs[1..]: rhs (simplified) uses[0]: lhs @@ -134,10 +156,7 @@ def annotation(self, xdata: InstrXData) -> str: return "NOP" xd = ARMMoveXData(xdata) - if xd.is_ok: - return xd.annotation - else: - return "Error value" + return xd.annotation def ast_prov_subsumed( self, @@ -178,7 +197,6 @@ def ast_prov( xdata: InstrXData) -> Tuple[ List[AST.ASTInstruction], List[AST.ASTInstruction]]: - xd = ARMMoveXData(xdata) annotations: List[str] = [iaddr, "MOV"] if xdata.is_nop: @@ -208,12 +226,16 @@ def ast_prov( # high-level assignment - if not xd.is_ok: - chklogger.logger.error("Error value encountered at %s", iaddr) - return ([], []) + xd = ARMMoveXData(xdata) + + if xd.is_cresult_ok: + rhs = xd.cresult + elif xd.is_result_ok: + rhs = xd.result + else: + rhs = xd.xrm lhs = xd.vrd - rhs = xd.result rdefs = xdata.reachingdefs defuses = xdata.defuses defuseshigh = xdata.defuseshigh diff --git a/chb/arm/opcodes/ARMMultiply.py b/chb/arm/opcodes/ARMMultiply.py index 01069527..8cae080f 100644 --- a/chb/arm/opcodes/ARMMultiply.py +++ b/chb/arm/opcodes/ARMMultiply.py @@ -50,6 +50,19 @@ class ARMMultiplyXData(ARMOpcodeXData): + """Data format: + - variables: + 0: vrd + + - expressions: + 0: xrn + 1: xrm + 2: result + 3: rresult (result rewritten) + + - c expressions: + 0: cresult + """ def __init__(self, xdata: InstrXData) -> None: ARMOpcodeXData.__init__(self, xdata) @@ -70,18 +83,41 @@ def xrm(self) -> "XXpr": def result(self) -> "XXpr": return self.xpr(2, "result") + @property + def is_result_ok(self) -> bool: + return self.is_xpr_ok(2) + @property def rresult(self) -> "XXpr": return self.xpr(3, "rresult") + @property + def is_rresult_ok(self) -> bool: + return self.is_xpr_ok(3) + + @property + def cresult(self) -> "XXpr": + return self.cxpr(0, "cresult") + + @property + def is_cresult_ok(self) -> bool: + return self.is_cxpr_ok(0) + @property def result_simplified(self) -> str: - return simplify_result( - self.xdata.args[3], self.xdata.args[4], self.result, self.rresult) + if self.is_result_ok and self.is_rresult_ok: + return simplify_result( + self.xdata.args[3], self.xdata.args[4], self.result, self.rresult) + else: + return str(self.xrn) + " * " + str(self.xrm) @property def annotation(self) -> str: - assignment = str(self.vrd) + " := " + self.result_simplified + cresult = ( + " (C: " + + (str(self.cresult) if self.is_cresult_ok else "None") + + ")") + assignment = str(self.vrd) + " := " + self.result_simplified + cresult return self.add_instruction_condition(assignment) @@ -112,10 +148,7 @@ def opargs(self) -> List[ARMOperand]: def annotation(self, xdata: InstrXData) -> str: xd = ARMMultiplyXData(xdata) - if xd.is_ok: - return xd.annotation - else: - return "Error value" + return xd.annotation def ast_prov( self, @@ -149,20 +182,27 @@ def ast_prov( # high-level assignment xd = ARMMultiplyXData(xdata) - if not xd.is_ok: - chklogger.logger.error("Error value encountered at %s", iaddr) - return ([], []) - lhs = xd.vrd - rhs1 = xd.xrn - rhs2 = xd.xrm - rhs3 = xd.rresult + if xd.is_cresult_ok and xd.is_rresult_ok: + rhs = xd.cresult + + elif xd.is_rresult_ok: + rhs = xd.rresult + elif xd.is_result_ok: + rhs = xd.result + + else: + chklogger.logger.error( + "MUL: Encountered error value for rhs at address %s", iaddr) + return ([], [ll_assign]) + + lhs = xd.vrd defuses = xdata.defuses defuseshigh = xdata.defuseshigh hl_lhs = XU.xvariable_to_ast_lval(lhs, xdata, iaddr, astree) - hl_rhs = XU.xxpr_to_ast_def_expr(rhs3, xdata, iaddr, astree) + hl_rhs = XU.xxpr_to_ast_def_expr(rhs, xdata, iaddr, astree) hl_assign = astree.mk_assign( hl_lhs, diff --git a/chb/arm/opcodes/ARMPop.py b/chb/arm/opcodes/ARMPop.py index 0ebbf44d..770fcec6 100644 --- a/chb/arm/opcodes/ARMPop.py +++ b/chb/arm/opcodes/ARMPop.py @@ -50,6 +50,23 @@ class ARMPopXData(ARMOpcodeXData): + """Data format: + - variables: + 0: splhs + 1..n: lhsvars + + - expressions: + 0: sprhs + 1: spresult + 2: rspresult (spresult, rewritten) + 3..n+2: rrhsexprs + n+3 .. (2n+2): xaddrs + + optional return values: + - returnval + - rreturnval + - creturnval + """ def __init__(self, xdata: InstrXData) -> None: ARMOpcodeXData.__init__(self, xdata) @@ -96,6 +113,12 @@ def returnval(self) -> "XXpr": def rreturnval(self) -> "XXpr": return self.xdata.get_return_xxpr() + def has_creturnval(self) -> bool: + return self.xdata.has_return_cxpr() + + def creturnval(self) -> "XXpr": + return self.xdata.get_return_cxpr() + @property def r0(self) -> Optional["XXpr"]: if "return" in self._xdata.tags: @@ -109,7 +132,11 @@ def annotation(self) -> str: assigns = "; ".join(str(v) + " := " + str(x) for (v, x) in pairs) assigns = spassign + "; " + assigns if self.has_return_xpr(): - rxpr = "; return " + str(self.rreturnval()) + cxpr = ( + " (C: " + + (str(self.creturnval()) if self.has_creturnval() else "None") + + ")") + rxpr = "; return " + str(self.rreturnval()) + cxpr else: rxpr = "" return self.add_instruction_condition(assigns + rxpr) @@ -126,16 +153,8 @@ class ARMPop(ARMOpcode): args[1]: index of register list in armdictionary args[2]: is-wide (thumb) - xdata format: a:vv(n)xxxx(n)rr(n)dd(n)hh(n) (SP + registers popped) - --------------------------------------------------------------------- - vars[0]: SP - vars[1..n]: v(r) for r: register popped - xprs[0]: SP - xprs[1]: SP updated - xprs[2]: SP updated, simplified - xprs[3..n+2]: x(m) for m: memory location value retrieved - xprs[n+3..2n+2]: memory address of memory location value retrieved - xprs[2n+3]: (optional) value of R0 if register list includes PC + xdata format + ------------ rdefs[0]: SP rdefs[1..n]: rdef(m) for m: memory location variable rdefs[n+1]: (optional) rdef for R0 if register list includes PC @@ -172,16 +191,16 @@ def is_return_instruction(self, xdata: InstrXData) -> bool: def return_value(self, xdata: InstrXData) -> Optional[XXpr]: xd = ARMPopXData(xdata) if xd.has_return_xpr(): - return xd.rreturnval() + if xd.has_creturnval(): + return xd.creturnval() + else: + return xd.rreturnval() else: return None def annotation(self, xdata: InstrXData) -> str: xd = ARMPopXData(xdata) - if xd.is_ok: - return xd.annotation - else: - return "Error value" + return xd.annotation def ast_condition_prov( self, diff --git a/chb/arm/opcodes/ARMReverseSubtract.py b/chb/arm/opcodes/ARMReverseSubtract.py index d29002ea..8ed30064 100644 --- a/chb/arm/opcodes/ARMReverseSubtract.py +++ b/chb/arm/opcodes/ARMReverseSubtract.py @@ -50,6 +50,19 @@ class ARMReverseSubtractXData(ARMOpcodeXData): + """Data format: + - variables: + 0: vrd + + - expressions: + 0: xrn + 1: xrm + 2: result + 3: rresult (result rewritten) + + - c expressions: + 0: cresult + """ def __init__(self, xdata: InstrXData) -> None: ARMOpcodeXData.__init__(self, xdata) @@ -70,18 +83,41 @@ def xrm(self) -> "XXpr": def result(self) -> "XXpr": return self.xpr(2, "result") + @property + def is_result_ok(self) -> bool: + return self.is_xpr_ok(2) + @property def rresult(self) -> "XXpr": return self.xpr(3, "rresult") + @property + def is_rresult_ok(self) -> bool: + return self.is_xpr_ok(3) + + @property + def cresult(self) -> "XXpr": + return self.cxpr(0, "cresult") + + @property + def is_cresult_ok(self) -> bool: + return self.is_cxpr_ok(0) + @property def result_simplified(self) -> str: - return simplify_result( - self.xdata.args[3], self.xdata.args[4], self.result, self.rresult) + if self.is_result_ok and self.is_rresult_ok: + return simplify_result( + self.xdata.args[3], self.xdata.args[4], self.result, self.rresult) + else: + return str(self.xrm) + " - " + str(self.xrn) @property def annotation(self) -> str: - assignment = str(self.vrd) + " := " + self.result_simplified + cresult = ( + " (C: " + + (str(self.cresult) if self.is_cresult_ok else "None") + + ")") + assignment = str(self.vrd) + " := " + self.result_simplified + cresult return self.add_instruction_condition(assignment) @@ -98,13 +134,8 @@ class ARMReverseSubtract(ARMOpcode): args[3]: index of op3 in armdictionary args[4]: is-wide (thumb) - xdata format: a:vxxxxrrdh - ------------------------- - vars[0]: lhs (Rd) - xprs[0]: rhs1 (Rn) - xprs[1]: rhs2 (Rm) - xprs[2]: rhs2 - rhs1 - xprs[3]: rhs2 - rhs1 (simplified) + xdata format: + ------------- rdefs[0]: rhs1 rdefs[1]: rhs2 rdefs[2]: reaching definitions for simplified result @@ -141,10 +172,7 @@ def is_writeback(self) -> bool: def annotation(self, xdata: InstrXData) -> str: xd = ARMReverseSubtractXData(xdata) - if xd.is_ok: - return xd.annotation - else: - return "Error value" + return xd.annotation def ast_prov( self, @@ -178,21 +206,25 @@ def ast_prov( # high-level assignment xd = ARMReverseSubtractXData(xdata) - if not xd.is_ok: + + if xd.is_cresult_ok: + rhs = xd.cresult + elif xd.is_rresult_ok: + rhs = xd.rresult + elif xd.is_result_ok: + rhs = xd.result + else: chklogger.logger.error( - "Encountered error value at address %s", iaddr) - return ([], []) + "RSB: Encountered error value for rhs at address %s", iaddr) + return ([], [ll_assign]) lhs = xd.vrd - rhs1 = xd.xrn - rhs2 = xd.xrm - rhs3 = xd.rresult defuses = xdata.defuses defuseshigh = xdata.defuseshigh hl_lhs = XU.xvariable_to_ast_lval(lhs, xdata, iaddr, astree) - hl_rhs = XU.xxpr_to_ast_def_expr(rhs3, xdata, iaddr, astree) + hl_rhs = XU.xxpr_to_ast_def_expr(rhs, xdata, iaddr, astree) hl_assign = astree.mk_assign( hl_lhs, diff --git a/chb/arm/opcodes/ARMStoreMultipleIncrementAfter.py b/chb/arm/opcodes/ARMStoreMultipleIncrementAfter.py index 7cb222f3..7d4fa6a1 100644 --- a/chb/arm/opcodes/ARMStoreMultipleIncrementAfter.py +++ b/chb/arm/opcodes/ARMStoreMultipleIncrementAfter.py @@ -25,7 +25,7 @@ # SOFTWARE. # ------------------------------------------------------------------------------ -from typing import cast, List, TYPE_CHECKING, Tuple +from typing import cast, Iterable, List, TYPE_CHECKING, Tuple from chb.app.InstrXData import InstrXData @@ -52,6 +52,24 @@ class ARMStoreMultipleIncrementAfterXData(ARMOpcodeXData): + """Data format: + - variables: + 0: baselhs + 1..n: memlhss + + - c variables: + 1..n: cmemlhss + + - expressions: + 0: baserhs + 1..n: rhss + n+1..2n: rrhss + 2n+1..3n: xaddrs + + - c expressions: + 0..n-1: crhss + n..2n-1: cxaddrs + """ def __init__(self, xdata: InstrXData) -> None: ARMOpcodeXData.__init__(self, xdata) @@ -71,32 +89,48 @@ def xdst(self) -> "XXpr": return self.ldmstm_xpr(0, "xdst") @property - def is_xdst_unknown(self) -> bool: - return self.xdata.xprs_r[0] is None + def is_xdst_ok(self) -> bool: + return self.is_xpr_ok(0) @property def xsrc(self) -> "XXpr": return self.ldmstm_xpr(1, "xsrc") @property - def is_xsrc_unknowns(self) -> bool: - return self.xdata.xprs_r[1] is None + def is_xsrc_ok(self) -> bool: + return self.is_xpr_ok(1) @property def xxdst(self) -> "XXpr": return self.ldmstm_xpr(2, "xxdst") @property - def is_xxdst_unknown(self) -> bool: - return self.xdata.xprs_r[2] is None + def is_xxdst_ok(self) -> bool: + return self.is_xpr_ok(2) @property def xxsrc(self) -> "XXpr": return self.ldmstm_xpr(3, "xxsrc") @property - def is_xxsrc_unknown(self) -> bool: - return self.xdata.xprs_r[3] is None + def is_xxsrc_ok(self) -> bool: + return self.is_xpr_ok(3) + + @property + def cdst(self) -> "XXpr": + return self.cxpr(0, "cdst") + + @property + def is_cdst_ok(self) -> bool: + return self.is_cxpr_ok(0) + + @property + def csrc(self) -> "XXpr": + return self.cxpr(1, "csrc") + + @property + def is_csrc_ok(self) -> bool: + return self.is_cxpr_ok(1) @property def copysize(self) -> int: @@ -114,16 +148,68 @@ def baselhs(self) -> "XVariable": return self.var(0, "baselhs") @property - def is_baselhs_known(self) -> bool: - return self.xdata.vars_r[0] is not None + def memlhs_range(self) -> Iterable[int]: + return range(1, self.regcount + 1) @property def memlhss(self) -> List["XVariable"]: - return [self.var(i, "memlhs-" + str(i)) for i in range(1, self.regcount + 1)] + return [self.var(i, "memlhs") for i in self.memlhs_range] + + @property + def are_memlhss_ok(self) -> bool: + return all(self.is_var_ok(i) for i in self.memlhs_range) + + @property + def cmemlhs_range(self) -> Iterable[int]: + return range(0, self.regcount) + + @property + def cmemlhss(self) -> List["XVariable"]: + return [self.cvar(i, "cmemlhs") for i in self.cmemlhs_range] + + @property + def are_cmemlhss_ok(self) -> bool: + return all(self.is_cvar_ok(i) for i in self.cmemlhs_range) + + @property + def baserhs(self) -> "XXpr": + return self.xpr(0, "baserhs") + + @property + def rhs_range(self) -> Iterable[int]: + return range(1, self.regcount + 1) @property def rhss(self) -> List["XXpr"]: - return [self.xpr(i, "rhs-" + str(i)) for i in range(3, self.regcount + 3)] + return [self.xpr(i, "rhs") for i in self.rhs_range] + + @property + def are_rhss_ok(self) -> bool: + return all(self.is_xpr_ok(i) for i in self.rhs_range) + + @property + def rrhs_range(self) -> Iterable[int]: + return range(self.regcount + 1, (2 * self.regcount) + 1) + + @property + def rrhss(self) -> List["XXpr"]: + return [self.xpr(i, "rrhs") for i in self.rrhs_range] + + @property + def are_rrhss_ok(self) -> bool: + return all(self.is_xpr_ok(i) for i in self.rrhs_range) + + @property + def crhs_range(self) -> Iterable[int]: + return range(0, self.regcount) + + @property + def crhss(self) -> List["XXpr"]: + return [self.cxpr(i, "crhs") for i in self.crhs_range] + + @property + def are_crhss_ok(self) -> bool: + return all(self.is_cxpr_ok(i) for i in self.crhs_range) @property def annotation(self) -> str: @@ -144,23 +230,26 @@ def annotation(self) -> str: return "; ".join(assigns) else: if self.is_ldmstm_aggregate: - if self.is_xxdst_unknown and self.is_xxsrc_unknown: - dst = str(self.xdst) - src = str(self.xsrc) - elif self.is_xxdst_unknown: + if self.is_xxdst_ok: + dst = str(self.xxdst) + elif self.is_xdst_ok: dst = str(self.xdst) - src = str(self.xxsrc) else: - dst = str(self.xxdst) + dst = "dst:error value" + if self.is_xxsrc_ok: + src = str(self.xxsrc) + elif self.is_xsrc_ok: src = str(self.xsrc) + else: + src = "src:error value" return ( - "memcpy(" - + dst - + ", " - + src - + ", " - + str(self.copysize) - + ")") + "memcpy(" + + dst + + ", " + + src + + ", " + + str(self.copysize) + + ")") else: return "not yet supported" @@ -180,12 +269,6 @@ class ARMStoreMultipleIncrementAfter(ARMOpcode): xdata: ---------------------------------------- - vars[0]: base - vars[1..n]: lhs memory locations where values are stored - xprs[0]: base - xprs[1]: updated base (may be unchanged in case of no writeback) - xprs[2]: updated base (simplified) - xprs[3..n+2]: values of registers being stored (simplified) rdefs[0]: reaching definition base register rdefs[1..n]: reaching definitions of registers being stored uses[0]: use of base register @@ -290,20 +373,9 @@ def ast_prov_ldmstmcopy( # high-level call xd = ARMStoreMultipleIncrementAfterXData(xdata) - if not xd.is_ok: - if xd.is_xxsrc_unknown and xd.is_xxdst_unknown: - chklogger.logger.error( - "LDM-STM-memcpy: (%s): src and dst unknown", iaddr) - elif xd.is_xxsrc_unknown: - chklogger.logger.error("LDM-STM-memcpy: (%s): src unknown", iaddr) - else: - chklogger.logger.error("LDM-STM-memcpy: (%s): dst unknown", iaddr) - return ([], []) xdst = xd.xdst xsrc = xd.xsrc - xxdst = xd.xxdst - xxsrc = xd.xxsrc xsize = xd.copysize # low-level arguments @@ -322,6 +394,20 @@ def ast_prov_ldmstmcopy( # high-level arguments + if xd.is_cdst_ok: + xxdst = xd.cdst + elif xd.is_xxdst_ok: + xxdst = xd.xxdst + else: + xxdst = xdst + + if xd.is_csrc_ok: + xxsrc = xd.csrc + elif xd.is_xxsrc_ok: + xxsrc = xd.xxsrc + else: + xxsrc = xsrc + if xxdst.is_stack_address: offset = xxdst.stack_address_offset() stackvar = astree.mk_stack_variable_lval(offset) @@ -419,22 +505,32 @@ def ast_prov( return self.ast_prov_ldmstmcopy(astree, iaddr, bytestring, xdata) xd = ARMStoreMultipleIncrementAfterXData(xdata) - if not xd.is_ok: + + if xd.are_cmemlhss_ok: + memlhss = xd.cmemlhss + elif xd.are_memlhss_ok: + memlhss = xd.memlhss + else: chklogger.logger.error( - "STM: Error value encountered at address %s", iaddr) + "STM: Error value encountered in LHSs at address %s", iaddr) + return ([], []) + + if xd.are_crhss_ok: + regrhss = xd.crhss + elif xd.are_rrhss_ok: + regrhss = xd.rhss + else: + chklogger.logger.error( + "STM: Error value encountered in RHSs at address %s", iaddr) return ([], []) annotations: List[str] = [iaddr, "STM"] - ''' - baselhs = xdata.vars[0] - baserhs = xdata.xprs[0] - baseresult = xdata.xprs[1] - baseresultr = xdata.xprs[2] + baselhs = xd.baselhs + baserhs = xd.baserhs baserdef = xdata.reachingdefs[0] baseuses = xdata.defuses[0] baseuseshigh = xdata.defuseshigh[0] - ''' # low-level assignments @@ -444,8 +540,6 @@ def ast_prov( (baselval, _, _) = self.opargs[0].ast_lvalue(astree) (baserval, _, _) = self.opargs[0].ast_rvalue(astree) - memlhss = xd.memlhss - regrhss = xd.rhss regrdefs = xdata.reachingdefs[1:] memuses = xdata.defuses[1:] memuseshigh = xdata.defuseshigh[1:] @@ -500,12 +594,11 @@ def ast_prov( memlhs.denotation).base.is_basevar)): astree.add_expose_instruction(hl_assign.instrid) - ''' if self.writeback: # low-level base assignment - baseincr = 4 * regcount + baseincr = 4 * xd.regcount baseincr_c = astree.mk_integer_constant(baseincr) ll_base_lhs = baselval @@ -520,9 +613,10 @@ def ast_prov( # high-level base assignment + baseresult = xd.get_base_update_xpr() hl_base_lhs = XU.xvariable_to_ast_lval(baselhs, xdata, iaddr, astree) hl_base_rhs = XU.xxpr_to_ast_def_expr( - baseresultr, xdata, iaddr, astree) + baseresult, xdata, iaddr, astree) hl_base_assign = astree.mk_assign( hl_base_lhs, hl_base_rhs, @@ -538,6 +632,5 @@ def ast_prov( astree.add_expr_reachingdefs(ll_base_rhs, [baserdef]) astree.add_lval_defuses(hl_base_lhs, baseuses) astree.add_lval_defuses_high(hl_base_lhs, baseuseshigh) - ''' return (hl_instrs, ll_instrs) diff --git a/chb/arm/opcodes/ARMStoreRegister.py b/chb/arm/opcodes/ARMStoreRegister.py index 11e23374..e5e59dbe 100644 --- a/chb/arm/opcodes/ARMStoreRegister.py +++ b/chb/arm/opcodes/ARMStoreRegister.py @@ -57,6 +57,25 @@ class ARMStoreRegisterXData(ARMOpcodeXData): + """Data format: + - variables: + 0: vmem_r (lhs) + + - c variables: + 0: cvmem_r (lhs) + + - expressions: + 0: xrn + 1: xrm + 2: xrt (rhs) + 3: xxrt (rhs, rewritten) + 4: xaddr (lhs address) + 5: xxaddr (lhs address, rewritten) + + - c expressions: + 0: cxrt (rhs) + 1: cxaddr (lhs address) + """ def __init__(self, xdata: InstrXData) -> None: ARMOpcodeXData.__init__(self, xdata) @@ -66,32 +85,16 @@ def vmem(self) -> "XVariable": return self.var(0, "vmem") @property - def is_vmem_known(self) -> bool: - return self.xdata.vars_r[0] is not None - - @property - def is_vmem_unknown(self) -> bool: - return self.xdata.vars_r[0] is None - - @property - def lhsvar(self) -> "XVariable": - return self.var(1, "lhsvar") - - @property - def is_lhsvar_unknown(self) -> bool: - return self.xdata.vars_r[1] is None - - @property - def is_lhsvar_known(self) -> bool: - return self.xdata.vars_r[1] is not None + def is_vmem_ok(self) -> bool: + return self.is_var_ok(0) @property - def is_xxrtc_known(self) -> bool: - return self.xdata.xprs_r[4] is not None + def cvmem(self) -> "XVariable": + return self.cvar(0, "cvmem") @property - def vrn(self) -> "XVariable": - return self.var(1, "vrn") + def is_cvmem_ok(self) -> bool: + return self.is_cvar_ok(0) @property def xrn(self) -> "XXpr": @@ -110,31 +113,61 @@ def xxrt(self) -> "XXpr": return self.xpr(3, "xxrt") @property - def xxrtc(self) -> "XXpr": - return self.xpr(4, "xxrtc") + def is_xxrt_ok(self) -> bool: + return self.is_xpr_ok(3) + + @property + def cxrt(self) -> "XXpr": + return self.cxpr(0, "cxrt") + + @property + def is_cxrt_ok(self) -> bool: + return self.is_cxpr_ok(0) @property def xaddr(self) -> "XXpr": - return self.xpr(5, "xaddr") + return self.xpr(4, "xaddr") + + @property + def is_xaddr_ok(self) -> "bool": + return self.is_xpr_ok(4) + + @property + def xxaddr(self) -> "XXpr": + return self.xpr(5, "xxaddr") @property - def is_address_known(self) -> bool: - return self.xdata.xprs_r[5] is not None + def is_xxaddr_ok(self) -> bool: + return self.is_xpr_ok(5) @property - def xaddr_updated(self) -> "XXpr": - return self.xpr(6, "xaddr_updated") + def cxaddr(self) -> "XXpr": + return self.cxpr(1, "cxaddr") + + @property + def is_cxaddr_ok(self) -> bool: + return self.is_cxpr_ok(1) @property def annotation(self) -> str: wbu = self.writeback_update() - rhs = self.xxrtc if self.is_xxrtc_known else self.xxrt - if self.is_ok or self.is_vmem_known: - assignment = str(self.vmem) + " := " + str(rhs) - elif self.is_vmem_unknown and self.is_address_known: - assignment = "*(" + str(self.xaddr) + ") := " + str(rhs) + clhs = str(self.cvmem) if self.is_cvmem_ok else "None" + crhs = str(self.cxrt) if self.is_cxrt_ok else "None" + assignc = "(C: " + clhs + " := " + crhs + ")" + if self.is_vmem_ok: + lhs = str(self.vmem) + elif self.is_xxaddr_ok: + lhs = "*(" + str(self.xxaddr) + ")" + elif self.is_xaddr_ok: + lhs = "*(" + str(self.xaddr) + ")" else: - assignment = "Error value" + lhs = "Error addr" + if self.is_xxrt_ok: + rhs = str(self.xxrt) + else: + rhs = "Error value" + assign = lhs + " := " + rhs + assignment = assign + " " + assignc return self.add_instruction_condition(assignment + wbu) @@ -153,14 +186,6 @@ class ARMStoreRegister(ARMOpcode): xdata format ------------ - vars[0]: lhs - vars[1]: vrn (base register, only if writeback) - xprs[0]: xrn (base register) - xprs[1]: xrm (index) - xprs[2]: xrt (rhs, source register) - xprs[3]: xrt (rhs, simplified) - xprs[4]: address of memory location - xprs[5]: condition (if TC is set) rdefs[0]: rn rdefs[1]: rm rdefs[2]: rt @@ -237,7 +262,6 @@ def ast_prov( xdata: InstrXData) -> Tuple[ List[AST.ASTInstruction], List[AST.ASTInstruction]]: - xd = ARMStoreRegisterXData(xdata) annotations: List[str] = [iaddr, "STR"] # low-level assignment @@ -253,41 +277,46 @@ def ast_prov( # high-level assignment - if xd.is_ok or xd.is_vmem_known: + xd = ARMStoreRegisterXData(xdata) + + if xd.is_cvmem_ok: + lhs = xd.cvmem + hl_lhs = XU.xvariable_to_ast_lval(lhs, xdata, iaddr, astree) + + elif xd.is_vmem_ok: lhs = xd.vmem - memaddr = xd.xaddr - hl_lhs = XU.xvariable_to_ast_lval( - lhs, xdata, iaddr, astree, memaddr=memaddr) + hl_lhs = XU.xvariable_to_ast_lval(lhs, xdata, iaddr, astree) - elif xd.is_vmem_unknown and xd.is_lhsvar_known and xd.is_address_known: - memaddr = xd.xaddr - lhsvar = xd.lhsvar - hl_lhs = XU.xvariable_to_ast_lval( - lhsvar, xdata, iaddr, astree, memaddr=memaddr) + elif xd.is_cxaddr_ok: + memaddr = xd.cxaddr + hl_lhs = XU.xmemory_dereference_lval(memaddr, xdata, iaddr, astree) + + elif xd.is_xxaddr_ok: + memaddr = xd.xxaddr + hl_lhs = XU.xmemory_dereference_lval(memaddr, xdata, iaddr, astree) - elif xd.is_address_known: + elif xd.is_xaddr_ok: memaddr = xd.xaddr hl_lhs = XU.xmemory_dereference_lval(memaddr, xdata, iaddr, astree) else: chklogger.logger.error( "STR: Lhs lval and address both have error values: skipping " - "store instruction at address %s", - iaddr) - return ([], []) + "store instruction at address %s", iaddr) + return ([], (ll_preinstrs + [ll_assign] + ll_postinstrs)) - if xd.is_vmem_unknown: - vmem = "unknown" + if xd.is_cxrt_ok: + rhs = xd.cxrt + elif xd.is_xxrt_ok: + rhs = xd.xxrt else: - vmem = str(xd.vmem) + rhs = xd.xrt + hl_rhs = XU.xxpr_to_ast_def_expr(rhs, xdata, iaddr, astree) - rhs = xd.xxrt rdefs = xdata.reachingdefs defuses = xdata.defuses defuseshigh = xdata.defuseshigh - hl_rhs = XU.xxpr_to_ast_def_expr(rhs, xdata, iaddr, astree) - if rhs.is_string_reference: rhsval = cast(XprConstant, rhs).intvalue saddr = hex(rhsval) @@ -305,7 +334,7 @@ def ast_prov( # to variables that are part of a struct or array variable, so these # assignments must be explicitly forced to appear in the lifting if ( - xd.is_vmem_unknown + (not xd.is_vmem_ok) or lhs.is_memory_variable and cast("VMemoryVariable", lhs.denotation).base.is_basevar or hl_lhs.offset.is_index_offset diff --git a/chb/arm/opcodes/ARMStoreRegisterByte.py b/chb/arm/opcodes/ARMStoreRegisterByte.py index d72a0045..3a9be3f4 100644 --- a/chb/arm/opcodes/ARMStoreRegisterByte.py +++ b/chb/arm/opcodes/ARMStoreRegisterByte.py @@ -52,6 +52,25 @@ class ARMStoreRegisterByteXData(ARMOpcodeXData): + """Data format: + - variables: + 0: vmem_r (lhs) + + - c variables: + 0: cvmem_r (lhs) + + - expressions: + 0: xrn + 1: xrm + 2: xrt (rhs) + 3: xxrt (rhs, rewritten) + 4: xaddr (lhs address) + 5: xxaddr (lhs address, rewritten) + + - c expressions: + 0: cxrt (rhs) + 1: cxaddr (lhs address) + """ def __init__(self, xdata: InstrXData) -> None: ARMOpcodeXData.__init__(self, xdata) @@ -61,20 +80,16 @@ def vmem(self) -> "XVariable": return self.var(0, "vmem") @property - def is_vmem_unknown(self) -> bool: - return self.xdata.vars_r[0] is None - - @property - def lhsvar(self) -> "XVariable": - return self.var(1, "lhsvar") + def is_vmem_ok(self) -> bool: + return self.is_var_ok(0) @property - def is_lhsvar_unknown(self) -> bool: - return self.xdata.vars_r[1] is None + def cvmem(self) -> "XVariable": + return self.cvar(0, "cvmem") @property - def is_lhsvar_known(self) -> bool: - return self.xdata.vars_r[1] is not None + def is_cvmem_ok(self) -> bool: + return self.is_cvar_ok(0) @property def xrn(self) -> "XXpr": @@ -92,23 +107,62 @@ def xrt(self) -> "XXpr": def xxrt(self) -> "XXpr": return self.xpr(3, "xxrt") + @property + def is_xxrt_ok(self) -> bool: + return self.is_xpr_ok(3) + + @property + def cxrt(self) -> "XXpr": + return self.cxpr(0, "cxrt") + + @property + def is_cxrt_ok(self) -> bool: + return self.is_cxpr_ok(0) + @property def xaddr(self) -> "XXpr": return self.xpr(4, "xaddr") @property - def is_address_known(self) -> bool: - return self.xdata.xprs_r[4] is not None + def is_xaddr_ok(self) -> "bool": + return self.is_xpr_ok(4) + + @property + def xxaddr(self) -> "XXpr": + return self.xpr(5, "xxaddr") + + @property + def is_xxaddr_ok(self) -> bool: + return self.is_xpr_ok(5) + + @property + def cxaddr(self) -> "XXpr": + return self.cxpr(1, "cxaddr") + + @property + def is_cxaddr_ok(self) -> bool: + return self.is_cxpr_ok(1) @property def annotation(self) -> str: wbu = self.writeback_update() - if self.is_ok: - assignment = str(self.vmem) + " := " + str(self.xxrt) - elif self.is_vmem_unknown and self.is_address_known: - assignment = "*(" + str(self.xaddr) + ") := " + str(self.xxrt) + clhs = str(self.cvmem) if self.is_cvmem_ok else "None" + crhs = str(self.cxrt) if self.is_cxrt_ok else "None" + assignc = "(C: " + clhs + " := " + crhs + ")" + if self.is_vmem_ok: + lhs = str(self.vmem) + elif self.is_xxaddr_ok: + lhs = "*(" + str(self.xxaddr) + ")" + elif self.is_xaddr_ok: + lhs = "*(" + str(self.xaddr) + ")" else: - assignment = "Error value" + lhs = "Error addr" + if self.is_xxrt_ok: + rhs = str(self.xxrt) + else: + rhs = "Error value" + assign = lhs + " := " + rhs + assignment = assign + " " + assignc return self.add_instruction_condition(assignment + wbu) @@ -125,15 +179,8 @@ class ARMStoreRegisterByte(ARMOpcode): args[3]: index of memory location in armdictionary args[4]: is-wide (thumb) - xdata format: a:vxxxxrrrdh - -------------------------- - vars[0]: lhs - xprs[0]: xrn (base register) - xprs[1]: xrm (index) - xprs[2]: xrt (rhs, source register) - xprs[3]: xrt (rhs, simplified) - xprs[4]: xaddr (memory address) - xprs[5]: condition (if TC is set) + xdata format: + ------------- rdefs[0]: rn rdefs[1]: rm rdefs[2]: rt @@ -199,42 +246,45 @@ def ast_prov( xd = ARMStoreRegisterByteXData(xdata) - if xd.is_ok: - lhs = xd.lhsvar - memaddr = xd.xaddr - hl_lhs = XU.xvariable_to_ast_lval( - lhs, xdata, iaddr, astree, memaddr=memaddr) + if xd.is_cvmem_ok: + lhs = xd.cvmem + hl_lhs = XU.xvariable_to_ast_lval(lhs, xdata, iaddr, astree) - elif xd.is_vmem_unknown and xd.is_lhsvar_known and xd.is_address_known: - memaddr = xd.xaddr - lhsvar = xd.lhsvar - hl_lhs = XU.xvariable_to_ast_lval( - lhsvar, xdata, iaddr, astree, memaddr=memaddr) + elif xd.is_vmem_ok: + lhs = xd.vmem + hl_lhs = XU.xvariable_to_ast_lval(lhs, xdata, iaddr, astree) + + elif xd.is_cxaddr_ok: + memaddr = xd.cxaddr + hl_lhs = XU.xmemory_dereference_lval(memaddr, xdata, iaddr, astree) - elif xd.is_address_known: + elif xd.is_xxaddr_ok: + memaddr = xd.xxaddr + hl_lhs = XU.xmemory_dereference_lval(memaddr, xdata, iaddr, astree) + + elif xd.is_xaddr_ok: memaddr = xd.xaddr hl_lhs = XU.xmemory_dereference_lval(memaddr, xdata, iaddr, astree) else: chklogger.logger.error( "STRB: Lhs lval and address both have error values: skipping " - + "store instruction at address %s", - iaddr) - return ([], []) + "store instruction at address %s", iaddr) + return ([], (ll_preinstrs + [ll_assign] + ll_postinstrs)) + + if xd.is_cxrt_ok: + rhs = xd.cxrt + elif xd.is_xxrt_ok: + rhs = xd.xxrt + else: + rhs = xd.xrt + + hl_rhs = XU.xxpr_to_ast_def_expr(rhs, xdata, iaddr, astree) - rhs = xd.xxrt - rhs_basic = xd.xrt rdefs = xdata.reachingdefs defuses = xdata.defuses defuseshigh = xdata.defuseshigh - if rhs.has_variables_with_property( - lambda v: v.is_initial_memory_value - and xdata.function.has_var_disequality(iaddr, v)): - hl_rhs = XU.xxpr_to_ast_def_expr(rhs_basic, xdata, iaddr, astree) - else: - hl_rhs = XU.xxpr_to_ast_def_expr(rhs, xdata, iaddr, astree) - hl_assign = astree.mk_assign( hl_lhs, hl_rhs, @@ -246,7 +296,7 @@ def ast_prov( # to variables that are part of a struct or array variable, so these # assignments must be explicitly forced to appear in the lifting if ( - xd.is_vmem_unknown + (not xd.is_vmem_ok) or hl_lhs.offset.is_index_offset or hl_lhs.offset.is_field_offset): astree.add_expose_instruction(hl_assign.instrid) @@ -302,4 +352,4 @@ def ast_prov( memexp = cast(AST.ASTMemRef, ll_lhs.lhost).memexp astree.add_expr_reachingdefs(memexp, [rdefs[0], rdefs[1]]) - return ([hl_assign], [ll_assign]) + return ([hl_assign], (ll_preinstrs + ll_assigns + ll_postinstrs)) diff --git a/chb/arm/opcodes/ARMStoreRegisterHalfword.py b/chb/arm/opcodes/ARMStoreRegisterHalfword.py index 58356e30..4b35015f 100644 --- a/chb/arm/opcodes/ARMStoreRegisterHalfword.py +++ b/chb/arm/opcodes/ARMStoreRegisterHalfword.py @@ -51,6 +51,25 @@ class ARMStoreRegisterHalfwordXData(ARMOpcodeXData): + """Data format: + - variables: + 0: vmem_r (lhs) + + - c variables: + 0: cvmem_r (lhs) + + - expressions: + 0: xrn + 1: xrm + 2: xrt (rhs) + 3: xxrt (rhs, rewritten) + 4: xaddr (lhs address) + 5: xxaddr (lhs address, rewritten) + + - c expressions: + 0: cxrt (rhs) + 1: cxaddr (lhs address) + """ def __init__(self, xdata: InstrXData) -> None: ARMOpcodeXData.__init__(self, xdata) @@ -60,8 +79,16 @@ def vmem(self) -> "XVariable": return self.var(0, "vmem") @property - def is_vmem_unknown(self) -> bool: - return self.xdata.vars_r[0] is None + def is_vmem_ok(self) -> bool: + return self.is_var_ok(0) + + @property + def cvmem(self) -> "XVariable": + return self.cvar(0, "cvmem") + + @property + def is_cvmem_ok(self) -> bool: + return self.is_cvar_ok(0) @property def xrn(self) -> "XXpr": @@ -80,31 +107,65 @@ def xxrt(self) -> "XXpr": return self.xpr(3, "xxrt") @property - def is_xxrt_known(self) -> bool: - return self.xdata.xprs_r[3] is not None + def is_xxrt_ok(self) -> bool: + return self.is_xpr_ok(3) + + @property + def cxrt(self) -> "XXpr": + return self.cxpr(0, "cxrt") + + @property + def is_cxrt_ok(self) -> bool: + return self.is_cxpr_ok(0) @property def xaddr(self) -> "XXpr": return self.xpr(4, "xaddr") @property - def is_address_known(self) -> bool: - return self.xdata.xprs_r[4] is not None + def is_xaddr_ok(self) -> "bool": + return self.is_xpr_ok(4) + + @property + def xxaddr(self) -> "XXpr": + return self.xpr(5, "xxaddr") + + @property + def is_xxaddr_ok(self) -> bool: + return self.is_xpr_ok(5) + + @property + def cxaddr(self) -> "XXpr": + return self.cxpr(1, "cxaddr") + + @property + def is_cxaddr_ok(self) -> bool: + return self.is_cxpr_ok(1) @property def annotation(self) -> str: wbu = self.writeback_update() - if self.is_ok: - assignment = str(self.vmem) + " := " + str(self.xxrt) - elif not self.is_xxrt_known: - assignment = "(*" + str(self.xaddr) + ") := " + str(self.xrt) - elif self.is_vmem_unknown and self.is_address_known: - assignment = "*(" + str(self.xaddr) + ") := " + str(self.xxrt) + clhs = str(self.cvmem) if self.is_cvmem_ok else "None" + crhs = str(self.cxrt) if self.is_cxrt_ok else "None" + assignc = "(C: " + clhs + " := " + crhs + ")" + if self.is_vmem_ok: + lhs = str(self.vmem) + elif self.is_xxaddr_ok: + lhs = "*(" + str(self.xxaddr) + ")" + elif self.is_xaddr_ok: + lhs = "*(" + str(self.xaddr) + ")" + else: + lhs = "Error addr" + if self.is_xxrt_ok: + rhs = str(self.xxrt) else: - assignment = "Error value" + rhs = "Error value" + assign = lhs + " := " + rhs + assignment = assign + " " + assignc return self.add_instruction_condition(assignment + wbu) + @armregistry.register_tag("STRH", ARMOpcode) class ARMStoreRegisterHalfword(ARMOpcode): """Stores the least significant halfword from a register into memory. @@ -118,15 +179,8 @@ class ARMStoreRegisterHalfword(ARMOpcode): args[3]: index of memory location in armdictionary args[4]: is-wide (thumb) - xdata format: a:vxxxxrrrdh - -------------------------- - vars[0]: lhs - xprs[0]: xrn (base register) - xprs[1]: xrm (index) - xprs[2]: xrt (rhs, source register) - xprs[3]: xrt (rhs, simplified) - xprs[4]: address of memory location - xprs[5]: condition (if TC is set) + xdata format: + ------------- rdefs[0]: rn rdefs[1]: rm rdefs[2]: rt @@ -193,24 +247,40 @@ def ast_prov( xd = ARMStoreRegisterHalfwordXData(xdata) - if xd.is_ok: + if xd.is_cvmem_ok: + lhs = xd.cvmem + hl_lhs = XU.xvariable_to_ast_lval(lhs, xdata, iaddr, astree) + + elif xd.is_vmem_ok: lhs = xd.vmem - memaddr = xd.xaddr - hl_lhs = XU.xvariable_to_ast_lval( - lhs, xdata, iaddr, astree, memaddr=memaddr) + hl_lhs = XU.xvariable_to_ast_lval(lhs, xdata, iaddr, astree) - elif xd.is_vmem_unknown and xd.is_address_known: + elif xd.is_cxaddr_ok: + memaddr = xd.cxaddr + hl_lhs = XU.xmemory_dereference_lval(memaddr, xdata, iaddr, astree) + + elif xd.is_xxaddr_ok: + memaddr = xd.xxaddr + hl_lhs = XU.xmemory_dereference_lval(memaddr, xdata, iaddr, astree) + + elif xd.is_xaddr_ok: memaddr = xd.xaddr hl_lhs = XU.xmemory_dereference_lval(memaddr, xdata, iaddr, astree) else: chklogger.logger.error( "STRH: Lhs lval and address both have error values: skipping " - + "store instruction at address %s", - iaddr) - return ([], []) + "store instruction at address %s", iaddr) + return ([], (ll_preinstrs + [ll_assign] + ll_postinstrs)) + + if xd.is_cxrt_ok: + rhs = xd.cxrt + elif xd.is_xxrt_ok: + rhs = xd.xxrt + else: + rhs = xd.xrt + hl_rhs = XU.xxpr_to_ast_def_expr(rhs, xdata, iaddr, astree) - rhs = xd.xxrt rdefs = xdata.reachingdefs defuses = xdata.defuses defuseshigh = xdata.defuseshigh @@ -228,7 +298,7 @@ def ast_prov( # to variables that are part of a struct or array variable, so these # assignments must be explicitly forced to appear in the lifting if ( - xd.is_vmem_unknown + (not xd.is_vmem_ok) or lhs.is_memory_variable and cast("VMemoryVariable", lhs.denotation).base.is_basevar or hl_lhs.offset.is_index_offset @@ -282,4 +352,4 @@ def ast_prov( ll_assigns = [ll_assign] hl_assigns = [hl_assign] - return (hl_assigns, ll_assigns) + return (hl_assigns, (ll_preinstrs + ll_assigns + ll_postinstrs)) diff --git a/chb/arm/opcodes/ARMSubtract.py b/chb/arm/opcodes/ARMSubtract.py index 0ba20cbb..9c7c85f9 100644 --- a/chb/arm/opcodes/ARMSubtract.py +++ b/chb/arm/opcodes/ARMSubtract.py @@ -50,6 +50,19 @@ class ARMSubtractXData(ARMOpcodeXData): + """Data format: + - variables: + 0: vrd + + - expressions: + 0: xrn + 1: xrm + 2: result + 3: rresult (result rewritten) + + - c expressions: + 0: cresult + """ def __init__(self, xdata: InstrXData) -> None: ARMOpcodeXData.__init__(self, xdata) @@ -70,18 +83,41 @@ def xrm(self) -> "XXpr": def result(self) -> "XXpr": return self.xpr(2, "result") + @property + def is_result_ok(self) -> bool: + return self.is_xpr_ok(2) + @property def rresult(self) -> "XXpr": return self.xpr(3, "rresult") + @property + def is_rresult_ok(self) -> bool: + return self.is_xpr_ok(3) + + @property + def cresult(self) -> "XXpr": + return self.cxpr(0, "cresult") + + @property + def is_cresult_ok(self) -> bool: + return self.is_cxpr_ok(0) + @property def result_simplified(self) -> str: - return simplify_result( - self.xdata.args[3], self.xdata.args[4], self.result, self.rresult) + if self.is_result_ok and self.is_rresult_ok: + return simplify_result( + self.xdata.args[3], self.xdata.args[4], self.result, self.rresult) + else: + return str(self.xrn) + " - " + str(self.xrm) @property def annotation(self) -> str: - assignment = str(self.vrd) + " := " + self.result_simplified + cresult = ( + " (C: " + + (str(self.cresult) if self.is_cresult_ok else "None") + + ")") + assignment = str(self.vrd) + " := " + self.result_simplified + cresult return self.add_instruction_condition(assignment) @@ -100,13 +136,8 @@ class ARMSubtract(ARMOpcode): args[4]: is-wide (thumb) args[5]: wide - xdata format: a:vxxxxrrdh - ------------------------- - vars[0]: lhs (Rd) - xprs[0]: rhs1 (Rn) - xprs[1]: rhs2 (Rm) - xprs[2]: rhs1 - rhs2 - xprs[3]: rhs1 - rhs2 (simplified) + xdata format: + ------------- rdefs[0]: rhs1 rdefs[1]: rhs2 rdefs[2..]: reaching definitions for simplified result @@ -146,10 +177,7 @@ def is_writeback(self) -> bool: def annotation(self, xdata: InstrXData) -> str: xd = ARMSubtractXData(xdata) - if xd.is_ok: - return xd.annotation - else: - return "Error value" + return xd.annotation def ast_prov( self, @@ -183,14 +211,27 @@ def ast_prov( # high-level assignment xd = ARMSubtractXData(xdata) - if not xd.is_ok: - chklogger.logger.error("Error value encountered at %s", iaddr) - return ([], []) + + if xd.is_cresult_ok and xd.is_rresult_ok: + rhs = xd.cresult + xrhs = xd.rresult + + elif xd.is_rresult_ok: + rhs = xd.rresult + xrhs = xd.rresult + + elif xd.is_result_ok: + rhs = xd.result + xrhs = xd.result + + else: + chklogger.logger.error( + "SUB: Encountered error value for rhs at address %s", iaddr) + return ([], [ll_assign]) lhs = xd.vrd rhs1 = xd.xrn rhs2 = xd.xrm - rhs3 = xd.rresult defuses = xdata.defuses defuseshigh = xdata.defuseshigh @@ -198,22 +239,22 @@ def ast_prov( hl_lhs = XU.xvariable_to_ast_lval(lhs, xdata, iaddr, astree) # resulting expression is a stack address - if str(rhs1) == "SP" and rhs3.is_stack_address: + if str(rhs1) == "SP" and xrhs.is_stack_address: annotations.append("stack address") - rhs3 = cast("XprCompound", rhs3) - stackoffset = rhs3.stack_address_offset() + xrhs = cast("XprCompound", xrhs) + stackoffset = xrhs.stack_address_offset() rhslval = astree.mk_stack_variable_lval(stackoffset) hl_rhs: AST.ASTExpr = astree.mk_address_of(rhslval) elif str(rhs1) == "PC" or str(rhs2) == "PC": annotations.append("PC-relative") - if rhs3.is_int_constant: - rhsval = cast("XprConstant", rhs3).intvalue + if xrhs.is_int_constant: + rhsval = cast("XprConstant", xrhs).intvalue rhsast = astree.mk_integer_constant(rhsval) else: - hl_rhs = XU.xxpr_to_ast_def_expr(rhs3, xdata, iaddr, astree) + hl_rhs = XU.xxpr_to_ast_def_expr(rhs, xdata, iaddr, astree) else: - hl_rhs = XU.xxpr_to_ast_def_expr(rhs3, xdata, iaddr, astree) + hl_rhs = XU.xxpr_to_ast_def_expr(rhs, xdata, iaddr, astree) hl_assign = astree.mk_assign( hl_lhs, diff --git a/chb/ast/ASTNode.py b/chb/ast/ASTNode.py index c571ea0a..2ce74022 100644 --- a/chb/ast/ASTNode.py +++ b/chb/ast/ASTNode.py @@ -2772,6 +2772,9 @@ def is_union(self) -> bool: def is_compinfo(self) -> bool: return True + def has_fields(self) -> bool: + return len(self.fieldinfos) > 0 + def has_field_offsets(self) -> bool: return all(finfo.has_byteoffset() for finfo in self.fieldinfos) diff --git a/chb/astinterface/ASTICodeTransformer.py b/chb/astinterface/ASTICodeTransformer.py index 827582da..661a2c7c 100644 --- a/chb/astinterface/ASTICodeTransformer.py +++ b/chb/astinterface/ASTICodeTransformer.py @@ -4,7 +4,7 @@ # ------------------------------------------------------------------------------ # The MIT License (MIT) # -# Copyright (c) 2022-2024 Aarno Labs LLC +# Copyright (c) 2022-2025 Aarno Labs LLC # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -85,15 +85,14 @@ def transform_instruction_sequence_stmt( and not self.provenance.has_expose_instruction(instr.instrid)): chklogger.logger.info( "Remove [%s]: has ssa value", str(instr)) - continue - if self.provenance.has_active_lval_defuse_high(instr.lhs.lvalid): - chklogger.logger.debug( + elif self.provenance.has_active_lval_defuse_high(instr.lhs.lvalid): + chklogger.logger.info( "Transform [%s]: active lval_defuse_high: %s", str(instr), self.provenance.active_lval_defuse_high(instr.lhs.lvalid)) instrs.append(instr) elif self.provenance.has_lval_store(instr.lhs.lvalid): - chklogger.logger.debug( + chklogger.logger.info( "Transform [%s]: lval_store", str(instr)) instrs.append(instr) elif self.provenance.has_expose_instruction(instr.instrid): @@ -101,12 +100,14 @@ def transform_instruction_sequence_stmt( "Transform [%s]: expose instruction", str(instr)) instrs.append(instr) elif instr.lhs.lhost.is_global: - chklogger.logger.debug( - "Transfor [%s]: global lhs", str(instr)) + chklogger.logger.info( + "Transform [%s]: global lhs", str(instr)) instrs.append(instr) else: chklogger.logger.info("Transform [%s]: remove", str(instr)) else: + chklogger.logger.info( + "Transform [%s]: include by default", str(instr)) instrs.append(instr) return self.astinterface.mk_instr_sequence( instrs, diff --git a/chb/cmdline/chkx b/chb/cmdline/chkx index b257e8ea..a9fa4c38 100755 --- a/chb/cmdline/chkx +++ b/chb/cmdline/chkx @@ -612,6 +612,9 @@ def parse() -> argparse.Namespace: "--opcodes", help=("json filename (without extension) to save opcode distribution " + "stats (for instructions within analyzed functions)")) + resultsstats.add_argument( + "--tagfile", + help="name of json file that has function tags") resultsstats.add_argument( "--loglevel", "-log", choices=UL.LogLevel.options(), diff --git a/chb/cmdline/commandutil.py b/chb/cmdline/commandutil.py index 7be9a075..8ff2d11c 100644 --- a/chb/cmdline/commandutil.py +++ b/chb/cmdline/commandutil.py @@ -619,6 +619,7 @@ def results_stats(args: argparse.Namespace) -> NoReturn: sortby: str = args.sortby timeshare: int = args.timeshare opcodes: str = args.opcodes + tagfile: Optional[str] = args.tagfile loglevel: str = args.loglevel logfilename: Optional[str] = args.logfilename logfilemode: str = args.logfilemode @@ -637,6 +638,23 @@ def results_stats(args: argparse.Namespace) -> NoReturn: mode=logfilemode, msg="results stats invoked") + tagdata: Dict[str, Any] = {} + if tagfile is not None: + with open(tagfile, "r") as fp: + tagdata = json.load(fp) + + functiontags: Dict[str, List[str]] = {} + + if "function-tags" in tagdata: + functiontags = tagdata["function-tags"] + + maxlen = 0 + for (faddr, keys) in functiontags.items(): + taglen = len(",".join(keys)) + if taglen > maxlen: + maxlen = taglen + maxlen = maxlen + 4 if maxlen > 0 else 0 + xinfo = XI.XInfo() xinfo.load(path, xfile) @@ -647,7 +665,7 @@ def results_stats(args: argparse.Namespace) -> NoReturn: if sortby == "instrs": sortkey = lambda f: f.instruction_count elif sortby == "basicblocks": - sortkey = lambda f: f.block_count + sortkey = lambda f: (f.block_count, f.instruction_count, int(f.faddr, 16)) elif sortby == "loopdepth": sortkey = lambda f: f.loop_depth elif sortby == "time": @@ -655,7 +673,14 @@ def results_stats(args: argparse.Namespace) -> NoReturn: else: sortkey = lambda f: int(f.faddr, 16) for f in sorted(stats.get_function_results(), key=sortkey): - print(f.metrics_to_string(shownocallees=nocallees)) + if f.faddr in functiontags: + fn_tags = functiontags[f.faddr] + else: + fn_tags = [] + if "hide" in fn_tags: + continue + print(f.metrics_to_string(shownocallees=nocallees, + tags=fn_tags, taglen=maxlen)) print(stats.disassembly_to_string()) print(stats.analysis_to_string()) diff --git a/chb/invariants/VMemoryOffset.py b/chb/invariants/VMemoryOffset.py index f5e59ab0..1b9bebce 100644 --- a/chb/invariants/VMemoryOffset.py +++ b/chb/invariants/VMemoryOffset.py @@ -36,6 +36,7 @@ | FieldOffset of string * int * memory_offset_t "f" 2 2 | IndexOffset of variable_t * int * memory_offset_t "i" 1 3 | ArrayIndexOffset of xpr_t * memory_offset_t "a" 1 2 + | BasePtrArrayIndexOffset of xpr_t * memory_offset_t "p" 1 2 | UnknownOffset "u" 1 0 """ @@ -84,6 +85,10 @@ def is_index_offset(self) -> bool: def is_array_index_offset(self) -> bool: return False + @property + def is_baseptr_array_index_offset(self) -> bool: + return False + @property def is_no_offset(self) -> bool: return False @@ -388,6 +393,39 @@ def __str__(self) -> str: return "[" + str(self.index_expression) + "]" + str(self.offset) +@varregistry.register_tag("p", VMemoryOffset) +class VMemoryOffsetBasePtrArrayIndexOffset(VMemoryOffset): + """Array index offset + + args[0]: index of index expression in xprdictionary + args[1]: index of next-level offset in vardictionary + """ + + def __init__( + self, + vd: "FnVarDictionary", + ixval: IndexedTableValue) -> None: + VMemoryOffset.__init__(self, vd, ixval) + + @property + def index_expression(self) -> "XXpr": + return self.xd.xpr(self.args[0]) + + @property + def offset(self) -> VMemoryOffset: + return self.vd.memory_offset(self.args[1]) + + @property + def is_baseptr_array_index_offset(self) -> bool: + return True + + def has_no_offset(self) -> bool: + return self.offset.is_no_offset + + def __str__(self) -> str: + return "[" + str(self.index_expression) + "]" + str(self.offset) + + @varregistry.register_tag("u", VMemoryOffset) class VMemoryOffsetUnknown(VMemoryOffset): diff --git a/chb/invariants/XXprUtil.py b/chb/invariants/XXprUtil.py index cbefa0ea..b899f93b 100644 --- a/chb/invariants/XXprUtil.py +++ b/chb/invariants/XXprUtil.py @@ -122,6 +122,7 @@ VMemoryOffsetConstantOffset, VMemoryOffsetFieldOffset, VMemoryOffsetArrayIndexOffset, + VMemoryOffsetBasePtrArrayIndexOffset, VMemoryOffsetIndexOffset) from chb.mips.MIPSRegister import MIPSRegister @@ -358,6 +359,21 @@ def field_pointer_to_ast_memref_expr( subfoffset: AST.ASTOffset = nooffset compinfo = astree.compinfo(compkey) + + if not compinfo.has_fields(): + if not anonymous: + chklogger.logger.error( + "Struct definition is missing for %s at address %s (no fields found)", + compinfo.compname, iaddr) + return astree.mk_temp_lval_expression() + + if not compinfo.has_field_offsets(): + if not anonymous: + chklogger.logger.error( + "Struct definition for %s does not have field offsets at address %s", + compinfo.compname, iaddr) + return astree.mk_temp_lval_expression() + (field, restoffset) = compinfo.field_at_offset(offset) if restoffset > 0: if field.fieldtype.is_compound: @@ -422,7 +438,10 @@ def memory_variable_to_lval_expression( return astree.mk_memref_expr( astbase, offset=astoffset, anonymous=anonymous) - else: + elif ( + offset.is_field_offset + or offset.is_array_index_offset + or offset.is_constant_value_offset): astlval = xvariable_to_ast_def_lval_expression( base.basevar, xdata, iaddr, astree, anonymous=anonymous) if offset.is_field_offset: @@ -436,10 +455,27 @@ def memory_variable_to_lval_expression( elif offset.is_constant_value_offset: astoffset = astree.mk_scalar_index_offset(offset.offsetvalue()) else: + chklogger.logger.warning( + "Offset %s not yet handled at address %s", + str(offset), iaddr) astoffset = nooffset return astree.mk_memref_expr( astlval, offset=astoffset, anonymous=anonymous) + elif offset.is_baseptr_array_index_offset: + astlval = xvariable_to_ast_def_lval_expression( + base.basevar, xdata, iaddr, astree, anonymous=anonymous) + offset = cast("VMemoryOffsetBasePtrArrayIndexOffset", offset) + (ptroffset, astoffset) = base_ptr_array_offset_to_ast_offset( + offset, xdata, iaddr, astree, anonymous=anonymous) + if ptroffset.is_integer_constant_zero: + return astree.mk_memref_expr( + astlval, offset=astoffset, anonymous=anonymous) + else: + ptrexpr = astree.mk_binary_op("plus", ptroffset, astlval) + return astree.mk_memref_expr( + ptrexpr, offset=astoffset, anonymous=anonymous) + name = str(base) if not astree.globalsymboltable.has_symbol(name): @@ -750,11 +786,6 @@ def vinitmemory_value_to_ast_lval_expression( return vglobal_variable_value_to_ast_lval_expression( avar.offset, xdata, iaddr, astree, size=size, anonymous=anonymous) - if vconstvar.is_argument_deref_value: - avar = vconstvar.variable.denotation - return vargument_deref_value_to_ast_lval_expression( - avar.basevar, avar.offset, xdata, iaddr, astree, anonymous=anonymous) - if vconstvar.is_function_return_deref_value: avar = vconstvar.variable.denotation return vreturn_deref_value_to_ast_lval_expression( @@ -1289,6 +1320,22 @@ def default() -> AST.ASTExpr: compkey = cast(AST.ASTTypComp, hl_addr_tgttype).compkey compinfo = astree.compinfo(compkey) + if not compinfo.has_fields(): + if not anonymous: + chklogger.logger.error( + "Struct definition is missing for %s at address %s " + + "(no fields found)", + compinfo.compname, iaddr) + return astree.mk_temp_lval_expression() + + if not compinfo.has_field_offsets(): + if not anonymous: + chklogger.logger.error( + "Struct definition for %s does not have field offsets " + + "at address %s", + compinfo.compname, iaddr) + return astree.mk_temp_lval_expression() + (field, _) = compinfo.field_at_offset(0) fieldoffset = astree.mk_field_offset(field.fieldname, compkey) return astree.mk_memref_expr( @@ -1331,6 +1378,22 @@ def default() -> AST.ASTExpr: compkey = cast(AST.ASTTypComp, exp1tgttype).compkey compinfo = astree.compinfo(compkey) + if not compinfo.has_fields(): + if not anonymous: + chklogger.logger.error( + "Struct definition is missing for %s at address %s " + + "(no fields found)", + compinfo.compname, iaddr) + return astree.mk_temp_lval_expression() + + if not compinfo.has_field_offsets(): + if not anonymous: + chklogger.logger.error( + "Struct definition for %s does not have field offsets " + + "at address %s", + compinfo.compname, iaddr) + return astree.mk_temp_lval_expression() + scalaroffset = cast(AST.ASTIntegerConstant, exp2).cvalue (field, rem) = compinfo.field_at_offset(scalaroffset) if rem > 0: @@ -1457,6 +1520,25 @@ def stack_variable_to_ast_lval( return astree.mk_temp_lval() +def base_ptr_array_offset_to_ast_offset( + offset: "VMemoryOffsetBasePtrArrayIndexOffset", + xdata: "InstrXData", + iaddr: str, + astree: ASTInterface, + anonymous: bool = False) -> Tuple[AST.ASTExpr, AST.ASTOffset]: + + indexxpr = xxpr_to_ast_def_expr( + offset.index_expression, xdata, iaddr, astree, anonymous=anonymous) + + if offset.has_no_offset() and indexxpr.is_integer_constant: + return (indexxpr, nooffset) + + chklogger.logger.error( + "Base ptr array offset %s not yet handled at address %s", + str(offset), iaddr) + return (astree.mk_integer_constant(0), nooffset) + + def array_offset_to_ast_offset( offset: "VMemoryOffsetArrayIndexOffset", xdata: "InstrXData", @@ -1633,8 +1715,7 @@ def xvariable_to_ast_lval( if ( rhs is not None and (rhs.is_constant - or (rhs.is_constant_value_variable - and not rhs.is_function_return_value))): + or (rhs.is_constant_value_variable))): astrhs: Optional[AST.ASTExpr] = xxpr_to_ast_def_expr( rhs, xdata, iaddr, astree, anonymous=anonymous) else: