(self, target, jumpkind, current_function_addr, irsb, addr, cfg_node, ins_addr, stmt_idx)
return jobs
Given a node and details of a successor, makes a list of CFGJobs
        and if it is a call or exit marks it appropriately so in the CFG

        :param int target:          Destination of the resultant job
        :param str jumpkind:        The jumpkind of the edge going to this node
        :param int current_function_addr: Address of the current function
        :param pyvex.IRSB irsb:     IRSB of the predecessor node
        :param int addr:            The predecessor address
        :param CFGNode cfg_node:    The CFGNode of the predecessor node
        :param int ins_addr:        Address of the source instruction.
        :param int stmt_idx:        ID of the source statement.
        :return:                    a list of CFGJobs
        :rtype:                     list
Given a node and details of a successor, makes a list of CFGJobs
        and if it is a call or exit marks it appropriately so in the CFG
Given a node and details of a successor makes a list of CFGJobs and if it is a call or exit marks it appropriately so in the CFG
def _create_jobs(self, target, jumpkind, current_function_addr, irsb, addr, cfg_node, ins_addr, stmt_idx):
        """
        Given a node and details of a successor, makes a list of CFGJobs
        and if it is a call or exit marks it appropriately so in the CFG

        :param int target:          Destination of the resultant job
        :param str jumpkind:        The jumpkind of the edge going to this node
        :param int current_function_addr: Address of the current function
        :param pyvex.IRSB irsb:     IRSB of the predecessor node
        :param int addr:            The predecessor address
        :param CFGNode cfg_node:    The CFGNode of the predecessor node
        :param int ins_addr:        Address of the source instruction.
        :param int stmt_idx:        ID of the source statement.
        :return:                    a list of CFGJobs
        :rtype:                     list
        """

        if type(target) is pyvex.IRExpr.Const:  # pylint: disable=unidiomatic-typecheck
            target_addr = target.con.value
        elif type(target) in (pyvex.IRConst.U8, pyvex.IRConst.U16, pyvex.IRConst.U32, pyvex.IRConst.U64):  # pylint: disable=unidiomatic-typecheck
            target_addr = target.value
        elif type(target) is int:  # pylint: disable=unidiomatic-typecheck
            target_addr = target
        else:
            target_addr = None

        if target_addr in self._known_thunks and jumpkind == 'Ijk_Boring':
            thunk_kind = self._known_thunks[target_addr][0]
            if thunk_kind == 'ret':
                jumpkind = 'Ijk_Ret'
                target_addr = None
            elif thunk_kind == 'jmp':
                pass # ummmmmm not sure about this one
            else:
                raise AngrCFGError("This shouldn't be possible")

        jobs = [ ]
        is_syscall = jumpkind.startswith("Ijk_Sys")

        # Special handling:
        # If a call instruction has a target that points to the immediate next instruction, we treat it as a boring jump
        if jumpkind == "Ijk_Call" and \
                not self.project.arch.call_pushes_ret and \
                cfg_node.instruction_addrs and \
                ins_addr == cfg_node.instruction_addrs[-1] and \
                target_addr == irsb.addr + irsb.size:
            jumpkind = "Ijk_Boring"

        if target_addr is None:
            # The target address is not a concrete value

            if jumpkind == "Ijk_Ret":
                # This block ends with a return instruction.
                if current_function_addr != -1:
                    self._function_exits[current_function_addr].add(addr)
                    self._function_add_return_site(addr, current_function_addr)
                    self.functions[current_function_addr].returning = True
                    self._pending_jobs.add_returning_function(current_function_addr)

                cfg_node.has_return = True

            elif self._resolve_indirect_jumps and \
                    (jumpkind in ('Ijk_Boring', 'Ijk_Call', 'Ijk_InvalICache') or jumpkind.startswith('Ijk_Sys')):
                # This is an indirect jump. Try to resolve it.
                # FIXME: in some cases, a statementless irsb will be missing its instr addresses
                # and this next part will fail. Use the real IRSB instead
                irsb = self._lift(cfg_node.addr, size=cfg_node.size).vex
                cfg_node.instruction_addrs = irsb.instruction_addresses
                resolved, resolved_targets, ij = self._indirect_jump_encountered(addr, cfg_node, irsb,
                                                                                 current_function_addr, stmt_idx)
                if resolved:
                    for resolved_target in resolved_targets:
                        if jumpkind == 'Ijk_Call':
                            jobs += self._create_job_call(cfg_node.addr, irsb, cfg_node, stmt_idx, ins_addr,
                                                          current_function_addr, resolved_target, jumpkind)
                        else:
                            to_outside, target_func_addr = self._is_branching_to_outside(addr, resolved_target,
                                                                                         current_function_addr)
                            edge = FunctionTransitionEdge(cfg_node, resolved_target, current_function_addr,
                                                          to_outside=to_outside, stmt_idx=stmt_idx, ins_addr=ins_addr,
                                                          dst_func_addr=target_func_addr,
                                                          )
                            ce = CFGJob(resolved_target, target_func_addr, jumpkind,
                                        last_addr=resolved_target, src_node=cfg_node, src_stmt_idx=stmt_idx,
                                        src_ins_addr=ins_addr, func_edges=[ edge ],
                                        )
                            jobs.append(ce)
                    return jobs

                if ij is None:
                    # this is not a valid indirect jump. maybe it failed sanity checks.
                    # for example, `jr $v0` might show up in a MIPS binary without a following instruction (because
                    # decoding failed). in this case, `jr $v0` shouldn't be a valid instruction, either.
                    return [ ]

                if jumpkind in ("Ijk_Boring", 'Ijk_InvalICache'):
                    resolved_as_plt = False

                    if irsb and self._heuristic_plt_resolving:
                        # Test it on the initial state. Does it jump to a valid location?
                        # It will be resolved only if this is a .plt entry
                        resolved_as_plt = self._resolve_plt(addr, irsb, ij)

                        if resolved_as_plt:
                            # this is definitely a PLT stub
                            jump_target = next(iter(ij.resolved_targets))
                            target_func_addr = jump_target  # TODO: FIX THIS

                            edge = FunctionTransitionEdge(cfg_node, jump_target, current_function_addr,
                                                          to_outside=True, dst_func_addr=jump_target,
                                                          stmt_idx=stmt_idx, ins_addr=ins_addr,
                                                          )
                            ce = CFGJob(jump_target, target_func_addr, jumpkind, last_addr=jump_target,
                                        src_node=cfg_node, src_stmt_idx=stmt_idx, src_ins_addr=ins_addr,
                                        func_edges=[edge],
                                        )
                            jobs.append(ce)

                    if resolved_as_plt:
                        # has been resolved as a PLT entry. Remove it from indirect_jumps_to_resolve
                        if ij.addr in self._indirect_jumps_to_resolve:
                            self._indirect_jumps_to_resolve.remove(ij.addr)
                            self._deregister_analysis_job(current_function_addr, ij)
                    else:
                        is_plt = addr in self.functions and self.functions.get_by_addr(addr).is_plt
                        if is_plt:
                            # this is definitely a PLT entry, but we could not resolve it. this is probably due to
                            # missing SimProcedures. we do not want to resolve this indirect jump again in the future.
                            self._indirect_jump_unresolved(ij)
                        else:
                            # add it to indirect_jumps_to_resolve
                            self._indirect_jumps_to_resolve.add(ij)

                            # register it as a job for the current function
                            self._register_analysis_job(current_function_addr, ij)

                else:  # jumpkind == "Ijk_Call" or jumpkind.startswith('Ijk_Sys')
                    self._indirect_jumps_to_resolve.add(ij)
                    self._register_analysis_job(current_function_addr, ij)

                    jobs += self._create_job_call(addr, irsb, cfg_node, stmt_idx, ins_addr, current_function_addr, None,
                                                  jumpkind, is_syscall=is_syscall
                                                  )

        elif target_addr is not None:
            # This is a direct jump with a concrete target.

            # pylint: disable=too-many-nested-blocks
            if jumpkind in {'Ijk_Boring', 'Ijk_InvalICache', 'Ijk_Exception'}:
                to_outside, target_func_addr = self._is_branching_to_outside(addr, target_addr, current_function_addr)
                edge = FunctionTransitionEdge(cfg_node, target_addr, current_function_addr,
                                              to_outside=to_outside,
                                              dst_func_addr=target_func_addr,
                                              ins_addr=ins_addr,
                                              stmt_idx=stmt_idx,
                                              is_exception=jumpkind == 'Ijk_Exception',
                                              )

                ce = CFGJob(target_addr, target_func_addr, jumpkind, last_addr=addr, src_node=cfg_node,
                            src_ins_addr=ins_addr, src_stmt_idx=stmt_idx, func_edges=[ edge ],
                            )
                jobs.append(ce)

            elif jumpkind == 'Ijk_Call' or jumpkind.startswith("Ijk_Sys"):
                jobs += self._create_job_call(addr, irsb, cfg_node, stmt_idx, ins_addr, current_function_addr,
                                              target_addr, jumpkind, is_syscall=is_syscall
                                              )

            else:
                # TODO: Support more jumpkinds
                l.debug("Unsupported jumpkind %s", jumpkind)
                l.debug("Instruction address: %#x", ins_addr)

        return jobs
