(self, irsb, function)
At the end of a basic block, simulate the very last instruction to see if the return address is read from the
        stack and written in PC. If so, the jumpkind of this IRSB will be set to Ijk_Ret. For detailed explanations,
        please see the documentation of _arm_track_lr_on_stack().

        :param pyvex.IRSB irsb: The basic block object.
        :param Function function: The function instance.
        :return: None
At the end of a basic block, simulate the very last instruction to see if the return address is read from the
        stack and written in PC. If so, the jumpkind of this IRSB will be set to Ijk_Ret. For detailed explanations,
        please see the documentation of _arm_track_lr_on_stack().
At the end of a basic block simulate the very last instruction to see if the return address is read from the stack and written in PC . If so the jumpkind of this IRSB will be set to Ijk_Ret . For detailed explanations please see the documentation of _arm_track_lr_on_stack () .
def _arm_track_read_lr_from_stack(self, irsb, function):  # pylint:disable=unused-argument
        """
        At the end of a basic block, simulate the very last instruction to see if the return address is read from the
        stack and written in PC. If so, the jumpkind of this IRSB will be set to Ijk_Ret. For detailed explanations,
        please see the documentation of _arm_track_lr_on_stack().

        :param pyvex.IRSB irsb: The basic block object.
        :param Function function: The function instance.
        :return: None
        """

        if 'lr_saved_on_stack' not in function.info or not function.info['lr_saved_on_stack']:
            return

        sp_offset = self.project.arch.sp_offset
        initial_sp = 0x7fff0000
        last_sp = None
        tmps = {}
        tmp_irsb = self._lift(irsb.instruction_addresses[-1]).vex
        # pylint:disable=too-many-nested-blocks
        for stmt in tmp_irsb.statements:
            if isinstance(stmt, pyvex.IRStmt.WrTmp):
                data = stmt.data
                if isinstance(data, pyvex.IRExpr.Get) and data.offset == sp_offset:
                    # t0 = GET:I32(sp)
                    tmps[stmt.tmp] = initial_sp
                elif isinstance(data, pyvex.IRExpr.Binop):
                    # only support Add
                    if data.op == 'Iop_Add32':
                        arg0, arg1 = data.args
                        if isinstance(arg0, pyvex.IRExpr.RdTmp) and isinstance(arg1, pyvex.IRExpr.Const):
                            if arg0.tmp in tmps:
                                tmps[stmt.tmp] = tmps[arg0.tmp] + arg1.con.value
                elif isinstance(data, pyvex.IRExpr.Load):
                    if isinstance(data.addr, pyvex.IRExpr.RdTmp):
                        if data.addr.tmp in tmps:
                            tmps[stmt.tmp] = ('load', tmps[data.addr.tmp])
            elif isinstance(stmt, pyvex.IRStmt.Put):
                if stmt.offset == sp_offset and isinstance(stmt.data, pyvex.IRExpr.RdTmp):
                    if stmt.data.tmp in tmps:
                        # loading things into sp
                        last_sp = tmps[stmt.data.tmp]

        if last_sp is not None and isinstance(tmp_irsb.next, pyvex.IRExpr.RdTmp):
            val = tmps.get(tmp_irsb.next.tmp, None)
            # val being None means there are statements that we do not handle
            if isinstance(val, tuple) and val[0] == 'load':
                # the value comes from memory
                memory_addr = val[1]
                if isinstance(last_sp, int):
                    lr_on_stack_offset = memory_addr - last_sp
                else:
                    lr_on_stack_offset = memory_addr - last_sp[1]

                if lr_on_stack_offset == function.info['lr_on_stack_offset']:
                    # the jumpkind should be Ret instead of boring
                    irsb.jumpkind = 'Ijk_Ret'
def _arm_track_read_lr_from_stack ( self , irsb , function ) : # pylint:disable=unused-argument if 'lr_saved_on_stack' not in function . info or not function . info [ 'lr_saved_on_stack' ] : return sp_offset = self . project . arch . sp_offset initial_sp = 0x7fff0000 last_sp = None tmps = { } tmp_irsb = self . _lift ( irsb . instruction_addresses [ - 1 ] ) . vex # pylint:disable=too-many-nested-blocks for stmt in tmp_irsb . statements : if isinstance ( stmt , pyvex . IRStmt . WrTmp ) : data = stmt . data if isinstance ( data , pyvex . IRExpr . Get ) and data . offset == sp_offset : # t0 = GET:I32(sp) tmps [ stmt . tmp ] = initial_sp elif isinstance ( data , pyvex . IRExpr . Binop ) : # only support Add if data . op == 'Iop_Add32' : arg0 , arg1 = data . args if isinstance ( arg0 , pyvex . IRExpr . RdTmp ) and isinstance ( arg1 , pyvex . IRExpr . Const ) : if arg0 . tmp in tmps : tmps [ stmt . tmp ] = tmps [ arg0 . tmp ] + arg1 . con . value elif isinstance ( data , pyvex . IRExpr . Load ) : if isinstance ( data . addr , pyvex . IRExpr . RdTmp ) : if data . addr . tmp in tmps : tmps [ stmt . tmp ] = ( 'load' , tmps [ data . addr . tmp ] ) elif isinstance ( stmt , pyvex . IRStmt . Put ) : if stmt . offset == sp_offset and isinstance ( stmt . data , pyvex . IRExpr . RdTmp ) : if stmt . data . tmp in tmps : # loading things into sp last_sp = tmps [ stmt . data . tmp ] if last_sp is not None and isinstance ( tmp_irsb . next , pyvex . IRExpr . RdTmp ) : val = tmps . get ( tmp_irsb . next . tmp , None ) # val being None means there are statements that we do not handle if isinstance ( val , tuple ) and val [ 0 ] == 'load' : # the value comes from memory memory_addr = val [ 1 ] if isinstance ( last_sp , int ) : lr_on_stack_offset = memory_addr - last_sp else : lr_on_stack_offset = memory_addr - last_sp [ 1 ] if lr_on_stack_offset == function . info [ 'lr_on_stack_offset' ] : # the jumpkind should be Ret instead of boring irsb . jumpkind = 'Ijk_Ret'