'Generate a CFGNode that starts at `addr`.
Since lifting machine code to IRSBs is slow, self._nodes is used as a cache of CFGNodes.
If the current architecture is ARM, this method will try to lift the block in the mode specified by the address
(determined by the parity of the address: even for ARM, odd for THUMB), and in case of decoding failures, try
the other mode. If the basic block is successfully decoded in the other mode (different from the initial one),
`addr` and `current_function_addr` are updated.
:param int addr: Address of the basic block.
:param int current_function_addr: Address of the current function.
:return: A 4-tuple of (new address, new function address, CFGNode instance, IRSB object)
:rtype: tuple'

def _generate_cfgnode(self, addr, current_function_addr):

    try:
        if (addr in self._nodes):
            cfg_node = self._nodes[addr]
            irsb = cfg_node.irsb
            if (cfg_node.function_address != current_function_addr):
                current_function_addr = cfg_node.function_address
        else:
            distance = None
            obj = self.project.loader.find_object_containing(addr)
            if obj:
                has_executable_section = (len([sec for sec in obj.sections if sec.is_executable]) > 0)
                section = self._addr_belongs_to_section(addr)
                if (has_executable_section and (section is None)):
                    return (None, None, None, None)
                if (section is not None):
                    if (not section.is_executable):
                        return (None, None, None, None)
                    distance = ((section.vaddr + section.memsize) - addr)
                    distance = min(distance, VEX_IRSB_MAX_SIZE)
            nodecode = False
            irsb = None
            try:
                irsb = self.project.factory.block(addr, size=distance).vex
            except SimTranslationError:
                nodecode = True
            if ((nodecode or (irsb.size == 0) or (irsb.jumpkind == 'Ijk_NoDecode')) and (self.project.arch.name in ('ARMHF', 'ARMEL'))):
                nodecode = False
                if ((addr % 2) == 0):
                    addr_0 = (addr + 1)
                else:
                    addr_0 = (addr - 1)
                if (addr_0 in self._nodes):
                    cfg_node = self._nodes[addr_0]
                    irsb = cfg_node.irsb
                    return (addr_0, cfg_node.function_address, cfg_node, irsb)
                try:
                    irsb = self.project.factory.block(addr_0, size=distance).vex
                except SimTranslationError:
                    nodecode = True
                if (not (nodecode or (irsb.size == 0) or (irsb.jumpkind == 'Ijk_NoDecode'))):
                    if (current_function_addr == addr):
                        current_function_addr = addr_0
                    addr = addr_0
            if (nodecode or (irsb.size == 0) or (irsb.jumpkind == 'Ijk_NoDecode')):
                if (irsb is None):
                    irsb_size = 1
                else:
                    irsb_size = (irsb.size if (irsb.size > 0) else 1)
                self._seg_list.occupy(addr, irsb_size, 'nodecode')
                return (None, None, None, None)
            if (irsb.size > 0):
                if ((self.project.arch.name in ('ARMHF', 'ARMEL')) and ((addr % 2) == 1)):
                    real_addr = (addr - 1)
                else:
                    real_addr = addr
                self._seg_list.occupy(real_addr, irsb.size, 'code')
            cfg_node = CFGNode(addr, irsb.size, self, function_address=current_function_addr, block_id=addr, irsb=irsb)
            self._nodes[addr] = cfg_node
            self._nodes_by_addr[addr].append(cfg_node)
        return (addr, current_function_addr, cfg_node, irsb)
    except (SimMemoryError, SimEngineError):
        return (None, None, None, None)