def _create_jobs ( self , target , jumpkind , current_function_addr , irsb , addr , cfg_node , ins_addr , stmt_idx ) : if type ( target ) is pyvex . IRExpr . Const : # pylint: disable=unidiomatic-typecheck target_addr = target . con . value elif type ( target ) in ( pyvex . IRConst . U8 , pyvex . IRConst . U16 , pyvex . IRConst . U32 , pyvex . IRConst . U64 ) : # pylint: disable=unidiomatic-typecheck target_addr = target . value elif type ( target ) is int : # pylint: disable=unidiomatic-typecheck target_addr = target else : target_addr = None if target_addr in self . _known_thunks and jumpkind == 'Ijk_Boring' : thunk_kind = self . _known_thunks [ target_addr ] [ 0 ] if thunk_kind == 'ret' : jumpkind = 'Ijk_Ret' target_addr = None elif thunk_kind == 'jmp' : pass # ummmmmm not sure about this one else : raise AngrCFGError ( "This shouldn't be possible" ) jobs = [ ] is_syscall = jumpkind . startswith ( "Ijk_Sys" ) # Special handling: # If a call instruction has a target that points to the immediate next instruction, we treat it as a boring jump if jumpkind == "Ijk_Call" and not self . project . arch . call_pushes_ret and cfg_node . instruction_addrs and ins_addr == cfg_node . instruction_addrs [ - 1 ] and target_addr == irsb . addr + irsb . size : jumpkind = "Ijk_Boring" if target_addr is None : # The target address is not a concrete value if jumpkind == "Ijk_Ret" : # This block ends with a return instruction. if current_function_addr != - 1 : self . _function_exits [ current_function_addr ] . add ( addr ) self . _function_add_return_site ( addr , current_function_addr ) self . functions [ current_function_addr ] . returning = True self . _pending_jobs . add_returning_function ( current_function_addr ) cfg_node . has_return = True elif self . _resolve_indirect_jumps and ( jumpkind in ( 'Ijk_Boring' , 'Ijk_Call' , 'Ijk_InvalICache' ) or jumpkind . startswith ( 'Ijk_Sys' ) ) : # This is an indirect jump. Try to resolve it. # FIXME: in some cases, a statementless irsb will be missing its instr addresses # and this next part will fail. Use the real IRSB instead irsb = self . _lift ( cfg_node . addr , size = cfg_node . size ) . vex cfg_node . instruction_addrs = irsb . instruction_addresses resolved , resolved_targets , ij = self . _indirect_jump_encountered ( addr , cfg_node , irsb , current_function_addr , stmt_idx ) if resolved : for resolved_target in resolved_targets : if jumpkind == 'Ijk_Call' : jobs += self . _create_job_call ( cfg_node . addr , irsb , cfg_node , stmt_idx , ins_addr , current_function_addr , resolved_target , jumpkind ) else : to_outside , target_func_addr = self . _is_branching_to_outside ( addr , resolved_target , current_function_addr ) edge = FunctionTransitionEdge ( cfg_node , resolved_target , current_function_addr , to_outside = to_outside , stmt_idx = stmt_idx , ins_addr = ins_addr , dst_func_addr = target_func_addr , ) ce = CFGJob ( resolved_target , target_func_addr , jumpkind , last_addr = resolved_target , src_node = cfg_node , src_stmt_idx = stmt_idx , src_ins_addr = ins_addr , func_edges = [ edge ] , ) jobs . append ( ce ) return jobs if ij is None : # this is not a valid indirect jump. maybe it failed sanity checks. # for example, `jr $v0` might show up in a MIPS binary without a following instruction (because # decoding failed). in this case, `jr $v0` shouldn't be a valid instruction, either. return [ ] if jumpkind in ( "Ijk_Boring" , 'Ijk_InvalICache' ) : resolved_as_plt = False if irsb and self . _heuristic_plt_resolving : # Test it on the initial state. Does it jump to a valid location? # It will be resolved only if this is a .plt entry resolved_as_plt = self . _resolve_plt ( addr , irsb , ij ) if resolved_as_plt : # this is definitely a PLT stub jump_target = next ( iter ( ij . resolved_targets ) ) target_func_addr = jump_target # TODO: FIX THIS edge = FunctionTransitionEdge ( cfg_node , jump_target , current_function_addr , to_outside = True , dst_func_addr = jump_target , stmt_idx = stmt_idx , ins_addr = ins_addr , ) ce = CFGJob ( jump_target , target_func_addr , jumpkind , last_addr = jump_target , src_node = cfg_node , src_stmt_idx = stmt_idx , src_ins_addr = ins_addr , func_edges = [ edge ] , ) jobs . append ( ce ) if resolved_as_plt : # has been resolved as a PLT entry. Remove it from indirect_jumps_to_resolve if ij . addr in self . _indirect_jumps_to_resolve : self . _indirect_jumps_to_resolve . remove ( ij . addr ) self . _deregister_analysis_job ( current_function_addr , ij ) else : is_plt = addr in self . functions and self . functions . get_by_addr ( addr ) . is_plt if is_plt : # this is definitely a PLT entry, but we could not resolve it. this is probably due to # missing SimProcedures. we do not want to resolve this indirect jump again in the future. self . _indirect_jump_unresolved ( ij ) else : # add it to indirect_jumps_to_resolve self . _indirect_jumps_to_resolve . add ( ij ) # register it as a job for the current function self . _register_analysis_job ( current_function_addr , ij ) else : # jumpkind == "Ijk_Call" or jumpkind.startswith('Ijk_Sys') self . _indirect_jumps_to_resolve . add ( ij ) self . _register_analysis_job ( current_function_addr , ij ) jobs += self . _create_job_call ( addr , irsb , cfg_node , stmt_idx , ins_addr , current_function_addr , None , jumpkind , is_syscall = is_syscall ) elif target_addr is not None : # This is a direct jump with a concrete target. # pylint: disable=too-many-nested-blocks if jumpkind in { 'Ijk_Boring' , 'Ijk_InvalICache' , 'Ijk_Exception' } : to_outside , target_func_addr = self . _is_branching_to_outside ( addr , target_addr , current_function_addr ) edge = FunctionTransitionEdge ( cfg_node , target_addr , current_function_addr , to_outside = to_outside , dst_func_addr = target_func_addr , ins_addr = ins_addr , stmt_idx = stmt_idx , is_exception = jumpkind == 'Ijk_Exception' , ) ce = CFGJob ( target_addr , target_func_addr , jumpkind , last_addr = addr , src_node = cfg_node , src_ins_addr = ins_addr , src_stmt_idx = stmt_idx , func_edges = [ edge ] , ) jobs . append ( ce ) elif jumpkind == 'Ijk_Call' or jumpkind . startswith ( "Ijk_Sys" ) : jobs += self . _create_job_call ( addr , irsb , cfg_node , stmt_idx , ins_addr , current_function_addr , target_addr , jumpkind , is_syscall = is_syscall ) else : # TODO: Support more jumpkinds l . debug ( "Unsupported jumpkind %s" , jumpkind ) l . debug ( "Instruction address: %#x" , ins_addr ) return jobs