diff --git a/chb/app/CHVersion.py b/chb/app/CHVersion.py index a6853405..49999518 100644 --- a/chb/app/CHVersion.py +++ b/chb/app/CHVersion.py @@ -1 +1 @@ -chbversion: str = "0.3.0-20250309" +chbversion: str = "0.3.0-20250312" diff --git a/chb/arm/opcodes/ARMMultiply.py b/chb/arm/opcodes/ARMMultiply.py index cce36cb9..01069527 100644 --- a/chb/arm/opcodes/ARMMultiply.py +++ b/chb/arm/opcodes/ARMMultiply.py @@ -25,7 +25,7 @@ # SOFTWARE. # ------------------------------------------------------------------------------ -from typing import List, TYPE_CHECKING +from typing import List, Tuple, TYPE_CHECKING from chb.app.InstrXData import InstrXData @@ -33,6 +33,11 @@ from chb.arm.ARMOpcode import ARMOpcode, ARMOpcodeXData, simplify_result from chb.arm.ARMOperand import ARMOperand +import chb.ast.ASTNode as AST +from chb.astinterface.ASTInterface import ASTInterface + +import chb.invariants.XXprUtil as XU + import chb.util.fileutil as UF from chb.util.IndexedTable import IndexedTableValue from chb.util.loggingutil import chklogger @@ -67,7 +72,7 @@ def result(self) -> "XXpr": @property def rresult(self) -> "XXpr": - return self.xpr(3, "result") + return self.xpr(3, "rresult") @property def result_simplified(self) -> str: @@ -101,9 +106,78 @@ def __init__(self, d: "ARMDictionary", ixval: IndexedTableValue) -> None: def operands(self) -> List[ARMOperand]: return [self.armd.arm_operand(i) for i in self.args[1:]] + @property + def opargs(self) -> List[ARMOperand]: + return [self.armd.arm_operand(i) for i in self.args[1:]] + def annotation(self, xdata: InstrXData) -> str: xd = ARMMultiplyXData(xdata) if xd.is_ok: return xd.annotation else: return "Error value" + + def ast_prov( + self, + astree: ASTInterface, + iaddr: str, + bytestring: str, + xdata: InstrXData) -> Tuple[ + List[AST.ASTInstruction], List[AST.ASTInstruction]]: + + annotations: List[str] = [iaddr, "MUL"] + + # low-level assignment + + (ll_lhs, _, _) = self.opargs[0].ast_lvalue(astree) + (ll_op1, _, _) = self.opargs[1].ast_rvalue(astree) + (ll_op2, _, _) = self.opargs[2].ast_rvalue(astree) + ll_rhs = astree.mk_binary_op("mult", ll_op1, ll_op2) + + ll_assign = astree.mk_assign( + ll_lhs, + ll_rhs, + iaddr=iaddr, + bytestring=bytestring, + annotations=annotations) + + rdefs = xdata.reachingdefs + + astree.add_expr_reachingdefs(ll_op1, [rdefs[0]]) + astree.add_expr_reachingdefs(ll_op2, [rdefs[1]]) + + # 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 + + 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_assign = astree.mk_assign( + hl_lhs, + hl_rhs, + iaddr=iaddr, + bytestring=bytestring, + annotations=annotations) + + astree.add_instr_mapping(hl_assign, ll_assign) + astree.add_instr_address(hl_assign, [iaddr]) + astree.add_expr_mapping(hl_rhs, ll_rhs) + astree.add_lval_mapping(hl_lhs, ll_lhs) + astree.add_expr_reachingdefs(hl_rhs, rdefs[2:]) + astree.add_expr_reachingdefs(ll_rhs, rdefs[:2]) + astree.add_lval_defuses(hl_lhs, defuses[0]) + astree.add_lval_defuses_high(hl_lhs, defuseshigh[0]) + + return ([hl_assign], [ll_assign]) diff --git a/chb/arm/opcodes/ARMStoreMultipleIncrementAfter.py b/chb/arm/opcodes/ARMStoreMultipleIncrementAfter.py index f568e76c..58838f5c 100644 --- a/chb/arm/opcodes/ARMStoreMultipleIncrementAfter.py +++ b/chb/arm/opcodes/ARMStoreMultipleIncrementAfter.py @@ -417,6 +417,12 @@ def ast_prov( if xdata.instruction_subsumes(): return self.ast_prov_ldmstmcopy(astree, iaddr, bytestring, xdata) + else: + chklogger.logger.error( + "AST conversion of STM not yet supported at address %s", + iaddr) + return ([], []) + regcount = len(xdata.reachingdefs) - 1 baselhs = xdata.vars[0] memlhss = xdata.vars[1:] diff --git a/chb/ast/ASTCPrettyPrinter.py b/chb/ast/ASTCPrettyPrinter.py index e237cca5..b02d51f8 100644 --- a/chb/ast/ASTCPrettyPrinter.py +++ b/chb/ast/ASTCPrettyPrinter.py @@ -151,7 +151,7 @@ def write_local_declarations(self, referenced: Set[str]) -> None: and not self.localsymboltable.is_formal(vinfo.vname)): self.ccode.newline(indent=self.indent) if vinfo.vtype is None: - self.ccode.write("? " + vinfo.vname) + self.ccode.write("? " + vinfo.vname + ";") continue if vinfo.vtype.is_array: @@ -185,14 +185,19 @@ def write_global_declarations(self) -> None: continue self.ccode.newline(indent=self.indent) if vinfo.vtype is None: - self.ccode.write("? " + vinfo.vname) + self.ccode.write("? " + vinfo.vname + ";") continue if vinfo.vtype.is_function: ftype = cast(AST.ASTTypFun, vinfo.vtype) - ftype.returntyp.accept(self) - self.ccode.write(" ") - self.ccode.write(vinfo.vname) + if ftype.returntyp.is_function_pointer: + returntyp = cast(AST.ASTTypPtr, ftype.returntyp) + fnptr = cast(AST.ASTTypFun, returntyp.tgttyp) + self.funtypptr_with_name(fnptr, vinfo.vname) + else: + ftype.returntyp.accept(self) + self.ccode.write(" ") + self.ccode.write(vinfo.vname) self.ccode.write("(") if ftype.argtypes is not None: ftype.argtypes.accept(self) @@ -608,10 +613,28 @@ def visit_fun_typ(self, t: AST.ASTTypFun) -> None: t.argtypes.accept(self) self.ccode.write(")") + def funtypptr_with_name(self, t: AST.ASTTypFun, name: str) -> None: + if t.returntyp.is_function_pointer: + returntyp = cast(AST.ASTTypPtr, t.returntyp) + retty = cast(AST.ASTTypFun, returntyp.tgttyp) + self.funtypptr_with_name(retty, name) + self.ccode.write("(") + if t.argtypes is not None: + t.argtypes.accept(self) + self.ccode.write(")") + else: + t.returntyp.accept(self) + self.ccode.write(" (*") + self.ccode.write(name) + self.ccode.write(")(") + if t.argtypes is not None: + t.argtypes.accept(self) + self.ccode.write(")") + def visit_funargs(self, funargs: AST.ASTFunArgs) -> None: args = funargs.funargs if len(args) == 0: - pass + self.ccode.write("void") else: for arg in args[:-1]: arg.accept(self) @@ -619,9 +642,14 @@ def visit_funargs(self, funargs: AST.ASTFunArgs) -> None: args[-1].accept(self) def visit_funarg(self, funarg: AST.ASTFunArg) -> None: - funarg.argtyp.accept(self) - self.ccode.write(" ") - self.ccode.write(funarg.argname) + if funarg.argtyp.is_function_pointer: + argtyp = cast(AST.ASTTypPtr, funarg.argtyp) + fnptr = cast(AST.ASTTypFun, argtyp.tgttyp) + self.funtypptr_with_name(fnptr, funarg.argname) + else: + funarg.argtyp.accept(self) + self.ccode.write(" ") + self.ccode.write(funarg.argname) def visit_named_typ(self, t: AST.ASTTypNamed) -> None: self.ccode.write("typedef ") @@ -649,6 +677,11 @@ def visit_compinfo(self, cinfo: AST.ASTCompInfo) -> None: if atype.size_expr is not None: atype.size_expr.accept(self) self.ccode.write("];") + elif finfo.fieldtype.is_function_pointer: + fieldtyp = cast(AST.ASTTypPtr, finfo.fieldtype) + funtyp = cast(AST.ASTTypFun, fieldtyp.tgttyp) + self.funtypptr_with_name(funtyp, finfo.fieldname) + self.ccode.write(";") else: finfo.fieldtype.accept(self) self.ccode.write(" ") diff --git a/chb/ast/ASTNode.py b/chb/ast/ASTNode.py index bc0b2fd5..c571ea0a 100644 --- a/chb/ast/ASTNode.py +++ b/chb/ast/ASTNode.py @@ -2242,6 +2242,10 @@ def is_pointer(self) -> bool: def is_void_pointer(self) -> bool: return False + @property + def is_function_pointer(self) -> bool: + return False + @property def is_scalar(self) -> bool: return ( @@ -2394,6 +2398,10 @@ def is_pointer(self) -> bool: def is_void_pointer(self) -> bool: return self.tgttyp.is_void + @property + def is_function_pointer(self) -> bool: + return self.tgttyp.is_function + def accept(self, visitor: "ASTVisitor") -> None: return visitor.visit_pointer_typ(self) diff --git a/chb/ast/astutil.py b/chb/ast/astutil.py index 5081e774..eeda4420 100644 --- a/chb/ast/astutil.py +++ b/chb/ast/astutil.py @@ -4,7 +4,7 @@ # ------------------------------------------------------------------------------ # The MIT License (MIT) # -# Copyright (c) 2023 Aarno Labs LLC +# Copyright (c) 2023-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 @@ -358,7 +358,7 @@ def parsecmd(args: argparse.Namespace) -> NoReturn: parsemanager.parse_ifile(ifile) for (faddr, dfn) in functions.items(): - fname = faddr.replace("0x", "sub_") + fname = faddr xpath = os.path.join(cname, "functions") xpath = os.path.join(xpath, fname) xfile = os.path.join(xpath, cname + "_" + fname + "_cfun.xml") @@ -381,6 +381,4 @@ def parsecmd(args: argparse.Namespace) -> NoReturn: xsbody = rootnode.find("sbody") - - exit(0)