# Buggy code
def _create_job_call(
    self,
    addr,
    irsb,
    cfg_node,
    stmt_idx,
    ins_addr,
    current_function_addr,
    target_addr,
    jumpkind,
    is_syscall=False,
):
    """
    Generate a CFGJob for target address, also adding to _pending_entries
    if returning to succeeding position (if irsb arg is populated)

    :param int addr:            Address of the predecessor node
    :param pyvex.IRSB irsb:     IRSB of the predecessor node
    :param CFGNode cfg_node:    The CFGNode instance of the predecessor node
    :param int stmt_idx:        ID of the source statement
    :param int ins_addr:        Address of the source instruction
    :param int current_function_addr: Address of the current function
    :param int target_addr:     Destination of the call
    :param str jumpkind:        The jumpkind of the edge going to this node
    :param bool is_syscall:     Is the jump kind (and thus this) a system call
    :return:                    A list of CFGJobs
    :rtype:                     list
    """

    jobs = []

    if is_syscall:
        # Fix the target_addr for syscalls
        tmp_state = self.project.factory.blank_state(
            mode="fastpath", addr=cfg_node.addr
        )
        # Find the first successor with a syscall jumpkind
        succ = next(
            iter(
                succ
                for succ in self.project.factory.successors(tmp_state).flat_successors
                if succ.history.jumpkind and succ.history.jumpkind.startswith("Ijk_Sys")
            ),
            None,
        )
        if succ is None:
            # For some reason, there is no such successor with a syscall jumpkind
            target_addr = self._unresolvable_call_target_addr
        else:
            try:
                syscall_stub = self.project.simos.syscall(succ)
                if (
                    syscall_stub
                ):  # can be None if simos is not a subclass of SimUserspac
                    syscall_addr = syscall_stub.addr
                    target_addr = syscall_addr
                else:
                    target_addr = self._unresolvable_call_target_addr
            except AngrUnsupportedSyscallError:
                target_addr = self._unresolvable_call_target_addr

    if isinstance(target_addr, SootAddressDescriptor):
        new_function_addr = target_addr.method
    else:
        new_function_addr = target_addr

    if irsb is None:
        return_site = None
    else:
        if self.project.arch.name != "Soot":
            return_site = (
                addr + irsb.size
            )  # We assume the program will always return to the succeeding position
        else:
            # For Soot, we return to the next statement, which is not necessarily the next block (as Shimple does
            # not break blocks at calls)
            assert isinstance(ins_addr, SootAddressDescriptor)
            soot_block = irsb
            return_block_idx = ins_addr.block_idx
            if stmt_idx + 1 >= soot_block.label + len(soot_block.statements):
                # tick the block ID
                return_block_idx += 1
            return_site = SootAddressDescriptor(
                ins_addr.method, return_block_idx, stmt_idx + 1
            )

    edge = None
    if new_function_addr is not None:
        edge = FunctionCallEdge(
            cfg_node,
            new_function_addr,
            return_site,
            current_function_addr,
            syscall=is_syscall,
            ins_addr=ins_addr,
            stmt_idx=ins_addr,
        )

    if new_function_addr is not None:
        # Keep tracing from the call
        ce = CFGJob(
            target_addr,
            new_function_addr,
            jumpkind,
            last_addr=addr,
            src_node=cfg_node,
            src_stmt_idx=stmt_idx,
            src_ins_addr=ins_addr,
            syscall=is_syscall,
            func_edges=[edge],
        )
        jobs.append(ce)

    callee_might_return = True
    callee_function = None

    if new_function_addr is not None:
        if is_syscall or self.project.is_hooked(new_function_addr):
            # we can create the function if it is a syscall or a SimProcedure and it does not exist yet. Note that
            # syscalls are handled as SimProcedures anyway.
            callee_function = self.kb.functions.function(
                addr=new_function_addr, syscall=is_syscall, create=True
            )
        else:
            callee_function = self.kb.functions.function(
                addr=new_function_addr, syscall=is_syscall
            )
        if callee_function is not None:
            callee_might_return = not (callee_function.returning is False)

    if callee_might_return:
        func_edges = []
        if return_site is not None:
            if callee_function is not None and callee_function.returning is True:
                fakeret_edge = FunctionFakeRetEdge(
                    cfg_node, return_site, current_function_addr, confirmed=True
                )
                func_edges.append(fakeret_edge)
                ret_edge = FunctionReturnEdge(
                    new_function_addr, return_site, current_function_addr
                )
                func_edges.append(ret_edge)

                # Also, keep tracing from the return site
                ce = CFGJob(
                    return_site,
                    current_function_addr,
                    "Ijk_FakeRet",
                    last_addr=addr,
                    src_node=cfg_node,
                    src_stmt_idx=stmt_idx,
                    src_ins_addr=ins_addr,
                    returning_source=new_function_addr,
                    syscall=is_syscall,
                    func_edges=func_edges,
                )
                self._pending_jobs.add_job(ce)
                # register this job to this function
                self._register_analysis_job(current_function_addr, ce)
            elif callee_function is not None and callee_function.returning is False:
                pass  # Don't go past a call that does not return!
            else:
                # HACK: We don't know where we are jumping.  Let's assume we fakeret to the
                # next instruction after the block
                # TODO: FIXME: There are arch-specific hints to give the correct ret site
                # Such as looking for constant values of LR in this block for ARM stuff.
                fakeret_edge = FunctionFakeRetEdge(
                    cfg_node, return_site, current_function_addr, confirmed=None
                )
                func_edges.append(fakeret_edge)
                fr = FunctionReturn(
                    new_function_addr, current_function_addr, addr, return_site
                )
                if fr not in self._function_returns[new_function_addr]:
                    self._function_returns[new_function_addr].add(fr)
                ce = CFGJob(
                    return_site,
                    current_function_addr,
                    "Ijk_FakeRet",
                    last_addr=addr,
                    src_node=cfg_node,
                    src_stmt_idx=stmt_idx,
                    src_ins_addr=ins_addr,
                    returning_source=new_function_addr,
                    syscall=is_syscall,
                    func_edges=func_edges,
                )
                self._pending_jobs.add_job(ce)
                # register this job to this function
                self._register_analysis_job(current_function_addr, ce)

    return jobs


