<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def _arm_track_lr_on_stack(self, addr, irsb, function):
 """ At the beginning of the basic block, we check if the first instruction stores the LR register onto the stack. If it does, we calculate the offset of that store, and record the offset in function.info. For instance, here is the disassembly of a THUMB mode function: 000007E4 STR.W LR, [SP,#var_4]! 000007E8 MOV R2, R1 000007EA SUB SP, SP, #0xC 000007EC MOVS R1, #0 00000800 ADD SP, SP, #0xC 00000802 LDR.W PC, [SP+4+var_4],#4 The very last basic block has a jumpkind of Ijk_Boring, which is because VEX cannot do such complicated analysis to determine the real jumpkind. As we can see, instruction 7e4h stores LR at [sp-4], and at the end of this function, instruction 802 loads LR from [sp], then increments sp by 4. We execute the first instruction, and track the following things: - if the value from register LR is stored onto the stack. - the difference between the offset of the LR store on stack, and the SP after the store. If at the end of the function, the LR is read out from the stack at the exact same stack offset, we will change the jumpkind of the final IRSB to Ijk_Ret. This method can be enabled by setting "ret_jumpkind_heuristics", which is an architecture-specific option on ARM, to True. :param int addr: Address of the basic block. :param pyvex.IRSB irsb: The basic block object. :param Function function: The function instance. :return: None """


        if irsb.statements is None:
            return

        if 'lr_saved_on_stack' in function.info:
            return

        # if it does, we log it down to the Function object.
        lr_offset = self.project.arch.registers['lr'][0]
        sp_offset = self.project.arch.sp_offset
        initial_sp = 0x7fff0000
        initial_lr = 0xabcdef
        tmps = {}

        # pylint:disable=too-many-nested-blocks
        for stmt in irsb.statements:
            if isinstance(stmt, pyvex.IRStmt.IMark):
                if stmt.addr + stmt.delta != addr:
                    break
            elif isinstance(stmt, pyvex.IRStmt.WrTmp):
                data = stmt.data
                if isinstance(data, pyvex.IRExpr.Get):
                    if data.offset == sp_offset:
                        tmps[stmt.tmp] = initial_sp
                    elif data.offset == lr_offset:
                        tmps[stmt.tmp] = initial_lr
                elif isinstance(data, pyvex.IRExpr.Binop):
                    if data.op == 'Iop_Sub32':
                        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(stmt, (pyvex.IRStmt.Store, pyvex.IRStmt.StoreG)):
                data = stmt.data
                storing_lr = False
                if isinstance(data, pyvex.IRExpr.RdTmp):
                    if data.tmp in tmps:
                        val = tmps[data.tmp]
                        if val == initial_lr:
                            # we are storing LR to somewhere
                            storing_lr = True
                if storing_lr:
                    if isinstance(stmt.addr, pyvex.IRExpr.RdTmp):
                        if stmt.addr.tmp in tmps:
                            storing_addr = tmps[stmt.addr.tmp]

                            function.info['lr_saved_on_stack'] = True
                            function.info['lr_on_stack_offset'] = storing_addr - initial_sp
                            break

        if 'lr_saved_on_stack' not in function.info:
            function.info['lr_saved_on_stack'] = False