# Traceback (ClaripyZeroDivisionError)
ClaripyZeroDivisionError                  Traceback (most recent call last)
~/Workspace/angr/angr/angr/engines/vex/irop.py in calculate(self, *args)
371         try:
--> 372             return self.extend_size(self._calculate(args))
373         except (ZeroDivisionError, claripy.ClaripyZeroDivisionError) as e:

~/Workspace/angr/angr/angr/engines/vex/irop.py in _op_divmod(self, args)
717         if self.is_signed:
--> 718             quotient = (args[0].SDiv(claripy.SignExt(self._from_size - self._to_size, args[1])))
719             remainder = (args[0].SMod(claripy.SignExt(self._from_size - self._to_size, args[1])))

~/Workspace/angr/claripy/claripy/operations.py in _op(*args)
66
---> 67         return return_type(name, fixed_args, **kwargs)
68

~/Workspace/angr/claripy/claripy/ast/base.py in __new__(cls, op, args, add_variables, hash, **kwargs)
152                 try:
--> 153                     r = operations._handle_annotations(eb._abstract(eb.call(op, args)), args)
154                     if r is not None:

~/Workspace/angr/claripy/claripy/backends/__init__.py in call(self, op, args)
238         converted = self.convert_list(args)
--> 239         return self._call(op, converted)
240

~/Workspace/angr/claripy/claripy/backends/__init__.py in _call(self, op, args)
249             # the raw ops don't get the model, cause, for example, Z3 stuff can't take it
--> 250             obj = self._op_raw[op](*args)
251         elif not op.startswith("__"):

~/Workspace/angr/claripy/claripy/bv.py in normalize_helper(self, o)
41             return NotImplemented
---> 42         return f(self, o)
43

~/Workspace/angr/claripy/claripy/bv.py in compare_guard(self, o)
15             raise ClaripyTypeError("bitvectors are differently-sized (%d and %d)" % (self.bits, o.bits))
---> 16         return f(self, o)
17

~/Workspace/angr/claripy/claripy/bv.py in SDiv(self, o)
417     if b == 0:
--> 418         raise ClaripyZeroDivisionError()
419     val = a//b if a*b>0 else (a+(-a%b))//b

ClaripyZeroDivisionError:

The above exception was the direct cause of the following exception:

SimZeroDivisionException                  Traceback (most recent call last)
<ipython-input-6-96f129e3fa7c> in <module>
----> 1 cfg = project.analyses.CFGFast()

~/Workspace/angr/angr/angr/analyses/analysis.py in __call__(self, *args, **kwargs)
107
108         oself._show_progressbar = show_progressbar
--> 109         oself.__init__(*args, **kwargs)
110         return oself
111

~/Workspace/angr/angr/angr/analyses/cfg/cfg_fast.py in __init__(self, binary, objects, regions, pickle_intermediate_results, symbols, function_prologues, resolve_indirect_jumps, force_segment, force_complete_scan, indirect_jump_target_limit, data_references, cross_references, normalize, start_at_entry, function_starts, extra_memory_regions, data_type_guessing_handlers, arch_options, indirect_jump_resolvers, base_state, exclude_sparse_regions, skip_specific_regions, heuristic_plt_resolving, detect_tail_calls, low_priority, cfb, model, use_patches, start, end, collect_data_references, extra_cross_references, **extra_arch_options)
643
644         # Start working!
--> 645         self._analyze()
646
647     def __getstate__(self):

~/Workspace/angr/angr/angr/analyses/forward_analysis.py in _analyze(self)
581             # An example is the CFG recovery.
582
--> 583             self._analysis_core_baremetal()
584
585         else:

~/Workspace/angr/angr/angr/analyses/forward_analysis.py in _analysis_core_baremetal(self)
706             self._job_info_queue = self._job_info_queue[1:]
707
--> 708             self._process_job_and_get_successors(job_info)
709
710             # Short-cut for aborting the analysis

~/Workspace/angr/angr/angr/analyses/forward_analysis.py in _process_job_and_get_successors(self, job_info)
724         job = job_info.job
725
--> 726         successors = self._get_successors(job)
727
728         all_new_jobs = [ ]

~/Workspace/angr/angr/angr/analyses/cfg/cfg_fast.py in _get_successors(self, job)
1050         #    l.debug("Tracing new exit %#x", addr)
1051
-> 1052         jobs = self._scan_block(job)
1053
1054         # l.debug("... got %d jobs: %s", len(jobs), jobs)

~/Workspace/angr/angr/angr/analyses/cfg/cfg_fast.py in _scan_block(self, cfg_job)
1351
1352         else:
-> 1353             entries = self._scan_irsb(cfg_job, current_func_addr)
1354
1355         return entries

~/Workspace/angr/angr/angr/analyses/cfg/cfg_fast.py in _scan_irsb(self, cfg_job, current_func_addr)
1544
1545             entries += self._create_jobs(target, jumpkind, function_addr, irsb, addr, cfg_node, ins_addr,
-> 1546                                          stmt_idx
1547                                          )
1548

~/Workspace/angr/angr/angr/analyses/cfg/cfg_fast.py in _create_jobs(self, target, jumpkind, current_function_addr, irsb, addr, cfg_node, ins_addr, stmt_idx)
1712             elif jumpkind == 'Ijk_Call' or jumpkind.startswith("Ijk_Sys"):
1713                 jobs += self._create_job_call(addr, irsb, cfg_node, stmt_idx, ins_addr, current_function_addr,
-> 1714                                               target_addr, jumpkind, is_syscall=is_syscall
1715                                               )
1716

~/Workspace/angr/angr/angr/analyses/cfg/cfg_fast.py in _create_job_call(self, addr, irsb, cfg_node, stmt_idx, ins_addr, current_function_addr, target_addr, jumpkind, is_syscall)
1747             tmp_state = self.project.factory.blank_state(mode="fastpath", addr=cfg_node.addr)
1748             # Find the first successor with a syscall jumpkind
-> 1749             succ = next(iter(succ for succ in self.project.factory.successors(tmp_state).flat_successors
1750                              if succ.history.jumpkind and succ.history.jumpkind.startswith("Ijk_Sys")), None)
1751             if succ is None:

~/Workspace/angr/angr/angr/factory.py in successors(self, *args, **kwargs)
52         """
53
---> 54         return self.project.engines.successors(*args, **kwargs)
55
56     def blank_state(self, **kwargs):

~/Workspace/angr/angr/angr/engines/hub.py in successors(self, state, addr, jumpkind, default_engine, procedure_engine, engines, **kwargs)
126         for engine in engines:
127             if engine.check(state, **kwargs):
--> 128                 r = engine.process(state, **kwargs)
129                 if r.processed:
130                     return r

~/Workspace/angr/angr/angr/engines/vex/engine.py in process(self, state, irsb, skip_stmts, last_stmt, whitelist, inline, force_addr, insn_bytes, size, num_inst, traceflags, thumb, extra_stop_points, opt_level, **kwargs)
146                 thumb=thumb,
147                 extra_stop_points=extra_stop_points,
--> 148                 opt_level=opt_level)
149
150     def _check(self, state, *args, **kwargs):

~/Workspace/angr/angr/angr/engines/engine.py in process(***failed resolving arguments***)
58         successors = new_state._inspect_getattr('sim_successors', successors)
59         try:
---> 60             self._process(new_state, successors, *args, **kwargs)
61         except SimException:
62             if o.EXCEPTION_HANDLING not in old_state.options:

~/Workspace/angr/angr/angr/engines/vex/engine.py in _process(self, state, successors, irsb, skip_stmts, last_stmt, whitelist, insn_bytes, size, num_inst, traceflags, thumb, extra_stop_points, opt_level)
197
198             try:
--> 199                 self._handle_irsb(state, successors, irsb, skip_stmts, last_stmt, whitelist)
200             except SimReliftException as e:
201                 state = e.state

~/Workspace/angr/angr/angr/engines/vex/engine.py in _handle_irsb(self, state, successors, irsb, skip_stmts, last_stmt, whitelist)
276                 state.scratch.stmt_idx = stmt_idx
277                 state._inspect('statement', BP_BEFORE, statement=stmt_idx)
--> 278                 cont = self._handle_statement(state, successors, stmt)
279                 state._inspect('statement', BP_AFTER)
280                 if not cont:

~/Workspace/angr/angr/angr/engines/vex/engine.py in _handle_statement(self, state, successors, stmt)
391             return None
392         else:
--> 393             exit_data = stmt_handler(self, state, stmt)
394
395         # for the exits, put *not* taking the exit on the list of constraints so

~/Workspace/angr/angr/angr/engines/vex/statements/wrtmp.py in SimIRStmt_WrTmp(engine, state, stmt)
2     # get data and track data reads
3     with state.history.subscribe_actions() as data_deps:
----> 4         data = engine.handle_expression(state, stmt.data)
5     state.scratch.store_tmp(stmt.tmp, data, deps=data_deps)
6

~/Workspace/angr/angr/angr/engines/vex/engine.py in handle_expression(self, state, expr)
452
453         state._inspect('expr', BP_BEFORE, expr=expr)
--> 454         result = handler(self, state, expr)
455
456         if o.SIMPLIFY_EXPRS in state.options:

~/Workspace/angr/angr/angr/engines/vex/expressions/op.py in SimIRExpr_Op(engine, state, expr)
12
13     try:
---> 14         result = translate(state, expr.op, exprs)
15
16         if o.TRACK_OP_ACTIONS in state.options:

~/Workspace/angr/angr/angr/engines/vex/irop.py in translate(state, op, s_args)
1042         l.error(error)
1043         raise UnsupportedIROpError(error)
-> 1044     return translate_inner(state, simop, s_args)
1045
1046

~/Workspace/angr/angr/angr/engines/vex/irop.py in translate_inner(state, irop, s_args)
1049         if irop._float and not options.SUPPORT_FLOATING_POINT in state.options:
1050             raise UnsupportedIROpError("floating point support disabled")
-> 1051         return irop.calculate(*s_args)
1052     except SimZeroDivisionException:
1053         if state.mode == 'static' and len(s_args) == 2 and state.solver.is_true(s_args[1] == 0):

~/Workspace/angr/angr/angr/engines/vex/irop.py in calculate(self, *args)
372             return self.extend_size(self._calculate(args))
373         except (ZeroDivisionError, claripy.ClaripyZeroDivisionError) as e:
--> 374             raise SimZeroDivisionException("divide by zero!") from e
375         except (TypeError, ValueError, SimValueError, claripy.ClaripyError) as e:
376             raise SimOperationError("%s._calculate() raised exception" % self.name) from e

SimZeroDivisionException: divide by zero!

# Fixed code
def _create_job_call(
    self,
    addr,
    irsb,
    cfg_node,
    stmt_idx,
    ins_addr,
    current_function_addr,
    target_addr,
    jumpkind,
    is_syscall=False,
):
    """
    Generate a CFGJob for target address, also adding to _pending_entries
    if returning to succeeding position (if irsb arg is populated)

    :param int addr:            Address of the predecessor node
    :param pyvex.IRSB irsb:     IRSB of the predecessor node
    :param CFGNode cfg_node:    The CFGNode instance of the predecessor node
    :param int stmt_idx:        ID of the source statement
    :param int ins_addr:        Address of the source instruction
    :param int current_function_addr: Address of the current function
    :param int target_addr:     Destination of the call
    :param str jumpkind:        The jumpkind of the edge going to this node
    :param bool is_syscall:     Is the jump kind (and thus this) a system call
    :return:                    A list of CFGJobs
    :rtype:                     list
    """

    jobs = []

    if is_syscall:
        # Fix the target_addr for syscalls
        tmp_state = self.project.factory.blank_state(
            mode="fastpath", addr=cfg_node.addr
        )
        # Find the first successor with a syscall jumpkind
        successors = self._simulate_block_with_resilience(tmp_state)
        if successors is not None:
            succ = next(
                iter(
                    succ
                    for succ in successors.flat_successors
                    if succ.history.jumpkind
                    and succ.history.jumpkind.startswith("Ijk_Sys")
                ),
                None,
            )
        else:
            succ = None
        if succ is None:
            # For some reason, there is no such successor with a syscall jumpkind
            target_addr = self._unresolvable_call_target_addr
        else:
            try:
                syscall_stub = self.project.simos.syscall(succ)
                if (
                    syscall_stub
                ):  # can be None if simos is not a subclass of SimUserspace
                    syscall_addr = syscall_stub.addr
                    target_addr = syscall_addr
                else:
                    target_addr = self._unresolvable_call_target_addr
            except AngrUnsupportedSyscallError:
                target_addr = self._unresolvable_call_target_addr

    if isinstance(target_addr, SootAddressDescriptor):
        new_function_addr = target_addr.method
    else:
        new_function_addr = target_addr

    if irsb is None:
        return_site = None
    else:
        if self.project.arch.name != "Soot":
            return_site = (
                addr + irsb.size
            )  # We assume the program will always return to the succeeding position
        else:
            # For Soot, we return to the next statement, which is not necessarily the next block (as Shimple does
            # not break blocks at calls)
            assert isinstance(ins_addr, SootAddressDescriptor)
            soot_block = irsb
            return_block_idx = ins_addr.block_idx
            if stmt_idx + 1 >= soot_block.label + len(soot_block.statements):
                # tick the block ID
                return_block_idx += 1
            return_site = SootAddressDescriptor(
                ins_addr.method, return_block_idx, stmt_idx + 1
            )

    edge = None
    if new_function_addr is not None:
        edge = FunctionCallEdge(
            cfg_node,
            new_function_addr,
            return_site,
            current_function_addr,
            syscall=is_syscall,
            ins_addr=ins_addr,
            stmt_idx=ins_addr,
        )

    if new_function_addr is not None:
        # Keep tracing from the call
        ce = CFGJob(
            target_addr,
            new_function_addr,
            jumpkind,
            last_addr=addr,
            src_node=cfg_node,
            src_stmt_idx=stmt_idx,
            src_ins_addr=ins_addr,
            syscall=is_syscall,
            func_edges=[edge],
        )
        jobs.append(ce)

    callee_might_return = True
    callee_function = None

    if new_function_addr is not None:
        if is_syscall or self.project.is_hooked(new_function_addr):
            # we can create the function if it is a syscall or a SimProcedure and it does not exist yet. Note that
            # syscalls are handled as SimProcedures anyway.
            callee_function = self.kb.functions.function(
                addr=new_function_addr, syscall=is_syscall, create=True
            )
        else:
            callee_function = self.kb.functions.function(
                addr=new_function_addr, syscall=is_syscall
            )
        if callee_function is not None:
            callee_might_return = not (callee_function.returning is False)

    if callee_might_return:
        func_edges = []
        if return_site is not None:
            if callee_function is not None and callee_function.returning is True:
                fakeret_edge = FunctionFakeRetEdge(
                    cfg_node, return_site, current_function_addr, confirmed=True
                )
                func_edges.append(fakeret_edge)
                ret_edge = FunctionReturnEdge(
                    new_function_addr, return_site, current_function_addr
                )
                func_edges.append(ret_edge)

                # Also, keep tracing from the return site
                ce = CFGJob(
                    return_site,
                    current_function_addr,
                    "Ijk_FakeRet",
                    last_addr=addr,
                    src_node=cfg_node,
                    src_stmt_idx=stmt_idx,
                    src_ins_addr=ins_addr,
                    returning_source=new_function_addr,
                    syscall=is_syscall,
                    func_edges=func_edges,
                )
                self._pending_jobs.add_job(ce)
                # register this job to this function
                self._register_analysis_job(current_function_addr, ce)
            elif callee_function is not None and callee_function.returning is False:
                pass  # Don't go past a call that does not return!
            else:
                # HACK: We don't know where we are jumping.  Let's assume we fakeret to the
                # next instruction after the block
                # TODO: FIXME: There are arch-specific hints to give the correct ret site
                # Such as looking for constant values of LR in this block for ARM stuff.
                fakeret_edge = FunctionFakeRetEdge(
                    cfg_node, return_site, current_function_addr, confirmed=None
                )
                func_edges.append(fakeret_edge)
                fr = FunctionReturn(
                    new_function_addr, current_function_addr, addr, return_site
                )
                if fr not in self._function_returns[new_function_addr]:
                    self._function_returns[new_function_addr].add(fr)
                ce = CFGJob(
                    return_site,
                    current_function_addr,
                    "Ijk_FakeRet",
                    last_addr=addr,
                    src_node=cfg_node,
                    src_stmt_idx=stmt_idx,
                    src_ins_addr=ins_addr,
                    returning_source=new_function_addr,
                    syscall=is_syscall,
                    func_edges=func_edges,
                )
                self._pending_jobs.add_job(ce)
                # register this job to this function
                self._register_analysis_job(current_function_addr, ce)

    return jobs